中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Apache Ignite 事務(wù)架構(gòu):并發(fā)模型和隔離級(jí)別

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬Linux鏡像隨意使用

在本系列的第一篇文章中,我們研究了2階段提交協(xié)議,以及Ignite如何處理各種類型的集群節(jié)點(diǎn),下面是在剩下的文章中要覆蓋的主題:

  • 并發(fā)模型和隔離級(jí)別
  • 故障轉(zhuǎn)移和恢復(fù)
  • Ignite持久化層中的事務(wù)處理(WAL、檢查點(diǎn)及其他);
  • 第三方持久化中的事務(wù)處理

在本文中,我們會(huì)聚焦并發(fā)模型和隔離級(jí)別。 大多數(shù)現(xiàn)代多用戶應(yīng)用允許并發(fā)數(shù)據(jù)訪問和修改。為了管理此功能,并確保系統(tǒng)從一個(gè)一致狀態(tài)切換到另一個(gè)一致狀態(tài),使用了事務(wù)的概念。事務(wù)依賴于鎖,它可以在事務(wù)開始時(shí)(悲觀鎖)獲得,也可以在事務(wù)結(jié)束提交之前(樂觀鎖)獲得。 Ignite支持兩種并發(fā)模型: 悲觀 和 樂觀 ,下面先講悲觀并發(fā)模型。

悲觀并發(fā)模型

悲觀并發(fā)模型的一個(gè)例子是兩個(gè)銀行賬戶之間的轉(zhuǎn)賬,需要確保兩個(gè)銀行賬戶的借貸狀態(tài)正確記錄。這時(shí)需要給兩個(gè)賬戶加鎖來確保更新全部完成并且余額正確。 在悲觀并發(fā)模型中,應(yīng)用需要在事務(wù)開始時(shí)鎖定即將要讀、寫或者修改的所有數(shù)據(jù)。Ignite還支持一組悲觀并發(fā)模型的 隔離級(jí)別 ,在讀寫數(shù)據(jù)時(shí)提供了靈活性:

  • 讀提交
  • 可重復(fù)讀
  • 序列化

在讀提交模型中,鎖是在寫操作對(duì)數(shù)據(jù)進(jìn)行任何改變之前獲得的,比如 put() 或者 putAll() ,而可重復(fù)讀以及序列化模型用于讀寫操作都需要獲得鎖的場(chǎng)景。Ignite還有些內(nèi)置的功能,使得調(diào)試和解決分布式死鎖問題更容易。 下面的代碼示例展示了可重復(fù)讀的悲觀事務(wù),因?yàn)閼?yīng)用需要對(duì)一個(gè)特定銀行賬戶進(jìn)行讀和寫的操作:

try (Transaction tx = Ignition.ignite().transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
    Account acct = cache.get(acctId);

    assert acct != null;

    ...

    // Deposit into account.
    acct.update(amount);

    // Store updated account in cache.
    cache.put(acctId, acct);

    tx.commit();
}

本例中,通過**txStart() tx.commit() 方法分別來進(jìn)行事務(wù)的開啟和提交。 txStart() 方法傳遞了PESSIMISTIC和REPEATABLE READ參數(shù),在try塊體中,代碼在 acctId 鍵上執(zhí)行了一個(gè) cache.get() 操作,之后,一些資金存入賬戶并且緩存使用 cache.put()**進(jìn)行了更新。 下面的代碼示例展示了讀提交并且?guī)в兴梨i處理的悲觀事務(wù):

try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.PESSIMISTIC, TransactionIsolation.READ_COMMITTED, TX_TIMEOUT, 0)) {

    // More code here.

    tx.commit();
} catch (CacheException e) {
    if (e.getCause() instanceof TransactionTimeoutException &&
        e.getCause().getCause() instanceof TransactionDeadlockException)

        System.out.println(e.getCause().getCause().getMessage());
}

本例中,代碼展示了如何使用Ignite的 死鎖檢測(cè)機(jī)制 ,這簡(jiǎn)化了可能由應(yīng)用代碼導(dǎo)致的分布式死鎖的調(diào)試。要開啟這個(gè)特性,需要開啟一個(gè)超時(shí)時(shí)間非0的Ignite事務(wù)(TX_TIMEOUT > 0),還需要捕獲包含死鎖詳細(xì)信息的TransactionDeadlockException。 下面再看一下不同隔離級(jí)別的消息流,對(duì)于讀提交,如圖1所示,在這個(gè)隔離模型中,Ignite對(duì)于讀操作不會(huì)獲得鎖,比如 get() 或者 getAll() ,這對(duì)很多場(chǎng)景可能更適合。

  1. 事務(wù)開始( 1 tx.Start );
  2. 事務(wù)協(xié)調(diào)器在內(nèi)部管理事務(wù)請(qǐng)求( 2 IgniteInternalTx );
  3. 應(yīng)用寫入鍵K1和K2( 3 tx.putAll(K1-V1, K2-V2) );
  4. 事務(wù)協(xié)調(diào)器將K1寫入本地事務(wù)映射( 4 Put(K1) );
  5. 事務(wù)協(xié)調(diào)器向存儲(chǔ)K1的主節(jié)點(diǎn)發(fā)起一個(gè)鎖請(qǐng)求( 5 lock(K1) );
  6. 主節(jié)點(diǎn)在內(nèi)部管理事務(wù)請(qǐng)求( 6 IgniteInternalTx );
  7. 主節(jié)點(diǎn)向事務(wù)協(xié)調(diào)者發(fā)送一個(gè)已經(jīng)準(zhǔn)備好的確認(rèn)( 7 ACK );
  8. 對(duì)于K2重復(fù)如圖1的4-7步驟;
  9. 發(fā)起事務(wù)提交請(qǐng)求( 12 tx.commit );
  10. K1和K2寫入相應(yīng)的主節(jié)點(diǎn)( 13 Write(K1)和13 Write(K2) );
  11. 主節(jié)點(diǎn)確認(rèn)事務(wù)提交( 14 ACK );

下一步,看一下可重復(fù)讀和序列化的消息流,如圖2所示:

  1. 事務(wù)開始( 1 tx.Start );
  2. 事務(wù)協(xié)調(diào)器在內(nèi)部管理事務(wù)請(qǐng)求( 2 IgniteInternalTx );
  3. 應(yīng)用讀取鍵K1和K2( 3 tx.getAll(K1-V1, K2-V2) );
  4. 事務(wù)協(xié)調(diào)器開始鍵K1的讀請(qǐng)求處理( 4 Get(K1) );
  5. 事務(wù)協(xié)調(diào)器向存儲(chǔ)K1的主節(jié)點(diǎn)發(fā)起一個(gè)鎖請(qǐng)求( 5 lock(K1) );
  6. 主節(jié)點(diǎn)在內(nèi)部管理事務(wù)請(qǐng)求( 6 IgniteInternalTx );
  7. 主節(jié)點(diǎn)向事務(wù)協(xié)調(diào)者發(fā)送一個(gè)已經(jīng)準(zhǔn)備好的確認(rèn)( 7 ACK )并且返回K1的值;
  8. 對(duì)于K2重復(fù)如圖2的4-7步驟;
  9. 應(yīng)用寫入K1和K2( 12 tx.putAll(K1-V2, K2-V2) );
  10. 事務(wù)協(xié)調(diào)器將K1的更新寫入本地事務(wù)映射( 13 Put(K1) );
  11. 事務(wù)協(xié)調(diào)器將K2的更新寫入本地事務(wù)映射( 14 Put(K2) );
  12. 發(fā)起事務(wù)提交請(qǐng)求( 15 tx.commit );
  13. K1和K2寫入相應(yīng)的主節(jié)點(diǎn)( 16 Write(K1)和16 Write(K2) );
  14. 主節(jié)點(diǎn)確認(rèn)事務(wù)提交( 17 ACK );

總結(jié)一下,在悲觀模型中,在事務(wù)完成之前鎖一直持有,并且鎖會(huì)阻止其他事務(wù)對(duì)數(shù)據(jù)的訪問。 下一步看一下樂觀并發(fā)模型。

樂觀并發(fā)模型

樂觀并發(fā)模型的一個(gè)例子是計(jì)算機(jī)輔助設(shè)計(jì)(CAD),這里一個(gè)設(shè)計(jì)師工作于整個(gè)設(shè)計(jì)的一部分,通常會(huì)將設(shè)計(jì)從中央倉庫中檢出到本地工作區(qū),然后進(jìn)行部分更新之后將成果檢入中央倉庫,因?yàn)樵O(shè)計(jì)師只負(fù)責(zé)整個(gè)設(shè)計(jì)的一部分,所以不可能與其他部分的更新產(chǎn)生沖突。 與悲觀并發(fā)模型相反,樂觀并發(fā)模型延遲了鎖的獲取,這樣更適合于資源爭(zhēng)用較少的應(yīng)用,比如上面描述的CAD的例子。Ignite還支持一些樂觀并發(fā)模型的 隔離級(jí)別 ,這提供了讀寫數(shù)據(jù)方面的靈活性:

  • 讀提交
  • 可重復(fù)讀
  • 序列化( 無死鎖 )

回顧一下前文中關(guān)于2階段提交中各個(gè)階段的討論,當(dāng)使用樂觀并發(fā)模型時(shí),在準(zhǔn)備階段,鎖是在主節(jié)點(diǎn)獲取的。在使用序列化模式時(shí),如果通過事務(wù)請(qǐng)求的數(shù)據(jù)已經(jīng)改變,在準(zhǔn)備階段事務(wù)會(huì)失敗。這時(shí),開發(fā)者需要編程控制應(yīng)用的行為,即是否需要重啟事務(wù)。而其他的兩個(gè)模式,可重復(fù)讀和讀提交,不會(huì)檢查數(shù)據(jù)是否改變。雖然這會(huì)帶來性能方面的好處,但是沒有了數(shù)據(jù)的原子性保證,因此,這兩個(gè)模式在生產(chǎn)中很少用到。 下面的代碼示例展示了序列化的樂觀事務(wù),因?yàn)閼?yīng)用需要對(duì)一個(gè)特定銀行賬戶進(jìn)行讀和寫的操作:

while (true) {
    try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.OPTIMISTIC, TransactionIsolation.SERIALIZABLE)) {

        Account acct = cache.get(acctId);

        assert acct != null;

        ...

        // Deposit into account.
        acct.update(amount);

        // Store updated account in cache.
        cache.put(acctId, acct);

        tx.commit();

        // Transaction succeeded. Exiting the loop.
        break;
    } catch (TransactionOptimisticException e) {
        // Transaction has failed. Retry.
    }
}

本例中,在外側(cè)有個(gè)while循環(huán),判斷事務(wù)是否失敗,它可以重試。下一步,有**txStart() tx.commit()**方法,分別用于事務(wù)的開始和提交。**txStart() 方法傳遞了OPTIMISTIC和SERIALIZABLE參數(shù),在try塊體中,代碼先在acctId鍵上執(zhí)行了 cache.get() 操作,之后,一些資金存入賬戶并且緩存使用 cache.put()**進(jìn)行了更新。如果事務(wù)成功,代碼會(huì)從循環(huán)中中斷,如果事務(wù)不成功,會(huì)拋出異常然后事務(wù)重試。對(duì)于樂觀的序列化事務(wù),訪問鍵的順序不受限制,因?yàn)镮gnite為了 避免死鎖 ,事務(wù)鎖是通過一個(gè)額外的檢查并行地獲得的。 下面看一下不同隔離級(jí)別下的消息流,先從序列化開始,如圖3所示:

  1. 事務(wù)開始( 1 tx.Start );
  2. 事務(wù)協(xié)調(diào)器在內(nèi)部管理事務(wù)請(qǐng)求( 2 IgniteInternalTx );
  3. 應(yīng)用寫入鍵K1( 3 tx.put(K1-V1) );
  4. 事務(wù)協(xié)調(diào)器將K1寫入本地事務(wù)映射( 4 Put(K1) );
  5. 應(yīng)用寫入鍵K2( 5 tx.put(K2-V2) );
  6. 事務(wù)協(xié)調(diào)器將K2寫入本地事務(wù)映射( 6 Put(K2) );
  7. 發(fā)起事務(wù)提交請(qǐng)求( 7 tx.commit );
  8. 事務(wù)協(xié)調(diào)器向存儲(chǔ)K1和K2的主節(jié)點(diǎn)發(fā)起鎖請(qǐng)求( 8 lock(K1, TV1) and 8 lock(K2, TV1) );
  9. 主節(jié)點(diǎn)在內(nèi)部管理事務(wù)請(qǐng)求( 9 IgniteInternalTx );
  10. 主節(jié)點(diǎn)向事務(wù)協(xié)調(diào)者發(fā)送一個(gè)已經(jīng)準(zhǔn)備好的確認(rèn)( 10 ACK );
  11. K1和K2寫入相應(yīng)的主節(jié)點(diǎn)( 11 Write(K1)和11 Write(K2) );
  12. 如果沒有數(shù)據(jù)沖突(即K1和K2沒有被其他的應(yīng)用更新),主節(jié)點(diǎn)確認(rèn)事務(wù)提交( 12 ACK )。

最后,看一下可重復(fù)讀和讀提交的消息流,如圖4所示:

  1. 事務(wù)開始( 1 tx.Start );
  2. 事務(wù)協(xié)調(diào)器在內(nèi)部管理事務(wù)請(qǐng)求( 2 IgniteInternalTx );
  3. 應(yīng)用寫入鍵K1( 3 tx.put(K1-V1) );
  4. 事務(wù)協(xié)調(diào)器將K1寫入本地事務(wù)映射( 4 Put(K1) );
  5. 應(yīng)用寫入鍵K2( 5 tx.put(K2-V2) );
  6. 事務(wù)協(xié)調(diào)器將K2寫入本地事務(wù)映射( 6 Put(K2) );
  7. 發(fā)起事務(wù)提交請(qǐng)求( 7 tx.commit );
  8. 事務(wù)協(xié)調(diào)器向存儲(chǔ)K1和K2的主節(jié)點(diǎn)發(fā)起鎖請(qǐng)求( 8 lock(K1, TV1) and 8 lock(K2, TV1) );
  9. 主節(jié)點(diǎn)向事務(wù)協(xié)調(diào)者發(fā)送一個(gè)已經(jīng)準(zhǔn)備好的確認(rèn)( 9 ACK );
  10. K1和K2寫入相應(yīng)的主節(jié)點(diǎn)( 10 Write(K1)和10 Write(K2) );
  11. 主節(jié)點(diǎn)在內(nèi)部管理事務(wù)請(qǐng)求( 11 IgniteInternalTx );
  12. 主節(jié)點(diǎn)確認(rèn)事務(wù)提交( 12 ACK )。

總結(jié)

在本文中,研究了Ignite支持的主要的鎖模型和隔離級(jí)別,我們看到,有很大的靈活性和選擇空間,本系列的后面文章中,會(huì)研究故障轉(zhuǎn)移和恢復(fù)。

本文譯自GridGain技術(shù)布道師Akmal B. Chaudhri的 博客 。

 

來自:https://my.oschina.net/liyuj/blog/1627248

 

標(biāo)簽: 代碼 開發(fā)者

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:如何將Git倉庫托管到GitHbub上的詳細(xì)操作指南

下一篇:新思路設(shè)計(jì)可視化大型微服務(wù)監(jiān)控系統(tǒng)