? 可靠性: 系統(tǒng)在困境(adversity)(硬件故障、軟件故障、人為錯誤)中仍可正常工作(正確完成功能,并能達到期望的性能水準。
我們提供的服務有:成都做網站、成都網站建設、成都外貿網站建設、微信公眾號開發(fā)、網站優(yōu)化、網站認證、永城ssl等。為超過千家企事業(yè)單位解決了網站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的永城網站制作公司
? 可靠性(Reliability) 意味著即使發(fā)生故障,系統(tǒng)也能正常工作。故障可能發(fā)生在硬件(通常是隨機的和不相關的),軟件(通常是系統(tǒng)性的Bug,很難處理),和人類(不可避免地時不時出錯)。 容錯技術 可以對終端用戶隱藏某些類型的故障。
? 可擴展性: 有合理的辦法應對系統(tǒng)的增長(數(shù)據(jù)量、流量、復雜性)
? 可擴展性(Scalability) 意味著即使在負載增加的情況下也有保持性能的策略。為了討論可擴展性,我們首先需要定量描述負載和性能的方法。我們簡要了解了推特主頁時間線的例子,介紹描述負載的方法,并將響應時間百分位點作為衡量性能的一種方式。在可擴展的系統(tǒng)中可以添加 處理容量(processing capacity) 以在高負載下保持可靠。
? 可維護性:許多不同的人(工程師、運維)在不同的生命周期,都能高效地在系統(tǒng)上工作(使系統(tǒng)保持現(xiàn)有行為,并適應新的應用場景)
? 可維護性(Maintainability) 有許多方面,但實質上是關于工程師和運維團隊的生活質量的。良好的抽象可以幫助降低復雜度,并使系統(tǒng)易于修改和適應新的應用場景。良好的可操作性意味著對系統(tǒng)的健康狀態(tài)具有良好的可見性,并擁有有效的管理手段。
? 文檔數(shù)據(jù)庫的應用場景是:數(shù)據(jù)通常是自我包含的,而且文檔之間的關系非常稀少
? 圖形數(shù)據(jù)庫用于相反的場景:任意事物都可能與任何事物相關聯(lián)
? 在高層次上,我們看到存儲引擎分為兩大類:優(yōu)化 事務處理(OLTP) 或 在線分析(OLAP) 。這些用例的訪問模式之間有很大的區(qū)別:
OLTP系統(tǒng)通常面向用戶,這意味著系統(tǒng)可能會收到大量的請求。為了處理負載,應用程序通常只訪問每個查詢中的少部分記錄。應用程序使用某種鍵來請求記錄,存儲引擎使用索引來查找所請求的鍵的數(shù)據(jù)。磁盤尋道時間往往是這里的瓶頸。
數(shù)據(jù)倉庫和類似的分析系統(tǒng)會低調一些,因為它們主要由業(yè)務分析人員使用,而不是由最終用戶使用。它們的查詢量要比OLTP系統(tǒng)少得多,但通常每個查詢開銷高昂,需要在短時間內掃描數(shù)百萬條記錄。磁盤帶寬(而不是查找時間)往往是瓶頸,列式存儲是這種工作負載越來越流行的解決方案。
? Json XML 編碼 --> 二進制編碼的發(fā)展
? 二進制編碼技術:Apache Thrift / Protocol Buffers(protobuf)/
? 服務中的數(shù)據(jù)流:REST & RPC
? REST不是一個協(xié)議,而是一個基于HTTP原則的設計哲學。它強調簡單的數(shù)據(jù)格式,使用URL來標識資源,并使用HTTP功能進行緩存控制,身份驗證和內容類型協(xié)商。與SOAP相比,REST已經越來越受歡迎,至少在跨組織服務集成的背景下,并經常與微服務相關。根據(jù)REST原則設計的API稱為restful, 通常涉及較少的代碼生成和自動化工具。
? RPC調用和本地函數(shù)調用的不同:
? 復制意味著在通過網絡連接的多臺機器上保留相同數(shù)據(jù)的副本,需要復制的原因:
? 復制算法:單領導者(single leader),多領導者(multi leader)和無領導者(leaderless)
? 基于領導者的復制原理:
?
? 同步復制和異步復制:
?
? 同步復制的優(yōu)點是,從庫保證有與主庫一致的最新數(shù)據(jù)副本。如果主庫突然失效,我們可以確信這些數(shù)據(jù)仍然能在從庫上上找到。缺點是,如果同步從庫沒有響應(比如它已經崩潰,或者出現(xiàn)網絡故障,或其它任何原因),主庫就無法處理寫入操作。主庫必須阻止所有寫入,并等待同步副本再次可用。
? 因此,將所有從庫都設置為同步的是不切實際的:任何一個節(jié)點的中斷都會導致整個系統(tǒng)停滯不前。實際上,如果在數(shù)據(jù)庫上啟用同步復制,通常意味著其中一個跟隨者是同步的,而其他的則是異步的。如果同步從庫變得不可用或緩慢,則使一個異步從庫同步。這保證你至少在兩個節(jié)點上擁有最新的數(shù)據(jù)副本:主庫和同步從庫。 這種配置有時也被稱為 半同步。
? 通常情況下,基于領導者的復制都配置為完全異步。 在這種情況下,如果主庫失效且不可恢復,則任何尚未復制給從庫的寫入都會丟失。 這意味著即使已經向客戶端確認成功,寫入也不能保證 持久(Durable)。 然而,一個完全異步的配置也有優(yōu)點:即使所有的從庫都落后了,主庫也可以繼續(xù)處理寫入。
? 如何確保新的從庫擁有主庫數(shù)據(jù)的精確副本?
? 節(jié)點宕機:
? 從庫失效:追趕恢復
? 在其本地磁盤上,每個從庫記錄從主庫收到的數(shù)據(jù)變更。如果從庫崩潰并重新啟動,或者,如果主庫和從庫之間的網絡暫時中斷,則比較容易恢復:從庫可以從日志中知道,在發(fā)生故障之前處理的最后一個事務。因此,從庫可以連接到主庫,并請求在從庫斷開連接時發(fā)生的所有數(shù)據(jù)變更。當應用完所有這些變化后,它就趕上了主庫,并可以像以前一樣繼續(xù)接收數(shù)據(jù)變更流。
? 主庫失效:故障切換
故障切換的麻煩:
? 如果使用異步復制,則新主庫可能沒有收到老主庫宕機前最后的寫入操作
? 如果數(shù)據(jù)庫需要和其他外部存儲相協(xié)調,那么丟棄寫入內容是極其危險的操作。
? 發(fā)生某些故障時可能會出現(xiàn)兩個節(jié)點都以為自己是主庫的情況,這種情況稱為 腦裂(split brain)。一些系統(tǒng)采取了安全防范措施:當檢測到兩個主庫節(jié)點同時存在時會關閉其中一個節(jié)點ii,但設計粗糙的機制可能最后會導致兩個節(jié)點都被關閉。
復制日志的實現(xiàn):
? 1、基于語句的復制
? 2、傳輸預寫式日志(WAL)
? 3、邏輯日志復制(基于行)
? 另一種方法是,復制和存儲引擎使用不同的日志格式,這樣可以使復制日志從存儲引擎內部分離出來。這種復制日志被稱為邏輯日志,以將其與存儲引擎的(物理)數(shù)據(jù)表示區(qū)分開來。
? 4、基于觸發(fā)器的復制
復制延遲問題
? 1、讀己之寫
?
? 圖 用戶寫入后從舊副本中讀取數(shù)據(jù)。需要寫后讀(read-after-write)的一致性來防止這種異常
? 2、單調讀
? 圖 用戶首先從新副本讀取,然后從舊副本讀取。時光倒流。為了防止這種異常,我們需要單調的讀取。
? 3、一致前綴讀
?
? 圖 如果某些分區(qū)的復制速度慢于其他分區(qū),那么觀察者在看到問題之前可能會看到答案。
復制延遲問題的解決方案:事務(性能和可用性代價過高)和其他替代機制
多主復制
? 應用場景
? 1、運維多個數(shù)據(jù)中心
?
? 圖 跨多個數(shù)據(jù)中心的多主復制
? 2、需要離線的客戶端
? 考慮手機,筆記本電腦和其他設備上的日歷應用。無論設備目前是否有互聯(lián)網連接,你需要能隨時查看你的會議(發(fā)出讀取請求),輸入新的會議(發(fā)出寫入請求)。如果在離線狀態(tài)下進行任何更改,則設備下次上線時,需要與服務器和其他設備同步。
在這種情況下,每個設備都有一個充當領導者的本地數(shù)據(jù)庫(它接受寫請求),并且在所有設備上的日歷副本之間同步時,存在異步的多主復制過程。復制延遲可能是幾小時甚至幾天,具體取決于何時可以訪問互聯(lián)網。
從架構的角度來看,這種設置實際上與數(shù)據(jù)中心之間的多領導者復制類似,每個設備都是一個“數(shù)據(jù)中心”,而它們之間的網絡連接是極度不可靠的。從歷史上各類日歷同步功能的破爛實現(xiàn)可以看出,想把多活配好是多么困難的一件事。
? 3、協(xié)同編輯
? 我們通常不會將協(xié)作式編輯視為數(shù)據(jù)庫復制問題,但與前面提到的離線編輯用例有許多相似之處。當一個用戶編輯文檔時,所做的更改將立即應用到其本地副本(Web瀏覽器或客戶端應用程序中的文檔狀態(tài)),并異步復制到服務器和編輯同一文檔的任何其他用戶。
如果要保證不會發(fā)生編輯沖突,則應用程序必須先取得文檔的鎖定,然后用戶才能對其進行編輯。如果另一個用戶想要編輯同一個文檔,他們首先必須等到第一個用戶提交修改并釋放鎖定。這種協(xié)作模式相當于在領導者上進行交易的單領導者復制。
但是,為了加速協(xié)作,您可能希望將更改的單位設置得非常?。ɡ纾粋€按鍵),并避免鎖定。這種方法允許多個用戶同時進行編輯,但同時也帶來了多領導者復制的所有挑戰(zhàn),包括需要解決沖突。
? 處理寫入沖突(多領導者復制的最大問題)
?
圖 兩個主庫同時更新同一記錄引起的寫入沖突
無主復制
? 當節(jié)點故障時寫入數(shù)據(jù)庫
?
? 圖5-10 仲裁寫入,法定讀取,并在節(jié)點中斷后讀修復。
? 檢測并發(fā)寫入
?
? 圖 并發(fā)寫入Dynamo風格的數(shù)據(jù)存儲:沒有明確定義的順序。
? 捕獲"此前發(fā)生"關系
? 最初,購物車是空的。在它們之間,客戶端向數(shù)據(jù)庫發(fā)出五次寫入:
分區(qū)與復制
? 分區(qū)通常與復制結合使用,使得每個分區(qū)的副本存儲在多個節(jié)點上。
? 圖6-1 組合使用復制和分區(qū):每個節(jié)點充當某些分區(qū)的領導者,其他分區(qū)充當追隨者。
鍵值數(shù)據(jù)的分區(qū)
? 1、根據(jù)鍵的范圍分區(qū)(字典)
? 2、根據(jù)鍵的散列分區(qū)
分區(qū)與次級索引
? 次級索引是關系型數(shù)據(jù)庫的基礎,并且在文檔數(shù)據(jù)庫中也很普遍。許多鍵值存儲(如HBase和Volde-mort)為了減少實現(xiàn)的復雜度而放棄了次級索引,但是一些(如Riak)已經開始添加它們,因為它們對于數(shù)據(jù)模型實在是太有用了。并且次級索引也是Solr和Elasticsearch等搜索服務器的基石。
? 次級索引的問題是它們不能整齊地映射到分區(qū)。有兩種用二級索引對數(shù)據(jù)庫進行分區(qū)的方法:基于文檔的分區(qū)(document-based)和基于關鍵詞(term-based)的分區(qū)
? 按文檔的二級索引
?
? 根據(jù)關鍵詞(Term)的二級索引
?
分區(qū)再平衡
? 隨著時間的推移,數(shù)據(jù)庫會有各種變化。
所有這些更改都需要數(shù)據(jù)和請求從一個節(jié)點移動到另一個節(jié)點。 將負載從集群中的一個節(jié)點向另一個節(jié)點移動的過程稱為再平衡(reblancing)。
無論使用哪種分區(qū)方案,再平衡通常都要滿足一些最低要求:
? 平衡策略:
* 反面教材:hash mod N
* 固定數(shù)量的分區(qū)
* 動態(tài)分區(qū)
* 按節(jié)點比例分區(qū)
請求路由(客戶端發(fā)送請求時連接數(shù)據(jù)庫的那個節(jié)點?)
? 許多分布式數(shù)據(jù)系統(tǒng)都依賴于一個獨立的協(xié)調服務,比如ZooKeeper來跟蹤集群元數(shù)據(jù)。 下圖每個節(jié)點在ZooKeeper中注冊自己,ZooKeeper維護分區(qū)到節(jié)點的可靠映射。 其他參與者(如路由層或分區(qū)感知客戶端)可以在ZooKeeper中訂閱此信息。 只要分區(qū)分配發(fā)生的改變,或者集群中添加或刪除了一個節(jié)點,ZooKeeper就會通知路由層使路由信息保持最新狀態(tài)。
ACID
? 原子性(Atomicity)
? 在多線程編程中,如果一個線程執(zhí)行一個原子操作,這意味著另一個線程無法看到該操作的一半結果。系統(tǒng)只能處于操作之前或操作之后的狀態(tài),而不是介于兩者之間的狀態(tài)。
? ACID原子性的定義特征是:能夠在錯誤時中止事務,丟棄該事務進行的所有寫入變更的能力。如果這些寫操作被分組到一個原子事務中,并且該事務由于錯誤而不能完成(提交),則該事務將被中止,并且數(shù)據(jù)庫必須丟棄或撤消該事務中迄今為止所做的任何寫入。
? 一致性(Consistency)
? 對數(shù)據(jù)的一組特定陳述必須始終成立。即不變量(invariants)。例如,在會計系統(tǒng)中,所有賬戶整體上必須借貸相抵。如果一個事務開始于一個滿足這些不變量的有效數(shù)據(jù)庫,且在事務處理期間的任何寫入操作都保持這種有效性,那么可以確定,不變量總是滿足的。
? 原子性,隔離性和持久性是數(shù)據(jù)庫的屬性,而一致性(在ACID意義上)是應用程序的屬性。應用可能依賴數(shù)據(jù)庫的原子性和隔離屬性來實現(xiàn)一致性,但這并不僅取決于數(shù)據(jù)庫。
? 隔離性(Isolation)
? 同時執(zhí)行的事務是相互隔離的:它們不能相互冒犯。大多數(shù)數(shù)據(jù)庫都會同時被多個客戶端訪問。如果它們各自讀寫數(shù)據(jù)庫的不同部分,這是沒有問題的,但是如果它們訪問相同的數(shù)據(jù)庫記錄,則可能會遇到并發(fā)問題。
?
? 持久性(Durability)
? 持久性 是一個承諾,即一旦事務成功完成,即使發(fā)生硬件故障或數(shù)據(jù)庫崩潰,寫入的任何數(shù)據(jù)也不會丟失。
單對象和多對象操作
?
? 圖 違反隔離性:一個事務讀取另一個事務的未被執(zhí)行的寫入(“臟讀”)
? 沒有原子性,錯誤處理就要復雜得多,缺乏隔離性,就會導致并發(fā)問題。
事務隔離級別
? 讀已提交(Read Committed)
?
圖 沒有臟讀:用戶2只有在用戶1的事務已經提交后才能看到x的新值。
圖 如果存在臟寫,來自不同事務的沖突寫入可能會混淆在一起
? 讀取偏差(不可重復讀)
? 在同一個事務中,客戶端在不同的時間點會看見數(shù)據(jù)庫的不同狀態(tài)。快照隔離經常用于解決這個問題??煺崭綦x的實現(xiàn)通常使用寫鎖來防止臟寫,從性能的角度來看,快照隔離的一個關鍵原則是:讀不阻塞寫,寫不阻塞讀。為了實現(xiàn)快照隔離,數(shù)據(jù)庫必須可能保留一個對象的幾個不同的提交版本,這種技術被稱為多版本并發(fā)控制。
? 如果一個數(shù)據(jù)庫只需要提供讀已提交的隔離級別,而不提供快照隔離,那么保留一個對象的兩個版本就足夠了:提交的版本和被覆蓋但尚未提交的版本。支持快照隔離的存儲引擎通常也使用MVCC來實現(xiàn)讀已提交隔離級別。一種典型的方法是讀已提交為每個查詢使用單獨的快照,而快照隔離對整個事務使用相同的快照。
?
? 圖中,當事務12 從賬戶2 讀取時,它會看到 $500 的余額,因為 $500 余額的刪除是由事務13 完成的(根據(jù)規(guī)則3,事務12 看不到事務13 執(zhí)行的刪除),且400美元記錄的創(chuàng)建也是不可見的(按照相同的規(guī)則)
圖 使用多版本對象實現(xiàn)快照隔離
? 更新丟失
兩個客戶端同時執(zhí)行**讀取-修改-寫入序列**。其中一個寫操作,在沒有合并另一個寫入變更情況下,直接覆蓋了另一個寫操作的結果。所以導致數(shù)據(jù)丟失??煺崭綦x的一些實現(xiàn)可以自動防止這種異常,而另一些實現(xiàn)則需要手動鎖定(`SELECT FOR UPDATE`)。
? 幻讀
? 事務讀取符合某些搜索條件的對象。另一個客戶端進行寫入,影響搜索結果。快照隔離可以防止直接的幻像讀取,但是寫入歪斜環(huán)境中的幻影需要特殊處理,例如索引范圍鎖定。
在存儲過程中封裝事務
? 即使人類已經找到了關鍵路徑,事務仍然以交互式的客戶端/服務器風格執(zhí)行,一次一個語句。應用程序進行查詢,讀取結果,可能根據(jù)第一個查詢的結果進行另一個查詢,依此類推。查詢和結果在應用程序代碼(在一臺機器上運行)和數(shù)據(jù)庫服務器(在另一臺機器上)之間來回發(fā)送。
在這種交互式的事務方式中,應用程序和數(shù)據(jù)庫之間的網絡通信耗費了大量的時間。如果不允許在數(shù)據(jù)庫中進行并發(fā)處理,且一次只處理一個事務,則吞吐量將會非常糟糕,因為數(shù)據(jù)庫大部分的時間都花費在等待應用程序發(fā)出當前事務的下一個查詢。在這種數(shù)據(jù)庫中,為了獲得合理的性能,需要同時處理多個事務。
出于這個原因,具有單線程串行事務處理的系統(tǒng)不允許交互式的多語句事務。取而代之,應用程序必須提前將整個事務代碼作為存儲過程提交給數(shù)據(jù)庫。這些方法之間的差異如圖所示。如果事務所需的所有數(shù)據(jù)都在內存中,則存儲過程可以非??斓貓?zhí)行,而不用等待任何網絡或磁盤I/O。
?
? 圖 交互式事務和存儲過程之間的區(qū)別
? 存儲過程與內存存儲,使得在單個線程上執(zhí)行所有事務變得可行。由于不需要等待I/O,且避免了并發(fā)控制機制的開銷,它們可以在單個線程上實現(xiàn)相當好的吞吐量。
可序列化快照隔離(SSI, serializable snapshot isolation)
? 檢測舊MVCC讀取(讀之前存在未提交的寫入)
?
? 當一個事務從MVCC數(shù)據(jù)庫中的一致快照讀時,它將忽略取快照時尚未提交的任何其他事務所做的寫入。上圖中,事務43 認為Alice的 on_call = true
,因為事務42(修改Alice的待命狀態(tài))未被提交。然而,在事務43想要提交時,事務42 已經提交。這意味著在讀一致性快照時被忽略的寫入已經生效,事務43 的前提不再為真。
? 為了防止這種異常,數(shù)據(jù)庫需要跟蹤一個事務由于MVCC可見性規(guī)則而忽略另一個事務的寫入。當事務想要提交時,數(shù)據(jù)庫檢查是否有任何被忽略的寫入現(xiàn)在已經被提交。如果是這樣,事務必須中止。
為什么要等到提交?當檢測到陳舊的讀取時,為什么不立即中止事務43 ?因為如果事務43 是只讀事務,則不需要中止,因為沒有寫入偏差的風險。當事務43 進行讀取時,數(shù)據(jù)庫還不知道事務是否要稍后執(zhí)行寫操作。此外,事務42 可能在事務43 被提交的時候中止或者可能仍然未被提交,因此讀取可能終究不是陳舊的。通過避免不必要的中止,SSI 保留快照隔離對從一致快照中長時間運行的讀取的支持。
? 檢測影響之前讀取的寫入(讀之后寫入)
? 上圖中,事務42 和43 都在班次1234 查找值班醫(yī)生。如果在shift_id
上有索引,則數(shù)據(jù)庫可以使用索引項1234 來記錄事務42 和43 讀取這個數(shù)據(jù)的事實。 (如果沒有索引,這個信息可以在表級別進行跟蹤)。這個信息只需要保留一段時間:在一個事務完成(提交或中止)之后,所有的并發(fā)事務完成之后,數(shù)據(jù)庫就可以忘記它讀取的數(shù)據(jù)了。
? 當事務寫入數(shù)據(jù)庫時,它必須在索引中查找最近曾讀取受影響數(shù)據(jù)的其他事務。這個過程類似于在受影響的鍵范圍上獲取寫鎖,但鎖并不會阻塞事務到其他事務完成,而是像一個引線一樣只是簡單通知其他事務:你們讀過的數(shù)據(jù)可能不是最新的啦。
? 上圖中,事務43 通知事務42 其先前讀已過時,反之亦然。事務42首先提交并成功,盡管事務43 的寫影響了42 ,但因為事務43 尚未提交,所以寫入尚未生效。然而當事務43 想要提交時,來自事務42 的沖突寫入已經被提交,所以事務43 必須中止。
? 部分失效是分布式系統(tǒng)的決定性特征。為了容忍錯誤,第一步是檢測它們,但即使這樣也很難。大多數(shù)系統(tǒng)沒有檢測節(jié)點是否發(fā)生故障的準確機制,所以大多數(shù)分布式算法依靠超時來確定遠程節(jié)點是否仍然可用。 一旦檢測到故障,使系統(tǒng)容忍它也并不容易:沒有全局變量,沒有共享內存,沒有共同的知識,或機器之間任何其他種類的共享狀態(tài)。
? 大多數(shù)非安全關鍵系統(tǒng)會選擇便宜而不可靠,而不是昂貴和可靠。分布式系統(tǒng)可以永久運行而不會在服務層面中斷,因為所有的錯誤和維護都可以在節(jié)點級別進行處理——至少在理論上是如此。 (實際上,如果一個錯誤的配置變更被應用到所有的節(jié)點,仍然會使分布式系統(tǒng)癱瘓)。
一致性保證
? 最終一致性:非常弱的保證
? 線性一致性:最強一致性模型之一
? 因果一致性
線性一致性
?
? 圖 這個系統(tǒng)是非線性一致的,導致了球迷的困惑
? 線性一致性背后的基本思想很簡單:使系統(tǒng)看起來好像只有一個數(shù)據(jù)副本。
? 圖 可視化讀取和寫入看起來已經生效的時間點。 B的最后讀取不是線性一致性的
? 上圖中有一些有趣的細節(jié)需要指出:
第一個客戶端B發(fā)送一個讀取 x
的請求,然后客戶端D發(fā)送一個請求將 x
設置為 0
,然后客戶端A發(fā)送請求將 x
設置為 1
。盡管如此,返回到B的讀取值為 1
(由A寫入的值)。這是可以的:這意味著數(shù)據(jù)庫首先處理D的寫入,然后是A的寫入,最后是B的讀取。雖然這不是請求發(fā)送的順序,但這是一個可以接受的順序,因為這三個請求是并發(fā)的。也許B的讀請求在網絡上略有延遲,所以它在兩次寫入之后才到達數(shù)據(jù)庫。
在客戶端A從數(shù)據(jù)庫收到響應之前,客戶端B的讀取返回 1
,表示寫入值 1
已成功。這也是可以的:這并不意味著在寫之前讀到了值,這只是意味著從數(shù)據(jù)庫到客戶端A的正確響應在網絡中略有延遲。
此模型不假設有任何事務隔離:另一個客戶端可能隨時更改值。例如,C首先讀取 1
,然后讀取 2
,因為兩次讀取之間的值由B更改??梢允褂迷?strong>比較并設置(cas)操作來檢查該值是否未被另一客戶端同時更改:B和C的cas請求成功,但是D的cas請求失?。ㄔ跀?shù)據(jù)庫處理它時,x
的值不再是 0
)。
客戶B的最后一次讀?。幱皸l柱中)不是線性一致性的。 該操作與C的cas寫操作并發(fā)(它將 x
從 2
更新為 4
)。在沒有其他請求的情況下,B的讀取返回 2
是可以的。然而,在B的讀取開始之前,客戶端A已經讀取了新的值 4
,因此不允許B讀取比A更舊的值。再次,與圖9-1中的Alice和Bob的情況相同。
這就是線性一致性背后的直覺。 正式的定義【6】更準確地描述了它。 通過記錄所有請求和響應的時序,并檢查它們是否可以排列成有效的順序,測試一個系統(tǒng)的行為是否線性一致性是可能的(盡管在計算上是昂貴的)【11】。
線性一致性的有效場景
? 鎖定和領導選舉 (zookeeper etcd 使用一致性算法以容錯方式保證)
? 約束和唯一性保證 (用戶名或電子郵件地址必須唯一標識一個用戶)
? 跨信道的時序依賴
? 圖 Web服務器和圖像調整器通過文件存儲和消息隊列進行通信,打開競爭條件的可能性
? 出現(xiàn)這個問題是因為Web服務器和縮放器之間存在兩個不同的信道:文件存儲與消息隊列。沒有線性一致性的新鮮性保證,這兩個信道之間的競爭條件是可能的。
因果一致性
? 因果性對系統(tǒng)中的事件施加了順序(什么發(fā)生在什么之前,基于因與果)。與線性一致不同,線性一致性將所有操作放在單一的全序時間線中,因果一致性為我們提供了一個較弱的一致性模型:某些事件可以是并發(fā)的,所以版本歷史就像是一條不斷分叉與合并的時間線。因果一致性沒有線性一致性的協(xié)調開銷,而且對網絡問題的敏感性要低得多。
分布式事務與共識
? 共識:所有節(jié)點一致同意所做決定,且這一決定不可撤銷。
? 共識問題:
? 線性一致性的CAS寄存器
寄存器需要基于當前值是否等于操作給出的參數(shù),原子地**決定**是否設置新值。
? 原子事務提交
數(shù)據(jù)庫必須**決定**是否提交或中止分布式事務。
? 全序廣播
消息系統(tǒng)必須**決定**傳遞消息的順序。
? 鎖和租約
當幾個客戶端爭搶鎖或租約時,由鎖來**決定**哪個客戶端成功獲得鎖。
? 成員/協(xié)調服務
給定某種故障檢測器(例如超時),系統(tǒng)必須**決定**哪些節(jié)點活著,哪些節(jié)點因為會話超時需 要被宣告死亡。
? 唯一性約束
當多個事務同時嘗試使用相同的鍵創(chuàng)建沖突記錄時,約束必須**決定**哪一個被允許,哪些因為 違反約束而失敗。
三種系統(tǒng)類型
? *服務(在線系統(tǒng))*:每收到一個,服務會試圖盡快處理它,并發(fā)回一個響應。響應時間通常 是服務性能的主要衡量指標,可用性通常非常重要
? 批處理系統(tǒng)(離線系統(tǒng))*:大量的輸入數(shù)據(jù),跑一個作業(yè)(job)*來處理它,并生成一些輸出 數(shù)據(jù),這往往需要一段時間(從幾分鐘到幾天),所以通常不會有用戶等待作業(yè)完成。相反,批 量作業(yè)通常會定期運行(例如,每天一次)。批處理作業(yè)的主要性能衡量標準通常是吞吐量(處 理特定大小的輸入所需的時間).
? *流處理系統(tǒng)(準實時系統(tǒng))*: 介于兩者之間。流處理消費輸入并產生輸出,在事件發(fā)生后不久就會對事件進行操作,不會等待一組固定的輸入數(shù)據(jù)(批處理的特點),因此具有低延遲的特點。
UNIX 分析簡單日志
cat /var/log/nginx/access.log | #1
awk '{print $7}' | #2
sort | #3
uniq -c | #4
sort -r -n | #5
head -n 5 #6
1. 讀取日志文件
2. 將每一行按空格分割成不同的字段,每行只輸出第七個字段,恰好是請求的URL。在我們的例子中是`/css/typography.css`。
3. 按字母順序排列請求的URL列表。如果某個URL被請求過n次,那么排序后,文件將包含連續(xù)重復出現(xiàn)n次的該URL。
4. `uniq`命令通過檢查兩個相鄰的行是否相同來過濾掉輸入中的重復行。 `-c`則表示還要輸出一個計數(shù)器:對于每個不同的URL,它會報告輸入中出現(xiàn)該URL的次數(shù)。
5. 第二種排序按每行起始處的數(shù)字(`-n`)排序,這是URL的請求次數(shù)。然后逆序(`-r`)返回結果,大的數(shù)字在前。
6. 最后,只輸出前五行(`-n 5`),并丟棄其余的
output:
4189 /favicon.ico
3631 /2013/05/24/improving-security-of-ssh-private-keys.html
2124 /2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html
1369 /
915 /css/typography.css
? 優(yōu)點:接受任意形式輸入,符合萬物皆文件的概念 (進程的輸出可以是下一個進程的輸入)
? 各命令之間的性能高。
? 缺點:只能在一臺機器上運行(進程到進程) ---> 引出Hadoop
MapReduce
? MapReduce是一個編程框架,你可以使用它編寫代碼來處理HDFS等分布式文件系統(tǒng)中的大型數(shù)據(jù)集。支持多臺機器上進行并行計算。Mapper和Reducer一次只能處理一條記錄;它們不需要知道它們的輸入來自哪里,或者輸出去往什么地方,所以框架可以處理在機器之間移動數(shù)據(jù)的復雜性。
? 要創(chuàng)建MapReduce作業(yè),你需要實現(xiàn)兩個回調函數(shù),Mapper和Reducer。
? Mapper
? Mapper會在每條輸入記錄上調用一次,其工作是從輸入記錄中提取鍵值。對于每個輸入,它可以生成任意數(shù)量的鍵值對(包括None)。它不會保留從一個輸入記錄到下一個記錄的任何狀態(tài),因此每個記錄都是獨立處理的。
? Reducer
? MapReduce框架拉取由Mapper生成的鍵值對,收集屬于同一個鍵的所有值,并使用在這組值列表上迭代調用Reducer。 Reducer可以產生輸出記錄(例如相同URL的出現(xiàn)次數(shù))。
? 分布式執(zhí)行MapReduce
?
? 每個輸入文件的大小通常是數(shù)百兆字節(jié)。 MapReduce調度器(圖中未顯示)試圖在其中一臺存儲輸入文件副本的機器上運行每個Mapper,只要該機器有足夠的備用RAM和CPU資源來運行Mapper任務【26】。這個原則被稱為將計算放在數(shù)據(jù)附近【27】:它節(jié)省了通過網絡復制輸入文件的開銷,減少網絡負載并增加局部性。
? 計算的Reduce端也被分區(qū)。雖然Map任務的數(shù)量由輸入文件塊的數(shù)量決定,但Reducer的任務的數(shù)量是由作業(yè)作者配置的(它可以不同于Map任務的數(shù)量)。為了確保具有相同鍵的所有鍵值對最終落在相同的Reducer處,框架使用鍵的散列值來確定哪個Reduce任務應該接收到特定的鍵值對。
? 只要當Mapper讀取完輸入文件,并寫完排序后的輸出文件,MapReduce調度器就會通知Reducer可以從該Mapper開始獲取輸出文件。Reducer連接到每個Mapper,并下載自己相應分區(qū)的有序鍵值對文件。按Reducer分區(qū),排序,從Mapper向Reducer復制分區(qū)數(shù)據(jù),這一整個過程被稱為混洗(shuffle)
? Reduce任務從Mapper獲取文件,并將它們合并在一起,并保留有序特性。因此,如果不同的Mapper生成了鍵相同的記錄,則在Reducer的輸入中,這些記錄將會相鄰。Reducer調用時會收到一個鍵,和一個迭代器作為參數(shù),迭代器會順序地掃過所有具有該鍵的記錄(因為在某些情況可能無法完全放入內存中)。Reducer可以使用任意邏輯來處理這些記錄,并且可以生成任意數(shù)量的輸出記錄。這些輸出記錄會寫入分布式文件系統(tǒng)上的文件中
? 排序合并連接
?
? 為了在批處理過程中實現(xiàn)良好的吞吐量,計算必須(盡可能)限于單臺機器上進行。為待處理的每條記錄發(fā)起隨機訪問的網絡請求實在是太慢了。更好的方法是獲取用戶數(shù)據(jù)庫的副本,并將它和用戶行為日志放入同一個分布式文件系統(tǒng)中。
? 當MapReduce框架通過鍵對Mapper輸出進行分區(qū),然后對鍵值對進行排序時,效果是具有相同ID的所有活動事件和用戶記錄在Reducer輸入中彼此相鄰。 Map-Reduce作業(yè)甚至可以也讓這些記錄排序,使Reducer總能先看到來自用戶數(shù)據(jù)庫的記錄,緊接著是按時間戳順序排序的活動事件 —— 這種技術被稱為二次排序(secondary sort)
? 由于Reducer一次處理一個特定用戶ID的所有記錄,因此一次只需要將一條用戶記錄保存在內存中,而不需要通過網絡發(fā)出任何請求。這個算法被稱為排序合并連接(sort-merge join),因為Mapper的輸出是按鍵排序的,然后Reducer將來自連接兩側的有序記錄列表合并在一起。
? 處理傾斜
? 在單個Reducer中收集與某個名流相關的所有活動(例如他們發(fā)布內容的回復)可能導致嚴重的傾斜(也稱為熱點(hot spot))—— 也就是說,一個Reducer必須比其他Reducer處理更多的記錄(參見“負載傾斜與消除熱點“)。由于MapReduce作業(yè)只有在所有Mapper和Reducer都完成時才完成,所有后續(xù)作業(yè)必須等待最慢的Reducer才能啟動。
? Pig中的傾斜連接(skewed join)方法首先運行一個抽樣作業(yè)來確定哪些鍵是熱鍵。連接實際執(zhí)行時,Mapper會將熱鍵的關聯(lián)記錄隨機(相對于傳統(tǒng)MapReduce基于鍵散列的確定性方法)發(fā)送到幾個Reducer之一。對于另外一側的連接輸入,與熱鍵相關的記錄需要被復制到所有處理該鍵的Reducer上
? 廣播散列連接
? 兩個連接輸入之一很小,所以它并沒有分區(qū),而且能被完全加載進一個哈希表中。因此,你可以為連接輸入大端的每個分區(qū)啟動一個Mapper,將輸入小端的散列表加載到每個Mapper中,然后掃描大端,一次一條記錄,并為每條記錄查詢散列表。
? 分區(qū)散列連接
? 如果兩個連接輸入以相同的方式分區(qū)(使用相同的鍵,相同的散列函數(shù)和相同數(shù)量的分區(qū)),則可以獨立地對每個分區(qū)應用散列表方法。
? 回調函數(shù)
? 分布式批處理引擎有一個刻意限制的編程模型:回調函數(shù)(比如Mapper和Reducer)被假定是無狀態(tài)的,而且除了指定的輸出外,必須沒有任何外部可見的副作用。這一限制允許框架在其抽象下隱藏一些困難的分布式系統(tǒng)問題:當遇到崩潰和網絡問題時,任務可以安全地重試,任何失敗任務的輸出都被丟棄。如果某個分區(qū)的多個任務成功,則其中只有一個能使其輸出實際可見。
? 得益于這個框架,你在批處理作業(yè)中的代碼無需操心實現(xiàn)容錯機制:框架可以保證作業(yè)的最終輸出與沒有發(fā)生錯誤的情況相同,也許不得不重試各種任務。在線服務處理用戶請求,并將寫入數(shù)據(jù)庫作為處理請求的副作用,比起在線服務,批處理提供的這種可靠性語義要強得多。
批處理的特點總結
? 批處理作業(yè)的顯著特點是,它讀取一些輸入數(shù)據(jù)并產生一些輸出數(shù)據(jù),但不修改輸入—— 換句話說,輸出是從輸入衍生出的。最關鍵的是,輸入數(shù)據(jù)是有界的(bounded):它有一個已知的,固定的大小(例如,它包含一些時間點的日志文件或數(shù)據(jù)庫內容的快照)。因為它是有界的,一個作業(yè)知道自己什么時候完成了整個輸入的讀取,所以一個工作在做完后,最終總是會完成的。
? 消息代理和事件日志可以視作文件系統(tǒng)的流式等價物。
消息代理(消息隊列)
? 與數(shù)據(jù)庫的差異
? 多個消費者
? 負載均衡與扇出
?
? 圖(a)負載平衡:在消費者間共享消費主題;(b)扇出:將每條消息傳遞給多個消費者。
? 兩種模式可以組合使用:例如,兩個獨立的消費者組可以每組各訂閱一個主題,每一組都共同收到所有消息,但在每一組內部,每條消息僅由單個節(jié)點處理。
? 分區(qū)日志(基于日志的消息代理)
?
圖 生產者通過將消息追加寫入主題分區(qū)文件來發(fā)送消息,消費者依次讀取這些文件
? 變更數(shù)據(jù)捕獲(CDC)
?
圖 將數(shù)據(jù)按順序寫入一個數(shù)據(jù)庫,然后按照相同的順序將這些更改應用到其他系統(tǒng)
流處理的三種類型
? 流流連接
? 兩個輸入流都由活動事件組成,而連接算子在某個時間窗口內搜索相關的事件。例如,它可能會將同一個用戶30分鐘內進行的兩個活動聯(lián)系在一起。如果你想要找出一個流內的相關事件,連接的兩側輸入可能實際上都是同一個流(自連接(self-join))。
? 流表連接
? 一個輸入流由活動事件組成,另一個輸入流是數(shù)據(jù)庫變更日志。變更日志保證了數(shù)據(jù)庫的本地副本是最新的。對于每個活動事件,連接算子將查詢數(shù)據(jù)庫,并輸出一個擴展的活動事件。
? 表表連接
? 兩個輸入流都是數(shù)據(jù)庫變更日志。在這種情況下,一側的每一個變化都與另一側的最新狀態(tài)相連接。結果是兩表連接所得物化視圖的變更流。
? 某些系統(tǒng)被指定為記錄系統(tǒng),而其他數(shù)據(jù)則通過轉換衍生自記錄系統(tǒng)。通過這種方式,我們可以維護索引,物化視圖,機器學習模型,統(tǒng)計摘要等等。通過使這些衍生和轉換操作異步且松散耦合,能夠防止一個區(qū)域中的問題擴散到系統(tǒng)中不相關部分,從而增加整個系統(tǒng)的穩(wěn)健性與容錯性。
? 將數(shù)據(jù)流表示為從一個數(shù)據(jù)集到另一個數(shù)據(jù)集的轉換也有助于演化應用程序:如果你想變更其中一個處理步驟,例如變更索引或緩存的結構,則可以在整個輸入數(shù)據(jù)集上重新運行新的轉換代碼,以便重新衍生輸出。同樣,出現(xiàn)問題時,你也可以修復代碼并重新處理數(shù)據(jù)以便恢復。
? 這些過程與數(shù)據(jù)庫內部已經完成的過程非常類似,因此我們將數(shù)據(jù)流應用的概念重新改寫為,分拆(unbundling) 數(shù)據(jù)庫組件,并通過組合這些松散耦合的組件來構建應用程序。
? 衍生狀態(tài)可以通過觀察底層數(shù)據(jù)的變更來更新。此外,衍生狀態(tài)本身可以進一步被下游消費者觀察。我們甚至可以將這種數(shù)據(jù)流一路傳送至顯示數(shù)據(jù)的終端用戶設備,從而構建可動態(tài)更新以反映數(shù)據(jù)變更,并在離線時能繼續(xù)工作的用戶界面。
? 接下來,我們討論了如何確保所有這些處理在出現(xiàn)故障時保持正確。我們看到可擴展的強完整性保證可以通過異步事件處理來實現(xiàn),通過使用端到端操作標識符使操作冪等,以及通過異步檢查約束??蛻舳丝梢缘鹊綑z查通過,或者不等待繼續(xù)前進,但是可能會冒有違反約束需要道歉的風險。這種方法比使用分布式事務的傳統(tǒng)方法更具可擴展性與可靠性,并且在實踐中適用于很多業(yè)務流程。
? 通過圍繞數(shù)據(jù)流構建應用,并異步檢查約束,我們可以避免絕大多數(shù)的協(xié)調工作,創(chuàng)建保證完整性且性能仍然表現(xiàn)良好的系統(tǒng),即使在地理散布的情況下與出現(xiàn)故障時亦然。然后,我們對使用審計來驗證數(shù)據(jù)完整性,以及損壞檢測進行了一些討論。
? 最后,我們退后一步,審視了構建數(shù)據(jù)密集型應用的一些道德問題。我們看到,雖然數(shù)據(jù)可以用來做好事,但它也可能造成很大傷害:作出嚴重影響人們生活的決定卻難以申訴,導致歧視與剝削,監(jiān)視常態(tài)化,曝光私密信息。我們也冒著數(shù)據(jù)被泄露的風險,并且可能會發(fā)現(xiàn),即使是善意地使用數(shù)據(jù)也可能會導致意想不到的后果。
? 由于軟件和數(shù)據(jù)對世界產生了如此巨大的影響,我們工程師們必須牢記,我們有責任為我們想要的那種世界而努力:一個尊重人們,尊重人性的世界。我希望我們能夠一起為實現(xiàn)這一目標而努力。