03 冪等性設(shè)計(jì)

一话浇、概述

  • 一次和多次請(qǐng)求某一個(gè)資源應(yīng)該具有相同的副作用。

1. 服務(wù)間調(diào)用狀態(tài)

  • 把系統(tǒng)解耦后闹究,服務(wù)間的調(diào)用三個(gè)狀態(tài)

    1. 成功 success
    2. 失敗 failed
    3. 超時(shí) timeout幔崖, 超時(shí)完全不知道是什么狀態(tài)
      • 假如超時(shí) 是網(wǎng)絡(luò)傳輸丟包的問題
        • 可能是請(qǐng)求時(shí)就沒有請(qǐng)求到
        • 可能是請(qǐng)求到了,返回結(jié)果時(shí)沒有正常返回等等情況。
  • 因?yàn)橄到y(tǒng)超時(shí)赏寇,而調(diào)用方重試一下吉嫩,會(huì)給我們的系統(tǒng)帶來不一致的副作用。

    • 兩種處理方式
      1. 一種是需要下游系統(tǒng)提供相應(yīng)的查詢接口嗅定。
        • 上游系統(tǒng)在timeout 后去查詢一下自娩。
          • 查到了,表明做了渠退,成功了就不用做了忙迁, 失敗了就走失敗流程
      2. 一種是通過冪等性的方式。
        • 這個(gè)查詢操作交給下游系統(tǒng)碎乃,上游系統(tǒng)只管重試姊扔,下游系統(tǒng)保證一次和多次的請(qǐng)求結(jié)果是一樣的。

二梅誓、冪等性的方式

1. 全局ID

  • 要做到冪等性的交易接口恰梢,需要一個(gè)唯一的標(biāo)識(shí),來標(biāo)志交易是同一筆交易梗掰。
  • 全局id 參考 全局id 的文章嵌言。

2. 處理流程

1. 流程

  1. 是需要一個(gè)存儲(chǔ)來記錄收到的交易。
  2. 當(dāng)收到交易請(qǐng)求的時(shí)候及穗,我們回到這個(gè)存儲(chǔ)中去查詢
    • 如果查到了就不再做操作呀页。并把上次做的結(jié)果返回。
    • 如果沒有查到拥坛,那么我們就記錄下來蓬蝶。
  • image.png

2 問題

  • 上面流程有個(gè)問題,28定律猜惋,80%的請(qǐng)求都是正常的丸氛,讓100%的請(qǐng)求都到這個(gè)存儲(chǔ)里去查一下,這會(huì)導(dǎo)致處理流程變的很慢著摔。

2.1 解決

  • 最好是當(dāng)這個(gè)存儲(chǔ)出現(xiàn)沖突的時(shí)候會(huì)報(bào)錯(cuò)缓窜,
    • 我們收到交易請(qǐng)求后,直接去存儲(chǔ)里記錄這個(gè) ID(相對(duì)于數(shù)據(jù)的 Insert 操作)谍咆,如果出現(xiàn) ID 沖突了的異常禾锤,那么我們就知道這個(gè)之前已經(jīng)有人發(fā)過來了,所以就不用再做了摹察。
  • 假如是mysql數(shù)據(jù)庫(kù)中你可以使用 insert into … values … on DUPLICATE KEY UPDATE … 這樣的操作
CREATE TABLE unique_table
(
    id    bigint DEFAULT 0 NOT NULL
        CONSTRAINT `PRIMARY`
        PRIMARY KEY,
    type  varchar(50)      NULL,
    state int    DEFAULT 0 NOT NULL
);

insert into unique_table values (2,'訂單系統(tǒng)',1) on DUPLICATE KEY UPDATE state = state + 1 ;
# 第一次操作 1 row affected in 19 ms
# 第二次操作 2 rows affected in 15 ms
根據(jù) row的值不同恩掷,判斷值是否有

  • 假如是更新的場(chǎng)景
update table set status = “paid” where id = xxx and status = “unpaid”;
  • 網(wǎng)上還有 MVCC 通過使用版本號(hào)等其他方式,我覺得這些都不標(biāo)準(zhǔn)供嚎,我們希望我們有一個(gè)標(biāo)準(zhǔn)的方式來做這個(gè)事黄娘,所以峭状,最好還是用一個(gè) ID。

3. 存儲(chǔ)

  • 因?yàn)閮绲刃苑欠植际降谋普孕枰鎯?chǔ)也是共享的优床。
  • 這樣每個(gè)服務(wù)就變成沒有狀態(tài)的了。但是誓焦,這個(gè)存儲(chǔ)就成了一個(gè)非常關(guān)鍵的依賴胆敞,其擴(kuò)展性和可用性也成了非常關(guān)鍵的指標(biāo)。
  • 你可以使用關(guān)系型數(shù)據(jù)庫(kù)杂伟,或是 key-value 的 NoSQL(如 MongoDB)來構(gòu)建這個(gè)存儲(chǔ)系統(tǒng)移层。

3. HTTP 的冪等性

1. http 常見方法的冪等性

image.png
  1. HTTP GET 方法用于獲取資源,不應(yīng)有副作用稿壁,所以是冪等的

  2. HTTP HEAD 和 GET 本質(zhì)是一樣的幽钢,區(qū)別在于 HEAD 不含有呈現(xiàn)數(shù)據(jù)歉备,而僅僅是 HTTP 頭信息傅是,不應(yīng)有副作用,也是冪等的

    • 欲判斷某個(gè)資源是否存在蕾羊,我們通常使用 GET喧笔,但這里用 HEAD 則意義更加明確。也就是說龟再,HEAD 方法可以用來做探活使用书闸。
  3. HTTP OPTIONS 主要用于獲取當(dāng)前 URL 所支持的方法,所以也是冪等的

    • 若請(qǐng)求成功利凑,則它會(huì)在 HTTP 頭中包含一個(gè)名為“Allow”的頭浆劲,值是所支持的方法,如“GET, POST”哀澈。
  4. HTTP DELETE 方法用于刪除資源牌借,有副作用,但它應(yīng)該滿足冪等性割按。

    • 比如:DELETE http://www.forum.com/article/4231膨报,調(diào)用一次和 N 次對(duì)系統(tǒng)產(chǎn)生的副作用是相同的,即刪掉 ID 為 4231 的帖子适荣。因此现柠,調(diào)用者可以多次調(diào)用或刷新頁面而不必?fù)?dān)心引起錯(cuò)誤。
  5. HTTP POST 方法用于創(chuàng)建資源弛矛,所對(duì)應(yīng)的 URI 并非創(chuàng)建的資源本身够吩,而是去執(zhí)行創(chuàng)建動(dòng)作的操作者,有副作用丈氓,不滿足冪等性废恋。

    • 比如:POST http://www.forum.com/articles的語義是在http://www.forum.com/articles下創(chuàng)建一篇帖子谈秫,HTTP 響應(yīng)中應(yīng)包含帖子的創(chuàng)建狀態(tài)以及帖子的 URI。兩次相同的 POST 請(qǐng)求會(huì)在服務(wù)器端創(chuàng)建兩份資源鱼鼓,它們具有不同的 URI拟烫;所以,POST 方法不具備冪等性迄本。
  6. HTTP PUT 方法用于創(chuàng)建或更新操作硕淑,所對(duì)應(yīng)的 URI 是要?jiǎng)?chuàng)建或更新的資源本身,滿足冪等性

    • 用于更新資源嘉赎,沒有的話則執(zhí)行創(chuàng)建操作置媳。每次執(zhí)行請(qǐng)求時(shí)都會(huì)先判斷一下序號(hào)為1的花信息是否存在,不存在則創(chuàng)建公条,否則視為更新拇囊。
  7. HTTP PATCH 是對(duì)PUT方法的補(bǔ)充,用來對(duì)已知資源進(jìn)行局部更新 , 不滿足冪等性

  8. TRACE 方法 實(shí)現(xiàn)沿通向目標(biāo)資源的路徑的消息環(huán)回(loop-back)測(cè)試靶橱,提供了一種實(shí)用的 debug 機(jī)制寥袭。

    • 請(qǐng)求的最終接收者應(yīng)當(dāng)原樣反射(reflect)它接收到的消息,除了以下字段部分关霸,作為一個(gè)Content-Type 為 message/http 的 200(OK)響應(yīng)的消息的主體(body)返回給客戶端传黄。

2. POST 方式不支持冪等性,的冪等性設(shè)計(jì)队寇。

  1. 在表單中需要隱藏一個(gè) token(可以前后端生成)

  2. 后端把用戶提交的數(shù)據(jù)和這個(gè) token 保存在數(shù)據(jù)庫(kù)中

    • 如果有重復(fù)提交膘掰,那么數(shù)據(jù)庫(kù)中的 token 會(huì)做排它限制,從而做到冪等性佳遣。
  3. 更為穩(wěn)妥的做法是识埋,后端成功后向前端返回 302 跳轉(zhuǎn),把用戶的前端頁跳轉(zhuǎn)到 GET 請(qǐng)求零渐,把剛剛 POST 的數(shù)據(jù)給展示出來窒舟。如果是 Web 上的最好還把之前的表單設(shè)置成過期,這樣用戶不能通過瀏覽器后退按鈕來重新提交相恃。這個(gè)模式又叫做 PRG 模式(Post/Redirect/Get)辜纲。

3 . POST 方式不支持冪等性,常用方式

  • 前端實(shí)現(xiàn)
    • 點(diǎn)擊提交拦耐, 按鈕disable
  • 后端
    • 數(shù)據(jù)庫(kù)唯一索引
      • 適合場(chǎng)景
        • 插入操作
    • 基于redis 實(shí)現(xiàn)一套冪等性防重框架
      • 適合場(chǎng)景
        • 更新操作耕腾,配合業(yè)務(wù)操作
      • 步驟
        • 用個(gè)攔截器,攔截所有參數(shù)杀糯, 參數(shù)拼接作為key去redis 判斷下扫俺。
          • 適合 系統(tǒng)參數(shù)比較規(guī)定。
        • 先uuid 獲取固翰,然后操作成功刪除狼纬。
    • 數(shù)據(jù)庫(kù)狀態(tài)機(jī)
      • 適合場(chǎng)景
        • 更新操作
    • 通過鎖實(shí)現(xiàn)
      • 使用數(shù)據(jù)庫(kù)實(shí)現(xiàn)冪等性
        • 通過悲觀鎖來實(shí)現(xiàn)冪等性
        • 通過唯一索引來實(shí)現(xiàn)冪等性
        • 通過樂觀鎖來實(shí)現(xiàn)冪等性
      • 使用 JVM 鎖實(shí)現(xiàn)冪等性
      • 使用分布式鎖實(shí)現(xiàn)冪等性
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羹呵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子疗琉,更是在濱河造成了極大的恐慌冈欢,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盈简,死亡現(xiàn)場(chǎng)離奇詭異凑耻,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柠贤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門香浩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人臼勉,你說我怎么就攤上這事邻吭。” “怎么了宴霸?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵囱晴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我猖败,道長(zhǎng)速缆,這世上最難降的妖魔是什么降允? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任恩闻,我火速辦了婚禮,結(jié)果婚禮上剧董,老公的妹妹穿的比我還像新娘幢尚。我一直安慰自己,他們只是感情好翅楼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布尉剩。 她就那樣靜靜地躺著,像睡著了一般毅臊。 火紅的嫁衣襯著肌膚如雪理茎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天管嬉,我揣著相機(jī)與錄音皂林,去河邊找鬼。 笑死蚯撩,一個(gè)胖子當(dāng)著我的面吹牛础倍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播胎挎,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼沟启,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼忆家!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起德迹,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤芽卿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后胳搞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹬竖,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年流酬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了币厕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芽腾,死狀恐怖旦装,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情摊滔,我是刑警寧澤阴绢,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站艰躺,受9級(jí)特大地震影響呻袭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腺兴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一左电、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧页响,春花似錦篓足、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至没陡,卻和暖如春涩哟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盼玄。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工贴彼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人强岸。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓锻弓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蝌箍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子青灼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容