1、什麼是冪等性
能夠參考數據庫樂觀鎖機制,好比執行一條更新庫存的 SQL 語句,在併發場景,爲了性能和數據可靠性,會在更新時加上查詢時的版本,而且更新這個版本信息。可能你要對一個事情進行操做,這個操做可能會執行成百上千次,可是操做結果都是相同的,這就是冪等性。
html
2、消費端的冪等性保障
在海量訂單生成的業務高峯期,生產端有可能就會重複發生了消息,這時候消費端就要實現冪等性,這就意味着咱們的消息永遠不會被消費屢次,即便咱們收到了同樣的消息。java
業界主流的冪等性有兩種操做:
1.惟一 ID + 指紋碼 機制,利用數據庫主鍵去重
2.利用redis的原子性去實現redis
3、惟一 ID + 指紋碼 機制
你們確定懂惟一 ID 的,就很少說了,爲何須要指紋碼呢?這是爲了應對用戶在一瞬間的頻繁操做,這個指紋碼多是咱們的一些規則或者時間戳加別的服務給到的惟一信息碼,它並不必定是咱們系統生成的,基本都是由咱們的業務規則拼接而來,可是必定要保證惟一性,而後就利用查詢語句進行判斷這個id是否存在數據庫中。算法
好處:實現簡單,就一個拼接,而後查詢判斷是否重複。
壞處:在高併發時,若是是單個數據庫就會有寫入性能瓶頸
解決方案 :根據 ID 進行分庫分表,對 id 進行算法路由,落到一個具體的數據庫,而後當這個 id 第二次來又會落到這個數據庫,這時候就像我單庫時的查重同樣了。利用算法路由把單庫的冪等變成多庫的冪等,分攤數據流量壓力,提升性能。數據庫
4、redis的原子性去實現
咱們都知道redis是單線程的,而且性能也很是好,提供了不少原子性的命令。好比可使用 setnx 命令。緩存
在接收到消息後將消息ID做爲key執行 setnx 命令,若是執行成功就表示沒有處理過這條消息,能夠進行消費了,執行失敗表示消息已經被消費了。併發
使用 redis 的原子性去實現主要須要考慮兩個點異步
第一:咱們是否要進行數據落庫,若是落庫的話,關鍵解決的問題是數據庫和緩存如何作到原子性?
採用延時雙刪策略函數
僞代碼以下:高併發
public void write(String key,Object data){ redis.delKey(key); db.updateData(data); Thread.sleep(1000); redis.delKey(key); }
轉化爲中文描述就是
(1)先淘汰緩存
(2)再寫數據庫(這兩步和原來同樣)
(3)休眠1(根據業務本身設定)秒,再次淘汰緩存
這麼作,能夠將1秒內所形成的緩存髒數據,再次刪除。
url:http://www.javashuo.com/article/p-ftdcqtnl-cx.html
第二:若是不進行落庫,那麼都存儲到緩存中,如何設置定時同步的策略(同步到關係型數據庫)?緩存又如何作到數據可靠性保障呢 關於不落庫,定時同步的策略, 目前主流方案有兩種: 第一種爲雙緩存模式,異步寫入到緩存中,也能夠異步寫到數據庫,可是最終會有一個回調函數檢查,這樣能保障最終一致性,不能保證100%的實時性。 第二種是定時同步,好比databus同步。