<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 如何保證萬無一失 ![](http://cdn.aipin100.cn/18-6-17/87926503.jpg) 假如我們是一家銀行,收到第三方發來的一筆轉賬請求(比如支付寶,微信支付里面的提現操作),收到這筆交易請求后,會進行下面三個動作(有簡化,但是能體現核心部分): 1. 創建一條交易記錄 2. 將轉賬操作扔到隊列 3. 消費者消費隊列,最終完成轉賬操作 >題外話:這就是為什么我們提現有延時的原因(2小時內到賬),因為最先放到隊列了,而不是直接處理,為什么不直接處理呢,因為交易量很大,計算能力有限,一時處理不過來。 這關鍵的三步,怎么保證安全性呢? 什么是安全性呢,在這里,正確性就是安全性。 再來看會出現哪些問題呢?下面我們提出一些問題: 1. 轉賬失敗了。 2. 重復轉賬了。 3. 轉賬成功了,但狀態還未顯示。 …… 不管有哪些情況,我們只知道,正確的結果只有一種,那就是轉賬成功,沒有多轉也沒有少轉,并且轉賬記錄顯示為成功。 **如果三步都能成功,和預期的一樣執行,那么就不會有任何問題了,但關鍵是沒有人能夠擔保一定不會出問題。** 所以我們就要用一些方法來解決這個不確定性問題了。 先來一步一步的看,假設執行到哪一步失敗的話會怎樣,以及如何解決。 1. 第一步失敗的話,交易記錄不能創建,也就沒有任何交易被創建。直接響應請求失敗。這不會造成什么問題,畢竟這是第一步,第一步失敗就不會有后面的事情了,失敗了又能有什么問題呢。 2. 第二步失敗的話,扔到隊列失敗了,可是第一步交易已經成功創建了,這可怎么辦。 好,先來解決這個問題。 **Q:扔隊列操作失敗了怎么辦?** **A:** 沒人能保證任何操作都一定能成功,隊列系統剛好不可用了,只能怪老天了,那此時怎么保證業務不出問題呢,總不能丟失這筆轉賬吧。這里有幾種方式:1. 重試,放隊列失敗,就不斷重試,如果有多條消息,后面消費時要檢查交易狀態(上鎖,不能出現并發問題),要保證冪等性,不能重復消費消息。2. 補償:在放隊列之前(交易創建之后),做一個補償標記,10小時候或者每隔10小時檢查該筆交易的狀態(檢查交易狀態,檢查確認,檢查隊列),如果有問題就重試,或者做好失敗記錄,記好日志。(這個時間是根據系統處理情況來定的,直到交易狀態為完成才刪除這個補償標記) **解決了這個問題,那么其實下面的n個問題就都解決了,比如隊列消息丟失啊,都是同樣的思路。不管你哪一步失敗,會出現什么問題,我們只知道有且只有一種正確結果,只要保持這種正確結果的最終正確性,系統就是可靠的,萬無一失的。** (如果系統確實出問題了,比如由于前期設計考慮不周全、疏忽而導致的問題,那我們也要最大限度的減少由此帶來的影響,最小化損失,并且設法挽回。) >[danger] 關鍵詞:**重試、補償、事后校正、確認、ACK確認、容錯、柔性事務、兩階段提交、最終一致性、鎖、防止并發問題、冪等性、防止重復消費、日志記錄**。 * * * * * ### 沒有絕對的健壯,但是有相對的 保持悲觀的同時也不要忘記樂觀。 由于每段代碼執行邏輯不同,所處環境也不同,所以出錯的幾率也不同,**一般主進程存在較小的崩潰概率,因為它邏輯直觀,不會摻雜任何的業務邏輯代碼,所以幾乎不會出錯中斷(甚至設計中可以認為此部分不會出錯,負載均衡部分也同理)**,但是worker進程就不同了,它是業務邏輯的具體執行部分,這里出錯是不可預料的,所以對于這部分代碼,可以理解為一定會出錯,主進程應做好維護工作。 這世界上并沒有萬無一失,就像兩座城堡的通信,信使總是可能不可靠的,你無法確定他一定不會叛變或者旅途中遇到突發情況,不論是什么情況發生,只要城堡是堅固的,我們就是安全的。任何時候我們都不能將安全的賭注壓在信使身上。如果你理解這個道理,你構建的系統就是堅固可靠的。 ***** ### 一致性保證 例:轉賬操作 1. **轉賬表** remittance: (id, from, to, amount, status, create_time, complete_time) : 增加一條轉賬記錄 2. **轉賬隊列消息記錄表** remittance_queue: (id, remittance_id status[待消費, 正在執行, 處理完成, 已關閉]) : 增加一條消息記錄 > 消費失敗,則轉入失敗記錄表進行相應的業務邏輯(如轉賬日志),而不是標記為處理失敗 (有人可能認為 `remittance_queue` 表是不必要的,的確只有 `remittance` 表也做得到行鎖并發控制,但是有這張表可以記錄某條轉賬的隊列處理記錄,并且將鎖開銷轉移到用戶不回訪問的表上了,所以我認為這張表有存在的必要。同時對于系統內多種這樣的操作,可以抽象出一張專門記錄隊列操作的表,如 隊列操作記錄表: [操作標識, 對應資源ID, 狀態] 這樣整個系統只需要這一張表保證就可以。) 3. **插入一條隊列消息** `Resque::enqueue()`: task, 載荷(包含 remittance_queue_id) 這樣應該被處理的業務邏輯就被 **“裝”** 到了隊列中,即Broker中。而隊列消息是不可靠的(存/取):丟失消息、消息重復(同樣的消息存在多條)、重復消費……,即便如此,我們也要在這樣的情況下保證整個轉賬的業務邏輯正確性。 具體要面對和解決的問題就是:冪等性 具體做法: 1. **防止并發問題:** task 消息消費時,必須使用 事務行鎖 檢查 `remittance_queue` 隊列消息的狀態是否為 `待消費`,只在 待消費 的狀態下執行任務處理。是否已經消費過了,(防止重復消費,或者隊列消息不穩定) 2. **補償機制:** 當一段時間過了還沒有到賬,說明隊列消息可能丟失了,或者其他原因,這時需要重發消息,相當于 **“再次執行轉賬操作”** (不過只是進行重發隊列消息),也就是 **啟動補償機制**。 此時的 **補償操作** 為: 1. 先 事務行鎖 檢查這條 轉賬記錄 對應的 隊列消息表,根據 `remittance_id` 查到 `remittance_queue` 中所在行,`status` 是否還為 `待消費`,是則將 `status` 標記 `關閉`,相當于拋棄對應的隊列消息了,不管你那條隊列消息此時到底是跑哪里了。 2. 然后,再次增加一條 隊列消息記錄 3. 再次插入一條隊列 > 上面說補償時的重發消息相當于 再次執行轉賬,但這個 “再次執行轉賬操作” 是加引號的,這個操作與轉賬操作不同的是,沒有其他的業務邏輯(如轉賬前的相關邏輯),只有安全的隊列操作。(操作對象是remittance_queue和隊列) #### 補償機制如何實現 如:發起一筆轉賬時,就建立一個補償,采用延時隊列實現,延時時間根據預估,比如轉賬發起后的12小時。這樣當轉賬開始后的12小時后,補償機制就會執行。補償發現轉賬不成功,會有相應的機制,如重發消息,日志記錄,報警等等。如成功了,那么補償時就什么都不做。 除了延時隊列實現補償,還可以手動觸發,比如后臺的“重試”按鈕,就相當于是手動的補償機制了。 并且每次操作/補償,都伴隨著補償(補償重發時也要再次加個延時補償),直至最終操作成功。 補償就像一個護花使者,它不直接與你同行,而是用另一種方式伴隨著你。 **另外沒有絕對的安全,系統應該定時執行財務對賬,這樣才能及時發現和規避風險。** ~~~ ### 最終一致性 補償 砍價服務 ? 砍價應用 砍價服務成功調用 砍價應用成功了,但自身的后續處理失敗了,那就沒辦法了,所以調用方需要自己確保自己也能落盤成功 分布式事務很難,只能做到最終一致性,如果失敗只能補償處理了 補償方案: 1. 被調用方 執行成功后 寫入一條 巡視確認記錄 后再返回結果 2. 調用方 執行成功后 處理 其巡視記錄(刪除或標記) 3. 監控經常 定期掃描 超時待確認的巡視記錄 就能發現 數據不一致的記錄 4. 程序或人工手工修復數據不一致的記錄,分析問題原因,這樣就能實現 最終一致性 ~~~ #### 如果補償也失敗了怎么辦? 還有人打破砂鍋問到底,說如果補償、確認等機制也失敗了怎么辦,好吧,抱著務實的態度,也來說一下: 一般來說,越簡單的系統越不容易出錯,出錯的系統一般是復雜性較大的系統,但凡事總有萬一,萬一最簡單的補償機制也失效了怎么辦?還有報警啊,還有日志啊,那如果報警和日志也都失效了怎么辦?好吧。你是不打算放過我了是吧。 其實你不用這么軸,這種情況即使出現我們也不怕,認真的告訴你,我們真的有考慮過這種情況的。別忘了我們還有最后一道防線,人工。人工審查/糾錯(成熟的系統都有財務、對賬、審查的,即使系統沒有這樣做,公司也會要求審查對賬的)。試想轉賬超過10天還沒有到賬的,就算沒有審查出來,用戶也會打電話來投訴的。 雖然你很煩,不過我還是喜歡這么軸這么認真的你,好樣的。 #### 沒有絕對的完美 還有人說,我代碼很完美了,怎么會有那么多的失敗呢,有可能嗎? 首先世界上沒有最完美的代碼,沒有永遠沒有BUG的系統,最完美的代碼就是不斷進化、升級、更新的代碼,最可靠的系統就是得到長期支持和維護的系統。 就算你的代碼不出問題,你能控制內因,你也無法控制外因啊。你能預料到地震,海嘯,臺風等自然災害嗎?硬盤爆炸呢,內存燒焦呢,CPU冒煙呢,停電呢,臨時工挖斷網線呢,這些你能控制嗎,**所以啊,任何時候,任何指令都可能執行失敗或者沒被執行**,如果你能在腦內模擬出硬件,那么你就能很簡單的看出程序是怎么運行的。就能在大腦里面想象程序運行的原理,你就知道這是怎么一回事了。 * * * * * ### 代碼的失敗率 <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.connect() // failure rate: 1/千 </p> <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.beginTransaction() // failure rate: 1/萬 </p> <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.ping() // failure rate: 1/十萬 </p> <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.query() // failure rate: 1/八萬 </p> <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.query() // failure rate: 1/七萬 </p> sleep(2) <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.query() // failure rate: 1/五萬 </p> <p style="background: linear-gradient(to right,#36ff670,#ffffff 5%);">db.commit() // failure rate: 1/三萬 </p> 1. 每次調用都是與 db 服務端進行交互 2. 假設 sql 都是正確的,每行代碼也都會有執行失敗的可能,只是失敗概率不同而已 3. 我們無法改變總是會有可能失敗的現實,只能盡量讓我們的業務代碼處在一個較低的失敗率之中,并做好容錯處理,考慮異常的情況 4. 即代碼并不是完全可靠的,但我們要有容錯,確保異常是可控的,這樣業務才是安全的,正確的 ---- ### 擴展 我們發現關系型數據庫還是很重要的,我們的數據都交給了它,可靠性也交給了它。 [傳統事務與柔性事務](https://www.jianshu.com/p/ab1a1c6b08a1) > 日志,冪等性,業務彈性,最終一致,重試,補償 [支付寶運營架構中柔性事務指的是什么? - 知乎](https://www.zhihu.com/question/31813039) > 業務層2PC(兩階段提交),事后校正 [創始人快去跟公司技術人員落實這件事](https://mp.weixin.qq.com/s/YQbxfI389FLVuwIpYhr9sw) > 有可能出 bug 的代碼最終都會出 bug。 > > 一定。 [RabbitMQ從入門到精通---ACK機制 | 菜鳥IT路](https://www.dev-heaven.com/posts/36563.html) [RabbitMQ ACK 機制的意義是什么? - 知乎](https://www.zhihu.com/question/41976893) [TCP報文到達確認(ACK)機制 - CSDN博客](https://blog.csdn.net/wjtxt/article/details/6606022) [php手冊經常見到,什么是“二進制安全”? - zhuocr的博客 - CSDN博客](https://blog.csdn.net/zhuocr/article/details/70591310)(充分了解你使用的系統) [事務已提交,數據卻丟了,趕緊檢查下這個配置!!! | 數據庫系列](https://mp.weixin.qq.com/s/-Hx2KKYMEQCcTC-ADEuwVA) * * * * * last update:2018-10-26 16:49:22
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看