可靠的、可擴展的、可維護的數據系統 ------《Designing Data-Intensive Applications》讀書筆記1

来源:http://www.cnblogs.com/happenlee/archive/2017/12/07/7998429.html
-Advertisement-
Play Games

坦白說也是機緣巧合,在碩士生階段進入分散式系統領域學習。無論是大規模存儲或計算,其核心也是運用分散式技術利用並行性來解決數據密集型應用的需求。最近開始在啃這本 "《Designing Data Intensive Applications》" 大部頭,作者 "Martin Kleppmann" 在分 ...


坦白說也是機緣巧合,在碩士生階段進入分散式系統領域學習。無論是大規模存儲或計算,其核心也是運用分散式技術利用並行性來解決數據密集型應用的需求。最近開始在啃這本《Designing Data-Intensive Applications》大部頭,作者Martin Kleppmann在分散式數據系統領域有著很深的功底,併在這本書中完整的梳理各類紛繁複雜設計背後的技術邏輯,不同架構之間的妥協與超越,很值得開發人員與架構設計者閱讀。
很可惜的是國內目前並沒有對應的中文版本,這個系列算是一個讀書感悟,同時也夾帶私貨,闡述一些自己的理解與看法,拋磚引玉,希望大家多交流學習。這本書共有12個章節,接下來我會一個章節更新一篇讀書筆記。(囧rz,感覺自己又開了一個坑)同時也希望國內的出版社可以儘快引入版權,我也想要參與翻譯工作啊(,,• ₃ •,,) !!

1.數據密集應用

作為一個開發者來說,目前絕大多數應用程式都是數據密集型的,而不是計算密集型的。CPU的計算能力不再成為這些應用程式的限制因素,而更加亟待解決的問題是海量的數據、數據結構之間的複雜性,應用的性能。

先看看我們經常打交道的數據系統:

  • 存儲數據,以便它們或其他應用程式稍後再找到它(資料庫
  • 記住昂貴操作的結果,以加快讀取速度。(緩存
  • 允許用戶按關鍵字搜索數據或通過各種方式過濾數據(搜索索引
  • 將消息發送到另一個進程,非同步處理(流處理
  • 周期性地壓縮大量的累積數據(批處理

而很多時候,我們所謂應用程式的絕大工作就是將這些數據系統進行組合,然後添加我們的運行邏輯,但是如何更加合理的整合這些數據系統,對我們來說仍然是一個值得學習和思考的問題。而數據系統也在慢慢變得越來越相似,不同的數據系統也在各自學習彼此的優點。如Redis這樣的緩存系統可以支持數據落地,很多時候的應用場合我們可以替代傳統的RDBMS。而Kafka這樣的數據隊列也可以支持數據落地來存儲消息。更加深刻的理解這些數據系統,來更好的權衡架構設計,是一門很精深的課題。
結合多個數據系統的應用

上圖是一個典型的由多種數據系統構成的應用程式,隨著數據量和數據邏輯的複雜,就成為了一個數據密集型的應用。

2.設計數據密集型應用的三原則

  • 可靠性
    具有容錯性(面對硬體或軟體故障,甚至是人為錯誤),系統仍應繼續正常工作(在期望的性能水平上執行正確的功能)。
  • 可擴展性
    隨著系統的增長(在數據量、流量或複雜度),應該有合理的方法來處理這種增長。
  • 可維護性
    隨著時間的推移,許多不同的人將致力改善數據系統(既保持當前的行為,並使系統適應新的環境),他們都應該能夠卓有成效地工作。

顯然,這三個原則不單單是數據密集型應用應當遵循的原則,在絕大多數軟體系統中同樣是很重要的問題,接下來我們一一梳理一下。

(1)可靠性

  • 硬體故障
    硬碟崩潰,記憶體出現故障時,電網停電,有人拔了網線,幾乎硬體故障在數據中心總是不間斷的出現。
    解決方案

    • 在軟體與硬體層面考慮冗餘,來確保硬體的故障不會演變為系統的故障。
  • 人為的錯誤
    人是很不可靠,從駕駛技術的演變就可以看出來,人為的疏失會帶來巨大的災難。而且,人經常犯錯。
    解決方案

    • 最小化錯誤機會的方式設計系統。例如,精心設計的抽象,API和管理界面可以很容易地做“正確的事情”,阻止“錯誤的事情”。
  • 人們犯最多錯誤的地方和那些可能導致失敗的地方解耦。

  • 全面測試,從單元測試到整個系統集成測試和手動測試。

  • 允許快速和容易地從人為錯誤中恢復,以儘量減少在失敗的情況下的影響。例如,使其快速回滾更改配置,逐步推出新的代碼(所以任何意想不到的錯誤隻影響一小部分用戶),並提供工具來重新計算數據(如果原來舊的計算是不正確的)。

(2)可擴展性

即使一個系統今天工作可靠,但這並不意味著它將來一定會可靠地工作。一個常見原因是負載增加:也許系統已經從10000個併發用戶發展到100000個併發用戶,或者從100萬個增加到1000萬個。

“如果系統以特定的方式增長,我們應對增長的選擇是什麼?” “我們怎樣才能增加計算資源來處理額外的負載?”

  • 描述負載
    首先,我們需要簡潔地描述系統當前的負載,負載可以用幾個數字來描述,我們稱之為負載參數。
    參數的選擇取決於系統的體繫結構,如:
  • 每秒對Web伺服器的請求
  • 資料庫中的讀寫比
  • 聊天室中的活躍用戶數量
  • 緩存的命中率

  • 描述性能
    一旦描述了系統上的負載,就可以討論負載增加時發生的情況。可以從兩方面看:
    1.增加負載參數並保持系統資源(CPU、記憶體、網路帶寬等)不變時,系統的性能如何受到影響?
    2.當增加負載時,如果希望保持性能不變,需要增加多少資源?

所以我們需要有描述性能的尺子:

  • 平均響應時間:給定n值的算術平均值,全部加起來,除以n。然而這不是一個很好的指標,因為它不告訴你有多少用戶真正體驗了延遲。
  • 百分比響應時間:把響應時間列表,從最快到最慢排序,那麼中間值是中間點:例如,如果平均響應時間是200毫秒,那意味著一半請求在少於200毫秒時返回,而一半請求花費的時間比那個要長。
  • 高百分比的響應時間:可以看看高百分位數:95th,99th,和99.9th百分位數是常見的(簡稱P95,P99,和p999),來參考響應時間的閾值。

負載情況與性能情況是很重要的,有時系統的瓶頸是由少數極端情況引起的。作者舉了一個Twitter的例子,我覺得很好,這裡詳細分享一下這個例子:

Twitter的故事

Twitter在2012年11月16日公佈的數據。
Twitter的兩個主要操作是:

  • 發出Tweet
    用戶可以發佈一個Tweet給他們的訂閱者。(平均4.6k請求/秒,峰值超過1.2萬的請求/秒)。
  • 獲取Tweet
    用戶可以查看他們關註者發佈Tweet。(約300K的請求/秒)。

Twitter在擴展性的挑戰主要不是由於Tweet的數量,而主要是在每個用戶都有很多訂閱者,每個用戶也有很多關註者。執行這兩種操作大致是兩種方法:

  • 1、發佈一條推特,只需將新的推文插入到全球的推文集合中即可。當用戶請求他們關註者的Tweet時,可以查找他們所關註的所有人,並找到每個用戶的所有Tweet,並將它們合併(按時間排序)。在關係資料庫中,可以編寫如下查詢,例如:
    java SELECT tweets.*, users.* FROM tweets JOIN users ON tweets.sender_id = users.id JOIN follows ON follows.followee_id = users.id WHERE follows.follower_id = current_user
    如下圖所示:
    關係型資料庫的實現格式
  • 2、為每個用戶訂閱的Tweet維護一個緩存,就像每個收件人的Twitter郵箱一樣。當用戶發佈一條推文時,請查找所有關註該用戶的人,並將新的Tweet推送到他們的緩存中。所以讀取Tweet列表是很划算的,因為它的結果提前計算好了。

Twitter的數據管道,用於發送消息給訂閱者

如上圖所示的結構顯然更合適Tweet的發佈,因為發佈的Tweet的寫操作幾乎比讀的操作低兩個數量級,所以在這種情況下,最好是在寫時做更多的工作,而不是在讀時做更多的工作。但是方法2並不適用於有大量關註者的賬號,假設某人有3000W粉絲,一次發佈Tweet產生的寫操作可能是巨大的。所以目前在Twitter的Tweet系統中,Twitter將這兩種方法混合。大多數用戶的推文在發佈時仍然會被擴展到Tweet緩存之中,但只有少數用戶擁有大量的關註者(即名人)。用戶可以跟蹤的任何名人的Tweet,並單獨讀取並與用戶的Tweet緩存中進行合併。這種混合方法能夠始終如一地提供良好的性能。

這個例子很精煉的描述了架構設計的妥協與精妙,依據業務特點,最大化的優化了數據系統的性能。很佩服Twitter的工程師在架構設計上的功力。同時也很好奇如微博,微信是不是也是採用類似的架構進行設計。

  • 怎麼擴展
    放大(垂直縮放,移動到更強大的機器)和縮放(橫向縮放,在多台更小的機器上分配負載)之間的二選一。實際上,好的架構通常涉及到一種實用的混合方法:例如,使用幾個功能強大的機器仍然比大量的小型虛擬機更簡單、更便宜。無節制的分散式會給系統混入複雜度,這是軟體工程中危險的地方,雖然在多台機器上分發無狀態服務相當簡單,但將有狀態數據系統從單個節點轉移到分散式安裝程式會帶來許多額外的複雜性。
    沒有這樣的東西,一個通用的,一個適合所有的應用的可伸縮的架構。(寫的真好

(3)可維護性

這部分教導了一些構建可維護系統的方法。軟體的大部分成本不是在最初的開發中,而是在持續的維護中修複bug、保持系統運行、使其適應新業務、添加新特性。

  • 可操作性
    讓操作運維團隊保持系統運行的順利。

  • 簡單
    讓新工程師很容易理解系統,通過儘可能地從系統中刪除儘可能多的複雜性。

  • 可進化性
    讓工程師很容易在將來對系統進行更改,以適應需求變化時的意料之外的用例。也被稱為可擴展性、可修改性、可塑性。

維護別人留下的爛攤子真的是很痛苦的事情,文檔,註釋真的是重中之重!!!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、const聲明一個只讀的常量。一旦聲明,常量的值就不能改變。 2、const的作用域與let命令相同:只在聲明所在的塊級作用域內有效。 3、const命令聲明的常量也是不提升,只能在聲明的位置後面使用。 4、ES6中:var命令和function命令聲明的全局變數,依舊是頂層對象的屬性;另一方面 ...
  • 阿子原創,轉載請註明出處。 在使用jQuery Mobile Slider時,發現在頁面上下拖動時,很容易不小心觸發Slider的點擊事件,從而造成誤操作。為此需要禁用Slider的點擊事件。 官方API並沒有提供禁用點擊事件的事件的方法,因此要實現這一功能只能另闢蹊徑。 留意到點擊Slider時都 ...
  • 1、實現塊作用域 2、不存在變數提升。 ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變數,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變數,就會報錯。 ...
  • 網頁性能優化 頁面優化 頁面優化可以提升頁面的訪問速度從而提高用戶體驗,優化的頁面可以更好的提升 SEO 的效果同時也可以提高代碼的可讀性和維護性。 網頁的生成過程,大致可以分成五步。 1. HTML代碼轉化成DOM 2. CSS代碼轉化成CSSOM(CSS Object Model) 3. 結合D ...
  • 超級偶數(SuperEven)是指每一位都是偶數的正整數,例如: 0,2,4,6,8,20,22,24,26,28,40,...,88,200,202,... 要求寫一個函數,輸入項數n,返回數列第n項的值。 說實話,這個題目整整花了我三天時間去思考(數學比較弱,大神見笑)#手動捂臉#。 其實到最後 ...
  • 工廠模式(Factory Pattern)定義: 定義了一個創建對象的介面,但由子類決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類。 針對實現編程,但是當我們每次使用new時候,不正是在針對實現編程嗎?是的,當使用“new”時,你的確實在實例化一個具體類,所以用的確實是實現,而不是介面。代 ...
  • 我以一個過來人的身份來分析下,希望可以幫到你也能幫到大家。因為我也是通過轉行做UI的,我之前主要是做前端的,我工作時間應該算是比較長的了,大概有八九年了吧,其實在差不多六年前很多公司的UI設計和前端是不分的,通常有一個人來完成。 ...
  • 各位朋友,本次LZ分享的是狀態模式,在這之前,懇請LZ解釋一下,由於最近公司事情多,比較忙,所以導致更新速度稍微慢了些(哦,往後LZ會越來越忙=。=)。 狀態模式,又稱狀態對象模式(Pattern of Objects for States),狀態模式是對象的行為模式。 狀態模式允許一個對象在其內部 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...