面向魯棒的系統設計

worldnote發表於2016-02-19

前言

  • 本來打算叫做面向異常的程式設計的,後來覺得可能多的是系統健壯性方面,於是改名面向魯棒的系統設計,所謂魯棒,魯棒是Robust的音譯,也就是健壯和強壯的意思。它是在異常和危險情況下系統生存的關鍵。
  • 平時在做業務系統的時候,尤其是最近一年多接觸的超複雜系統,發現處理線上問題所佔的時間越來越多,總結發現,其實這些問題大都是之前欠下的債,至於為啥欠債,大多數情況下迫於專案或者日常的時間壓力,很多設計從簡,業務流程考慮主流程和分支流程,異常流程關注的少,不管三七二十一,功能先上線再說,如此便導致了惡性迴圈。
  • 由此,我們可以有的應對方案是啥呢,後面的專案,肯定也會是時間壓力大的,那隻能提升我們自身處理異常的能力了,也就是說在系統設計或者方案考慮的時候,就規避掉,提升應對經驗,這樣在同樣的時間裡面,就能夠遊刃有餘,編寫出更高質量的程式碼,進入良性迴圈階段。

解決方案探索

  • 大多數的新手程式設計師,由於編碼經驗的缺失,導致在程式碼的保護方面做的不好,隨著後續編碼經驗的積累以及採坑次數的增加,慢慢的會更多關注在健壯性方面;
  • 分享部分典型的案例,抽象一下,學習別人失敗的教訓,舉一反三,來規避問題;

抽象的解決方案描述

  • 遠端資源的呼叫,務必考慮失敗或者超時的邏輯
  • 業務邏輯的測試,多多模擬異常的邊界情況
  • 資料獲取類的介面,需要評估目前的資料量,後續的增長情況,以及極端情況下的量大小
  • 列表類的介面或者資料展示,需要考慮資料的極限情況,最大是多少,並做好保護
  • 批量的資料,務必需要考慮異常情況,部分失敗了怎麼辦;

典型案例

  • 本地快取,載入失敗,之後應用系統啟動

    • java local cache在高併發系統中,使用的較多,把熱點的資料或者後設資料儲存在JVM的heap區,從而實現低延遲,但是這裡就涉及到快取資料的載入了;
    • 常用的資料載入方案,一種是應用啟動的時候,全部載入所有的資料,之後有增量變更的時候,再增量更新;另外一種是啟動的時候不載入,在資料第一次訪問的時候載入這個資料;
    • 這兩種方式各有優劣,但是假如選擇了第一種,就需要在邏輯裡面考慮,假如快取資料載入失敗了,怎麼辦,是應用系統直接啟動失敗,還是程式碼邏輯裡面冗餘懶載入的機制,如果不考慮,又一個坑留下了;
  • 分散式快取和資料庫中的資料一致性考慮

    • 目前網際網路級的系統,快取基本上是架構上不可或缺的,引入快取,必然就會面臨資料一致性問題,舉個例子,加入同一份資料,在DB和快取中都有,這時候使用者在頁面操作,變更資料,需要變更快取和DB,需要同時生效,如果update 的sql執行成功,之後快取變更的時候超時了導致變更失敗,這時候,整體應該返回使用者失敗,然後DB的資料回滾掉。
    • 如果是沒有經驗的開發,可能就DB更新,然後快取更新,沒有針對快取更新失敗或者超時做邏輯處理,本地值系統功能邏輯缺失導致;
  • 業務操作和資料庫持久化以及訊息傳送的一致性考慮

    • 業務系統,在考慮非同步解耦的時候,會引入訊息系統,這時候面臨了一個問題,就是業務操作和訊息系統的一致性問題;
    • 業務操作和訊息的傳送,要能夠滿足事務的特性,例如藉助二階段提交來實現,然後訊息系統來進行重試,從而實現最終一致性的要求;
  • 批量更新資料庫的順序問題導致的死鎖

    • 假如這裡有個方法,是List資料的更新,在併發情況下,如果更新的SQL不做排序,會導致死鎖問題,這時候需要按照唯一主鍵,例如id來做排序,從而保證鎖佔用的時候的順序性;
    • 至於為啥會有死鎖問題,假如兩個呼叫,含有相同的資料,例如都含有A和B,因為批量update佔鎖的時候,是行級佔用,第一個執行緒是A-B順序,第二個執行緒是B-A順序,第一個執行緒佔了A,第二個執行緒佔了B,然後,然後就死鎖了;
  • 頁面點選操作,可能涉及到非常複雜的業務邏輯,是否考慮非同步化,引入排隊機制

    • 舉個例子,點選一個確認按鈕,背後很多業務邏輯,這時候需要使用者等待的時間比較長;
    • 如果存在少量資料和大量資料共同存在,切大資料量是常態的情況下,可以考慮非同步化操作;
    • 使用者點選之後,儲存任務在進行中的狀態,然後後臺多執行緒處理,處理完了之後,回寫狀態,頁面重新整理後看到最新的結果,如果不需要使用者重新整理就能看到結果,可以在頁面做長連線或者ajax輪訓;
  • 更新資料,例如更新十條,第六條出錯了,是回滾還是繼續處理

    • 批量操作,正常流程沒有問題,一下子全部成功,但是假如其中的一條出現錯誤;
    • 兩種方案,一種是所有的資料都回滾,然後提示使用者修改資料,重新提交,另外一種就是成功的提交,失敗的記錄下來,讓使用者重試失敗的資料,但是失敗的邏輯一定要有;
  • 頁面資料載入多個區塊的資料,且部分割槽塊獲取資料的介面高延遲

    • 同步載入的時候,整個頁面載入的速度會慢很多,所以在做資料載入設計的時候,就要區分掉;
    • 區塊可以修改為非同步ajax來進行載入資料;
  • 資料匯出功能,如果是非常少的資料匯出,則直接匯出即可,但是資料量大,就會面臨各種問題

    • 資料讀取的時候,如果多於特定的量,是否可以分頁或者多執行緒載入;
    • 匯出資料的上限限制,如果沒有上限,可能出現幾百萬的資料,使用者點選導致,由於http請求的超時機制,使用者可能會重複點選,此時伺服器和資料庫的壓力會很大;
    • 資料回寫,除了直接返回之外,是否可以寫檔案,然後直接提供給使用者需要下載的檔案連結;
    • 平時遇到的問題大多數是,系統剛剛上線,業務資料比較少,功能能夠正常,但是隨著業務發展,資料越來越多,導致的問題就是無法下載下來,而如果沒有做上面的優化或者保護的話,這個功能使用就會出現異常;


相關文章