第一部分 數據系統的基石
第一章 可靠性、可擴展性、可維護性
1、關於數據系統的思考
-
本書主要講 數據系統,是通過數據庫、隊列、緩存、搜索引擎等等組合而成的應用的稱呼,又可稱爲數據密集系統。
-
多個組件(數據庫、緩存、隊列等)配合使用的數據系統架構
-
數據軟件系統中三個很重要的問題
2、可靠性(Reliability)
-
簡單概念:即使出現偏離標準的問題(故障-fault),也能繼續正確工作(容錯-fault-tolerant)。容錯機制是爲了防止因故障而導致失效(停止爲用戶服務)。
-
故障類型
硬件故障(隨着科技進步和硬件冗餘該故障已變得相當罕見)
在遇到硬盤奔潰、內存出錯、機房斷電等原因時,一般是增加單個硬件冗餘,然後是引入軟件容錯。只有極少量要求非常高的應用會要求多套硬件冗餘。
軟件錯誤
軟件錯誤主要是指應用依賴的環境錯誤,如linux內核錯誤,cpu、內存等佔用過高,依賴服務變慢等等。這些錯誤很難被發現,一般會潛伏很久才觸發,可以做如下措施來預防和報警。
- 仔細考慮系統中的假設和交互
- 徹底的測試
- 進程隔離
- 允許進程奔潰並重啓
- 測量、監控並分析生產環境中的系統行爲
人爲錯誤 (主要故障來源)
從開發到測試到運維都會出現沒有考慮全面,或者人爲操作失誤等問題,這類問題不可避免,但是可以利用以下方法提高系統可靠性。
- 以最小化犯錯機會的方式設計系統
- 將容易犯錯的地方和可能導致服務不可用的地方解藕
- 徹底的測試,單元測試、系統集成測試、手動測試、自動化測試等等
- 允許人爲錯誤快速的恢復,最大限度減少失效情況帶來的影響
- 配置詳細和明確的監控,如性能指標和錯誤率等
3、可擴展性(Scalability)
-
可擴展性意味着即使在負載增加的情況下也有保持性能的策略。
-
討論可擴展步驟如下:
描述負載(數據庫讀寫比例、活躍用戶數、緩存命中率等)
負載可用一些稱爲負載參數的數字來描述,參數取決於系統架構。
描述性能(吞吐量、響應時間等)
一旦系統的負載被描述好,就可以研究當負載增加會發生什麼,從兩方面來說:
-
增加負載參數並保持系統資源(cpu、內存、網絡帶寬等)不變時,系統性能的影響?
-
增加負載參數並希望保持性能不變時,需要增加多少系統資源?
確定性能指標最好使用 百分位點 ,比如:要求99%的響應小於200ms,而不是平均響應時間要求200ms,這會使有一半的用戶感受到系統延遲,顯然是不允許的。
應對負載的方法(可擴展架構)
一個良好的可擴展架構是圍繞着假設建立的:哪些操作常見?哪些操作罕見?這就是所謂的擴展參數。
- 縱向擴展 :轉向更強大的機器,相對簡單。
- 橫向擴展 :將負載分散到多臺小機器,跨多臺機器分配負載也稱爲無共享架構。
- 彈性系統 :根據負載增加或減少自動增加或釋放計算資源。
-
4、可維護性
-
軟件大部分開銷並不在初期開發階段,而是在持續的維護階段:修復漏洞、調查服務不可用、適配新技術、添加新功能、償還技術債等。
-
可維護性方面的三個設計原則
第二章 數據模型與查詢語言
數據模型 影響着我們的解題思路
1、關係模型與文檔模型
-
NoSQL誕生的驅動因素:
- 需要比關係數據庫更好的擴展性,包括非常強大的數據集或非常高的寫入吞吐量。
- 相比商業數據庫產品,免費和開源軟件更受偏愛。
- 關係模型不能很好的支持一些特殊查詢操作。
- 受挫於關係模型的限制性,渴望一種更具多動態性與表現力的數據模型。
-
這一小節主要講了一些sql和noSql的歷史和規範,對我沒有太大幫助,簡單過了一遍,我這裏主要提一些名詞,有興趣的可以自行去了解
混合持久化(polyglot persistence)、阻抗不匹配(impedance mismatch)、ORM、數據庫規範化(normalization)、層次模型(hierarchical model)、關係模型(network model)、網絡模型(network model)、訪問路徑(access path)、
-
文檔數據庫和關係型數據庫對比
- 文檔數據庫通常數據是自我包含,而且文檔之間的關係非常稀少,最好不要有多對多。
- 文檔數據庫使用讀時模式(數據結構是隱含的,只有在數據庫讀取時才被解釋)
- 關係數據庫使用寫時模式(模式明確,數據庫保存所有的數據字段都固定不變,要變需要單獨更改表結構或遷移數據)
2、數據查詢語言
- MapReduce
- 批量處理大規模數據的編程模型
- 介於聲明式查詢(sql)和命令式查詢之間的模型
- 大多用於集羣上的分佈式計算
3、圖數據模型
-
圖的組成對象:頂點(也叫節點或實體)和 邊(叫關係或弧),典型案例:
社交圖譜:頂點是人,邊指哪些彼此認識的人。
網絡圖譜 :頂點是網頁,邊表示指向其他頁面的HTML鏈接。
公路或鐵路網絡 :頂點是交叉路口,邊代表他們之間的道路或鐵路線。
第三章 存儲與檢索
-
世界上最簡單的數據庫
#!/bin/bash db_set () { echo "$1,$2" >> database } db_get () { grep "^$1," database | sed -e "s/^$1,//" | tail -n 1 }
1、驅動數據庫的數據結構
- 這小節主要是用實例簡單介紹了下幾種數據結構:
哈希索引
、SSTables索引
、LSM樹
、B樹
、R樹
(空間索引數據結構),並多一些對比,並沒有探究具體的原理和實現方式。如果本身對這些數據結構原理不怎麼了解的話,看這小節可能會比較吃力。
2、事務處理還是分析
-
事務處理OLTP 和 分析系統OLAP 的特點
-
數據倉庫
- 數據倉庫是一個獨立的數據庫,包含一個公司所有各種OLTP系統中的只讀數據副本。
- ETL(抽取-轉換-加載) :從OLTP數據庫中提取數據,轉換成適合分析的模式,清理並加載到數據倉庫中。
-
聚合:物化視圖
數據倉庫查詢通常涉及一個聚合函數,如sql的count、sum、avg等,如果相同的聚合被許多不同的查詢使用,那麼每次都可以通過原始數據來處理。爲什麼不緩存一些查詢使用頻繁的計數或總和?創建這種緩存的一種方式就是物化視圖。
第四章、編碼與演化
1、編碼數據的格式
-
程序通常(至少)使用兩種形式的數據:
在內存中,數據保存在對象,結構體,列表,數據,哈希表,樹等中。
如果要將數據寫入文件,或通過網絡發送,則必須將其序列化爲某種字包含的字節序列(如json文檔)。
-
語言的特定格式
各語言提供將內存對象編碼爲字節序列的問題:
這類編碼通常與特定的編程語⾔言深度綁定,其他語⾔言很難讀取這種數據;
爲了了恢復相同對象類型的數據,解碼過程需要實例例化任意類的能力,這通常是安全問題的一個來源;
因爲它們旨在快速簡便地對數據進行編碼,所以往往忽略了前向後向兼容性帶來的麻煩問題;
效率(編碼或解碼所花費的CPU時間,以及編碼結構的⼤小);
因此最好不要使用語言內置編碼。
-
JSON、XML和二進制變體
文本格式存在的問題(json、xml、csv):
數字的編碼多有歧義之處。如:XML和CSV不能區分數字和字符串;JSON不區分整數和浮點數;
當處理⼤量數據時存在諸多限制。如:大於的整數不能在IEEE754雙精度浮點數中精確表示等;
不支持二進制數據。
-
接下來講了二進制編碼格式(messagePack,BSON等)以及對應使用場景(Thrift和Protocol Buffers),但實際上二進制編碼對於大多數開發人員來說接觸會很少,有興趣的可以讀讀,瞭解第三方組建採用的底層數據編碼。
-
Avro(有興趣單獨瞭解,這裏製作基本概述)
-
Apache Avro是另外一種二進制編碼格式。有兩種語言模式:一種(Avro IDL)是用於人工編輯,一種(基於JSON)更易於機器讀取。
-
使⽤用Avro,向前兼容性意味着您可以將新版本的架構作爲編寫器,並將舊版本的架構作爲讀者。相反, 向後兼容意味着你可以有一個作爲讀者的新版本的模式和作爲作者的舊版本。
-
2、數據流的類型
-
數據庫中的數據流
在不同的時候寫入不同的值:數據庫字段的值寫入,新字段的增加,我們往往都需要考慮廢棄字段,或者字段不爲空等對之前代碼邏輯和之後代碼邏輯的影響,要做到向前向後兼容。
歸檔存儲:利用數據歸檔,可以把老數據轉換爲適配新數據結構的數據。
-
服務中的數據流:REST與RPC
web服務:當服務使用http作爲底層協議通信時,可稱之爲web服務。
- 兩種流行的web服務方法:REST和SOAP;
- REST不是一個協議,而是一個基於HTTP原則的設計哲學,強調簡單的數據格式,使用URL來標識資源,使用HTTP功能進行緩存控制,身份驗證和內容類型協商。
- SOAP時用於製作網絡API請求的基於XML的協議,SOAP web服務的API使用稱爲web服務描述語言(WSDL)的基於XML的語言描述。
遠程過程調用(RPC)的問題
- 本地函數調用可預測,網絡請求是不可預知的,包含返回結果、調用時間、錯誤原因等等區別
-
消息傳遞中的數據流
異步消息系統:通過稱爲消息代理(消息隊列或面向消息的中間件)的中介來臨時存儲消息,與RPC相比,差異在於消息傳遞通信通常是單向的:發送者不期望收到消息的回覆。
- 如果收件人不可用或過載,可以充當緩衝區,從而提高系統可靠性。
- 它可以自動將消息重新發送到已經崩潰的進程,從⽽防止消息丟失。
- 避免發件人需要知道收件人的IP地址和端⼝號。
- 它允許將⼀條消息發送給多個收件⼈。
- 將發件人與收件人邏輯分離(發件人只是發佈郵件,不關⼼使用者)。