閱界資訊

第362期:GitHub 工程師談系統設計

閱閱界編輯部2閱讀4分鐘

上週,我讀到一篇文章,作者是 GitHub 的高級工程師肖恩·戈德克(sean goedecke)。文章題目是《我所知的良好的系統設計》。讀完後,我覺得寫得不錯。GitHub 工程師總結經驗,教大家設計一個良好的系統,不是空泛之談。下面是我的一些摘錄。1、程序設計是組裝代碼,系統設計是組裝服務。程序設計的組件是變量、函數、類等,系統設計的組件是服務器、數據庫、緩存、隊列、事件總線、代理等。2、

如果一個系統很長時間不出錯,它的設計就是良好的。如果你進一步看了代碼,脫口而出:“哈,這比我想的要簡單”,或者“這個部分不用我操心,即使出問題也容易解決”,它的設計就是優秀的。3、良好的系統設計,總是從一個有效的簡單系統發展而來。千萬不要從零開始設計一個複雜的系統。4、系統設計的難點在於狀態。儘量採用無狀態組件,最小化“有狀態組件”的數量。狀態的複雜性在於,你無法簡單地重啓服務。一旦出錯,往往需要手動修復狀態。5、

狀態需要保存在數據庫。數據庫是最重要的系統組件,用來管理狀態。數據庫的設計目標是每張表易於理解:打開看一下表結構,就能大致瞭解存儲的數據內容及其原因。千萬不要採用複雜的表結構(也就是數據結構),會給代碼帶來極大的複雜性和性能約束。6、數據庫往往是系統瓶頸,因爲每個頁面請求可能要調用數十次、數百次數據庫,而且是按順序調用。爲了避免瓶頸,數據庫可以做成一個寫入節點和多個只讀副本。數據查詢都發往只讀副本,數據寫入發往寫入節點。

寫入節點與只讀副本之間,存在數據複製延遲。如果更新一條記錄後,你需要立即讀取它,那麼可以將數據放入內存,寫入數據庫成功後從內存讀取。7、耗時的操作要拆分出來,放在後臺作業(即系統外部的單獨服務),排隊完成。後臺作業主要分成兩個組件:一個隊列服務,一個作業運行器(從隊列中獲取任務並執行)。隊列任務的軟件,可以用 Redis(需要儘快執行的任務),也可以用數據庫(不着急的任務)。8、

如果數據的生成速度和讀取速度不匹配,經典解決方案就是緩存。緩存的最簡單做法,就是把數據保存在內存,否則就使用專門的鍵值存儲軟件(比如 Redis 或 Memcached),後者的好處是多個服務器可以共享緩存。初級工程師希望緩存所有內容,而高級工程師希望儘量少用緩存。因爲緩存是狀態的來源,不可避免需要校驗狀態和處理狀態過期。9、除了緩存和後臺作業,大型系統通常還有事件中心,一般用的是 Kafka。

事件中心也是一個隊列,存放的是“某件事發生了”的消息。比如,用戶註冊觸發了“新帳戶創建”事件,該事件就放入事件中心,然後由事件中心去通知訂閱該事件的多個服務:發送歡迎電子郵件、設置個人空間等等。事件中心適用於,發送事件的代碼不關心其他服務如何處理事件,或者事件量很大且對響應時間不太敏感。不要過度使用事件,很多時候,更簡單的做法是讓一個服務請求另一個服務的 API。爲了便於除錯,所有日誌最好都放在一起,你可以立即看到另一個服務的響應。

10、推拉如果數據需要傳送到多處,有拉取(pull)和推送(push)兩種選擇。一般來說,拉取比較簡單(比如大多數網站採用的輪詢),推送更節省資源,不需要用戶主動請求數據,一旦後端數據發生變化,服務器主動將數據推送給每個客戶端。

如果你確實需要向100萬個客戶端提供最新數據(就像 GMail 那樣),應該採用推送還是拉取?這要視情況而定。如果採用推送,就要把每次推送放入一個事件隊列,並讓一大羣事件處理器從隊列中拉取數據並推送。如果採用拉取,就要部署一堆(比如100臺)快速的只讀緩存服務器,處理所有讀取流量。

來源|阮一峯科技愛好者週刊第 362 期,

每週精選周刊头条

評論(0)

暫無評論,來搶第一條。