1. 程式人生 > >分散式異構系統的資料一致性架構實現

分散式異構系統的資料一致性架構實現

分散式異構系統的實際應用場景

在現代的系統設計裡面,由於科技的不斷更新,分散式演算法和移動計算模型,分散式計算模型的成熟,

會產生很多系統遷移的案例, 主要是系統整合以及資料的遷移和整合。

隨著基於應用域的設計和開發(DDD)的成熟,讓微服務(Mirco-Service)架構的應運而生。

就產生了各個基於domain的細粒度的分散式系統的設計。每一個系統基於不同的應用域需求,運用了不同的架構設計實現,

和分散式儲存模型。

舉個例子,最簡單的一個購買推廣的雲平臺,提供Saas的商城購買服務。

那麼,在基於這種DDD的微服務(Micro-Service)架構的設計理念,

把整個Saas的架構基於不同的domain, 劃分成不同的微服務系統,

比如, 財務模組(Accounting), 社交模組(Social), 搜尋模組(Searching), 數字安全模組(Security),

統計報表模組(Reporting), BI模組(Business Intelligence)

 

在每一個這種模組裡面,都會基於實際的需求採用不同的分散式架構設計和分散式資料儲存。

在Social模組,主要記錄的是使用者的關係和Profile, 這一類用GraphDB 比較合適

在搜尋模組,會使用Solr或者Elastic Search作為Indexing引擎

在財務模組,會使用結構化儲存,以及強調資料一致性

在數字安全模組,使用OAuth,和結構化儲存

在統計報表模組,使用的是結構化儲存,和資料分析功能

在BI模組,使用的是HDFS和Hadoop以及使用資料平臺架構

那麼,其實在這種細粒度的微服務架構裡面, 在某些子系統存在著需要資料強一致或者最終一致性的要求。

那麼,在分散式異構系統裡面是如何做到保證資料完整性又不去損失對於高併發的支援。

首先,說幾個案例,

1. 一個對於外部智慧傢俱系統的資料採集和分析系統裡面,在對方Utilty公司用push的模式對於系統平臺,定時推送資料

的情況下,在每一秒鐘有上萬次資料採集甚至10w次資料採集頻率的級別下面, n * 100000 /second , 當時,系統

採用Hibernate的樂觀鎖,或者行級鎖,是沒有辦法Scale的

解決方案,把這個系統的儲存從Mysql改為了Cassandra

評論: 在這種系統裡面是不需要強調資料的完整性,所以不需要事務支援

2. 交易系統,在每秒鐘要求實時的高併發達到每秒上十萬甚至百萬級別的交易量, 要求是實時(Real-Time), 資料完整,

以及支援高吞吐(High Thought-put)和高併發(high Concurrent), 低延遲(Low Latency)

解決方案: 結合使用non-blocking和blocking演算法,在JVM層面達到系統設計要求

評論: 這種系統裡面需要同時支援高併發和資料完整性, 需要根據實際的應用需求設計系統

其實在CAP理論裡面,論述了Consistency, Availability 以及 Partition 不可兼得

舉個例子說明,還是以A, B, C 3個人的轉賬來稱述

初始狀態 A($100) B($100) C($0)

在時間點T1 A 向 B轉賬 $100 那麼系統狀態變化 ($0, $200, $0) 事件1: From A to B $100 狀態變化:[[A, -$100],[B, +$100]]

在時間點T2 B 向 C轉賬 $200 那麼系統狀態變化 ($0, $0, $200) 事件2: From B to C $200 狀態變化:[[B, -$100],[C, +$100]]

在一般的併發的事務處理裡面,系統一般是使用 Permisic Lock: 對於整個表,或者行級別加鎖,保證資料的一致性和完整性,

其實就是保證了這個事件序列的正確性。也就是事件1一定是發生在事件2之前的,是使用排他鎖(Mutual Lock)去完成的。

在這一個併發處理級別,是不太可能達到Scalable的。

那麼,如果是基於多個數據源的,一般是採用了基於2階段提交協議(2 phase commit)的處理方式,等多方表決一致的情況下

才一致提交,這種也是基於sync的處理方式,也是不能Scale效能的。

其實,在使用了Optimize Lock的之後,犧牲了一定程度的對於事件序列的一致性要求,來提高了整個系統的併發量,和可以一定程度的Scale

這個是一種無鎖併發演算法,也就是Lock-Free,在JDK裡面是使用了一些併發庫API,比如putIfAbsent的API等等,比如readAndUpdate的API

來實現一樣的Lock-Free演算法。

那麼,在接下來,我們說,這個系統是要支援高度併發的系統設計要求。

那麼,必須做到通過擴容伺服器的數量,就可以簡單有效地無限擴容計算效能,那麼,這個就是分散式演算法。

我們再次重述一下問題,

在時間點T1 A 向 B轉賬 $100 那麼系統狀態變化 ($0, $200, $0) 事件1: From A to B $100 狀態變化:[[A, -$100],[B, +$100]]

在時間點T2 B 向 C轉賬 $200 那麼系統狀態變化 ($0, $0, $200) 事件2: From B to C $200 狀態變化:[[B, -$100],[C, +$100]]

那麼,在分散式系統裡面,缺乏全域性狀態,沒有全域性時鐘,

如果,事件1 發生在一個在美國的伺服器,T1是當地時間 8:00 am, 隨後 事件2 發生在一箇中國的伺服器,T2: 當地時間 5:01pm

其實統一到UTC時間,他們只是相隔1分鐘發生的,但是在伺服器上面缺乏一致的時間。所以,也無法對於事件排序,說T1 是發生在T2之前,

那麼,作為使用者小A,看到的是在T1時刻,他發起轉賬,在T1.1時刻,他看到賬號裡面少了100刀,

使用者小B在T1時刻是$0,但是在T1.1時刻,他可能什麼都沒有看到,或者看到了100刀,取決於他的手機app讀取的是哪個分散式資料庫,

是在西雅圖的,還是在上海的,在T1時刻,資料先到了西雅圖的AWS上面,但是在上海的資料庫還沒有同步資料,因為partition的問題,

因為地域分佈的問題。如果,他在美國,看到的是轉賬成功,多了$200,但是如果他在上海,是看不到這個轉賬。

下面一個問題出現了,

如果小B看不到轉賬,他是無法向小C轉賬$200, 在UI上面做了限制

如果小B看到了轉賬,他是可以向小C轉賬$200,  那麼,還是partition的問題,他的轉賬對於,小C來說,或者是看到了,或者沒有看到,

就是,讀寫不一致的問題。在這種情況下,要強調資料強一致性,會損失系統的效能。那麼其實,只要做到session級別的資料一致就可以了。

這個是一種最終一致的強級別。

在系統設計上面,在分散式系統,使用happened before來定義事件發生序列,

還是以這個例子,

在時間點T1 A 向 B轉賬 $100 那麼系統狀態變化 ($0, $200, $0) 事件1: From A to B $100 狀態變化:[[A, -$100],[B, +$100]]

那麼,A的第一個狀態V1 是$100, 第二個狀態V2 是$0 B的第一個狀態V1 是$100 第二個狀態V2 是$200

對於分散式系統的狀態儲存是使用客戶端(Session at Client)儲存和分散式狀態(Distributed Session)儲存2種.

那麼不管哪一種狀態,在session層,始終是能根據不同資料的版本去同步資料,保證了資料在Session層面的一致性。

那麼,其實是資料庫保證了partition和availibity,但是在session層去保證了consistence,最終資料庫也會得到正確的資料版本更新。

這個就是在3年前大家一直使用的分散式異構系統的資料一致性實現方案。