使用Apache Ignite實現無死鎖事務
死鎖會殺死服務,我們看看Apache Ignite透過分配數字到事務是如何實現無死鎖的事務的。
在多使用者環境中,對於快取記憶體中同一條資料或物件進行併發事務操作時會引發死鎖,這是效能殺手,一旦系統進入嚴重的死鎖狀態,恢復需要整個叢集重新啟動,而Apache Ignite能夠支援相容ACID的無死鎖事務,防止死鎖和增強應用效能。
什麼是死鎖?
有兩個併發事務T1和T2,T1等待資源R2釋放,因為R2正在被事務T2鎖住,而T2正在等待資源R1釋放,而R1正在被事務T1鎖住,彼此互相等待對方釋放自己需要操作的資源,永遠等下去了。
死鎖是因為併發事務檢視以不同順序從同一物件上獲得鎖,解決辦法是使用同樣順序獲得鎖,但是這種方法不靈活,不可控的。
Apache Ignite執行事務是使用併發模式 OPTIMISTIC和隔離級別SERIALIZABLE,鎖是在提交事務commit期間獲得,同時使用附加檢查,這樣能避免死鎖,能提高吞吐量,甚至,在提交期間,如果Ignite探測到一個讀寫衝突或多個事務之間的鎖衝突,只有一個事務被允許提交commit,所有其他衝突的事務將回滾且拋錯。
那麼其工作原理是什麼?
Ignite會分配一個版本數字到每個事務和快取中被操作的專案,版本數字會幫助決定一個事務將被提交或回滾,遭遇下面情況,Ignite會失敗一個OPTIMISTIC(樂觀) SERIALIZABLE(序列化) 事務(T2),並拋錯TransactionOptimisticException :
1.如果存在正在進行的一個悲觀事務,或者是樂觀事務,但是帶有隔離級別是READ-COMMITTED or REPEATABLE-READ,這個事務稱為T1,它正在鎖住快取中一個專案,而該專案被T2請求,那麼T2拋錯。
2.存在另外一個正在進行的樂觀序列化事務T1,它的版本號大於T2,而T2正在鎖住快取中專案將被T2請求加鎖,那麼T2將拋錯。
3.當T2獲得所有需要的鎖,快取中存在一個專案帶有當前版本號不同於被觀察版本號,這是因為另外一個事務T1已經提交了,改變了快取專案的版本。
程式碼案例:
該案例輸出T2回滾拋錯Exception,因為事務T2和T1有鎖衝突。
在一個高併發環境中,樂觀鎖會導致更頻繁的事務失敗,但是相比悲觀鎖導致死鎖更可能發生還是有利的,Optimistic-Serializable (樂觀-序列化)事務在Ignite中明顯快於悲觀事務,能夠提供高效能,Ignite事務是一種ACID相容機制,確保叢集中資料一直一致,也就是高一致性。
在多使用者環境中,對於快取記憶體中同一條資料或物件進行併發事務操作時會引發死鎖,這是效能殺手,一旦系統進入嚴重的死鎖狀態,恢復需要整個叢集重新啟動,而Apache Ignite能夠支援相容ACID的無死鎖事務,防止死鎖和增強應用效能。
什麼是死鎖?
有兩個併發事務T1和T2,T1等待資源R2釋放,因為R2正在被事務T2鎖住,而T2正在等待資源R1釋放,而R1正在被事務T1鎖住,彼此互相等待對方釋放自己需要操作的資源,永遠等下去了。
死鎖是因為併發事務檢視以不同順序從同一物件上獲得鎖,解決辦法是使用同樣順序獲得鎖,但是這種方法不靈活,不可控的。
Apache Ignite執行事務是使用併發模式 OPTIMISTIC和隔離級別SERIALIZABLE,鎖是在提交事務commit期間獲得,同時使用附加檢查,這樣能避免死鎖,能提高吞吐量,甚至,在提交期間,如果Ignite探測到一個讀寫衝突或多個事務之間的鎖衝突,只有一個事務被允許提交commit,所有其他衝突的事務將回滾且拋錯。
那麼其工作原理是什麼?
Ignite會分配一個版本數字到每個事務和快取中被操作的專案,版本數字會幫助決定一個事務將被提交或回滾,遭遇下面情況,Ignite會失敗一個OPTIMISTIC(樂觀) SERIALIZABLE(序列化) 事務(T2),並拋錯TransactionOptimisticException :
1.如果存在正在進行的一個悲觀事務,或者是樂觀事務,但是帶有隔離級別是READ-COMMITTED or REPEATABLE-READ,這個事務稱為T1,它正在鎖住快取中一個專案,而該專案被T2請求,那麼T2拋錯。
2.存在另外一個正在進行的樂觀序列化事務T1,它的版本號大於T2,而T2正在鎖住快取中專案將被T2請求加鎖,那麼T2將拋錯。
3.當T2獲得所有需要的鎖,快取中存在一個專案帶有當前版本號不同於被觀察版本號,這是因為另外一個事務T1已經提交了,改變了快取專案的版本。
程式碼案例:
public class DeadlockExample { private static final String ENTRY1 = "entry1"; private static final String ENTRY2 = "entry2"; public static void main(String[] args) throws IgniteException { Ignite ignite = Ignition.start("/myexamples/config/cluster-config.xml"); // Create cache with given name, if it does not exist. final IgniteCache<String, String> cache = ignite.getOrCreateCache("myCache"); // populate int i = 0; cache.put(ENTRY1, Integer.toString(i++)); cache.put(ENTRY2, Integer.toString(i++)); new Thread(() -> { try (Transaction t1 = Ignition.ignite().transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) { String val1 = cache.get(ENTRY1); cache.put(ENTRY1, val1 + "b"); String val2 = cache.get(ENTRY2); cache.put(ENTRY2, val2 + "b"); t1.commit(); System.out.println("t1: " + cache.get(ENTRY1)); System.out.println("t1: " + cache.get(ENTRY2)); } }, "t1-Thread").start(); new Thread(() -> { try (Transaction t2 = Ignition.ignite().transactions().txStart(OPTIMISTIC, SERIALIZABLE)) { String val2 = cache.get(ENTRY2); cache.put(ENTRY2, val2 + "c"); String val1 = cache.get(ENTRY1); cache.put(ENTRY1, val1 + "c"); t2.commit(); System.out.println("t2: " + cache.get(ENTRY1)); System.out.println("t2: " + cache.get(ENTRY2)); } }, "t2-Thread").start(); } } <p class="indent"> |
該案例輸出T2回滾拋錯Exception,因為事務T2和T1有鎖衝突。
在一個高併發環境中,樂觀鎖會導致更頻繁的事務失敗,但是相比悲觀鎖導致死鎖更可能發生還是有利的,Optimistic-Serializable (樂觀-序列化)事務在Ignite中明顯快於悲觀事務,能夠提供高效能,Ignite事務是一種ACID相容機制,確保叢集中資料一直一致,也就是高一致性。
相關文章
- 線上併發事務死鎖問題排查
- node.js 中使用redis實現分散式事務鎖Node.jsRedis分散式
- Apache ShardingSphere 如何實現分散式事務Apache分散式
- Apache Ignite剖析Apache
- Apache Ignite 學習筆記(6): Ignite中Entry Processor使用Apache筆記
- 事務的本質和死鎖的原理・改
- Apache Ignite 與 Apache Spark比較ApacheSpark
- Java 實現執行緒死鎖Java執行緒
- 初步認識Apache IgniteApache
- 十、Redis事務、事務鎖Redis
- 實現宣告式鎖,支援分散式鎖自定義鎖、SpEL和結合事務分散式
- 死磕Synchronized底層實現–偏向鎖synchronized
- MySQL 死鎖與日誌二三事MySql
- 使用Spring Boot實現事務管理Spring Boot
- golang 中 channel 的詳細使用、使用注意事項及死鎖分析Golang
- 死磕Synchronized底層實現--重量級鎖synchronized
- 面試:什麼是死鎖,如何避免或解決死鎖;MySQL中的死鎖現象,MySQL死鎖如何解決面試MySql
- 使用JOTM實現分散式事務的例子分散式
- 使用Spring Boot實現分散式事務Spring Boot分散式
- ORACLE 死事務的回滾Oracle
- MySQL 事務和鎖MySql
- MySQL事務與鎖MySql
- MySQL事務和鎖MySql
- MyRocks事務鎖分析
- 死磕Synchronized底層實現–輕量級鎖synchronized
- 死磕Synchronized底層實現--輕量級鎖synchronized
- Laravel 事務中 使用 悲觀鎖 小結Laravel
- oracle自治事務引起的死鎖Oracle
- 效能優化-使用雙buffer實現無鎖佇列優化佇列
- C#中使用CAS實現無鎖演算法C#演算法
- [CareerCup] 16.4 A Lock Without Deadlocks 無死鎖的鎖
- MySQL事務實現原理MySql
- Kafka事務實現原理Kafka
- Seata 無侵入式分散式事務服務的實現基石-JDBC篇分散式JDBC
- Oracle的TX鎖(行級鎖、事務鎖)Oracle
- 使用Spring Boot實現Redis事務 | VinsguruSpring BootRedis
- 模擬SQLserver死鎖現象SQLServer
- Java鎖——死鎖Java