Apache Cassandra和Apache Ignite:強一致和事務 頂 原 薦

NoSQL數據庫,比如Apache Cassandra,是最終一致性系統的典型案例,這種系統的機制比較簡單:如果應用在一臺主機上觸發了數據的變更,那麼在某個時間點更新會被傳播到所有的副本,換言之,最終一致。

在變更完全同步之前,系統作爲一個整體會處於一個不一致的狀態。如果從一個未同步的副本中讀取變更的數據,更甚者,同時更新數據,誰知道會發生什麼呢?

NoSQL的廠商和用戶接受了這個機制和行爲,因爲最終一致給分佈式系統帶來了高可擴展和高性能,這是事實,如果需要強一致和事務,那麼就得考慮傳統RDBMS了,但是現在不是這樣了!

在前面的文章中,提到即使在分佈式數據庫中,SQL也可以高效地執行。比如Apache Ignite,不僅僅可以執行簡單的SQL操作,還可以容易地對存儲於不同主機的數據進行關聯,這在十年前是不可能的,但是目前已經成爲現代分佈式數據庫的標配。

再次回到一致性和事務的話題,Ignite可以混合匹配NoSQL的水平擴展和高性能以及RDBMS領域的功能,下面會以Apache Cassandra作爲NoSQL數據庫的代表,與Ignite作爲現代分佈式數據庫的代表進行比較。

可調一致性和輕量級事務

Cassandra關注於高數據一致性和事務,這不是祕密,因爲這是用戶的需求。 首先,如果將讀寫一致性級別配置爲ALL,這就獲得了最高的一致性。這個模式中,Cassandra會在完成提交日誌和所有副本節點內存表的寫入之後完成寫入操作,相對應的對於讀,會在所有副本認可的情況下,纔會返回值。這個功能很方便,但是它在保證一致性的前提下,降低了性能,如果需要,可以啓用。

其次,這個讀寫ALL模式沒有解決併發更新的問題。如果要更新一個用戶賬戶,如何確保沒有其他人干擾呢?事務通常用於解決這樣的問題,這時用戶可以使用Cassandra的叫做輕量級事務(LWT)的功能。

輕量級事務是爲避免單條記錄的併發更新而特別設計的。比如,如果兩個不同的應用都試圖更新一個用戶賬戶,那麼LWT會確保只有一個應用成功,而其他的失敗。假定第一個應用更早地發起了一個事務,那麼就可以像下面這樣安全而原子地對年齡進行修改:

UPDATE user_account
SET    user_age=35
IF     user_id=’Bob Smith’; 

但是對於更復雜的操作,比如不同賬戶間的轉賬,會怎麼樣呢?

不幸的是,這超出了Cassandra及其LWT的範圍,因爲後者限定在單一分區內,而銀行賬戶是可以存儲在不同的集羣節點上的。

強一致和ACID事務

雖然轉賬在Cassandra中是個大問題,但是在Ignite中卻是個常規操作。 首先,在Ignite中要做到強一致性,需要配置FULL_SYNC同步模式以及爲緩存(或者表)開啓事務模式,甚至開啓FSYNC模式的預寫日誌來避免整個集羣的電源故障。

其次,使用Ignite的事務API,可以對可能存儲在不同節點上的賬戶間進行轉賬操作:

try (Transaction tx = Ignition.ignite().transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
    Account acctA = accounts.get(acctAid);
    
    Account acctB = accounts.get(acctBid);
    
    // Withdraw from accountB.
    acctB.update(amount);
    
    // Deposit into accountA.
    acctA.update(amount);

    // Store updated accounts in the cluster.
    accounts.put(acctAid, acctA);
    accounts.put(acctBid, acctB);

    tx.commit();
}

就是這些,Ignite的ACID事務基於2階段提交(2PC)的高級版,即使故障,也能保證數據的一致性,參考這個系列文章,可以學習Ignite事務子系統實現的更多細節。

總結

Ignite證明了分佈式的ACID事務和強一致是可行的,並且被可以水平擴展和高可用的現代數據庫廣泛採用,它完全可以根據需要進行配置。看一下有多少金融機構信任Ignite,將其部署進核心應用,你就知道ASF的項目不是徒有虛名。

本文譯自Denis Magda的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章