日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

python乐观锁代码实现_Elasticsearch系列—并发控制及乐观锁实现原理

發(fā)布時(shí)間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python乐观锁代码实现_Elasticsearch系列—并发控制及乐观锁实现原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概要

本篇主要介紹一下Elasticsearch的并發(fā)控制和樂觀鎖的實(shí)現(xiàn)原理,列舉常見的電商場(chǎng)景,關(guān)系型數(shù)據(jù)庫的并發(fā)控制、ES的并發(fā)控制實(shí)踐。

并發(fā)場(chǎng)景

不論是關(guān)系型數(shù)據(jù)庫的應(yīng)用,還是使用Elasticsearch做搜索加速的場(chǎng)景,只要有數(shù)據(jù)更新,并發(fā)控制是永恒的話題。

當(dāng)我們使用ES更新document的時(shí)候,先讀取原始文檔,做修改,然后把document重新索引,如果有多人同時(shí)在做相同的操作,不做并發(fā)控制的話,就極有可能會(huì)發(fā)生修改丟失的。可能有些場(chǎng)景,丟失一兩條數(shù)據(jù)不要緊(比如文章閱讀數(shù)量統(tǒng)計(jì),評(píng)論數(shù)量統(tǒng)計(jì)),但有些場(chǎng)景對(duì)數(shù)據(jù)嚴(yán)謹(jǐn)性要求極高,丟失一條可能會(huì)導(dǎo)致很嚴(yán)重的生產(chǎn)問題,比如電商系統(tǒng)中商品的庫存數(shù)量,丟失一次更新,可能會(huì)導(dǎo)致超賣的現(xiàn)象。

我們還是以電商系統(tǒng)的下單環(huán)節(jié)舉例,某商品庫存100個(gè),兩個(gè)用戶下單購買,都包含這件商品,常規(guī)下單扣庫存的實(shí)現(xiàn)步驟 客戶端完成訂單數(shù)據(jù)校驗(yàn),準(zhǔn)備執(zhí)行下單事務(wù)。

客戶端從ES中獲取商品的庫存數(shù)量。

客戶端提交訂單事務(wù),并將庫存數(shù)量扣減。

客戶端將更新后的庫存數(shù)量寫回到ES。

示例流程圖如下:

如果沒有并發(fā)控制,這件商品的庫存就會(huì)更新成99(實(shí)際正確的值是98),這樣就會(huì)導(dǎo)致超賣現(xiàn)象。假定http-1比http-2先一步執(zhí)行,出現(xiàn)這個(gè)問題的原因是http-2在獲取庫存數(shù)據(jù)時(shí),http-1還未完成下單扣減庫存后,更新到ES的環(huán)節(jié),導(dǎo)致http-2獲取的數(shù)據(jù)已經(jīng)是過期數(shù)據(jù),后續(xù)的更新肯定也是錯(cuò)的。

上述的場(chǎng)景,如果更新操作越是頻繁,并發(fā)數(shù)越多,讀取到更新這一段的耗時(shí)越長,數(shù)據(jù)出錯(cuò)的概率就越大。

常用的鎖方案

并發(fā)控制尤為重要,有兩種通用的方案可以確保數(shù)據(jù)在并發(fā)更新時(shí)的正確性。

悲觀并發(fā)控制

悲觀鎖的含義:我認(rèn)為每次更新都有沖突的可能,并發(fā)更新這種操作特別不靠譜,我只相信只有嚴(yán)格按我定義的粒度進(jìn)行串行更新,才是最安全的,一個(gè)線程更新時(shí),其他的線程等著,前一個(gè)線程更新完成后,下一個(gè)線程再上。

關(guān)系型數(shù)據(jù)庫中廣泛使用該方案,常見的表鎖、行鎖、讀鎖、寫鎖,依賴redis或memcache等實(shí)現(xiàn)的分布式鎖,都屬于悲觀鎖的范疇。明顯的特征是后續(xù)的線程會(huì)被掛起等待,性能一般來說比較低,不過自行實(shí)現(xiàn)的分布式鎖,粒度可以自行控制(按行記錄、按客戶、按業(yè)務(wù)類型等),在數(shù)據(jù)正確性與并發(fā)性能方面也能找到很好的折衷點(diǎn)。

樂觀并發(fā)控制

樂觀鎖的含義:我認(rèn)為沖突不經(jīng)常發(fā)生,我想提高并發(fā)的性能,如果真有沖突,被沖突的線程重新再嘗試幾次就好了。

在使用關(guān)系型數(shù)據(jù)庫的應(yīng)用,也經(jīng)常會(huì)自行實(shí)現(xiàn)樂觀鎖的方案,有性能優(yōu)勢(shì),方案實(shí)現(xiàn)也不難,還是挺吸引人的。

Elasticsearch默認(rèn)使用的是樂觀鎖方案,前面介紹的_version字段,記錄的就是每次更新的版本號(hào),只有拿到最新版本號(hào)的更新操作,才能更新成功,其他拿到過期數(shù)據(jù)的更新失敗,由客戶端程序決定失敗后的處理方案,一般是重試。

ES的樂觀鎖方案

我們還是以上面的案例為背景,若http-2向ES提交更新數(shù)據(jù)時(shí),ES會(huì)判斷提交過來的版本號(hào)與當(dāng)前document版本號(hào),document版本號(hào)單調(diào)遞增,如果提交過來的版本號(hào)比document版本號(hào)小,則說明是過期數(shù)據(jù),更新請(qǐng)求將提示錯(cuò)誤,過程圖如下:

使用內(nèi)置_version實(shí)戰(zhàn)樂觀鎖控制效果

我們?cè)趉ibana平臺(tái)上模擬兩個(gè)線程修改同一條document數(shù)據(jù),打開兩個(gè)瀏覽器標(biāo)簽即可,我們使用原有的案例數(shù)據(jù):{

"_index": "music",

"_type": "children",

"_id": "2",

"_version": 2,

"found": true,

"_source": {

"name": "wake me, shark me",

"content": "don't let me sleep too late, gonna get up brightly early in the morning",

"language": "english",

"length": "55"

}

}

當(dāng)前的version是2,我們使用一個(gè)瀏覽器標(biāo)簽頁,發(fā)出更新請(qǐng)求,把當(dāng)前的version帶上:POST /music/children/2?version=2

{

"doc": {

"length": 56

}

}

此時(shí)更新成功{

"_index": "music",

"_type": "children",

"_id": "2",

"_version": 3,

"result": "updated",

"_shards": {

"total": 2,

"successful": 1,

"failed": 0

},

"_seq_no": 2,

"_primary_term": 2

}

同時(shí)我們?cè)诹硪粋€(gè)標(biāo)簽頁上,也使用version=2進(jìn)行更新,得到的錯(cuò)誤結(jié)果如下:{

"error": {

"root_cause": [

{

"type": "version_conflict_engine_exception",

"reason": "[children][2]: version conflict, current version [3] is different than the one provided [2]",

"index_uuid": "9759yb44TFuJSejo6boy4A",

"shard": "2",

"index": "music"

}

],

"type": "version_conflict_engine_exception",

"reason": "[children][2]: version conflict, current version [3] is different than the one provided [2]",

"index_uuid": "9759yb44TFuJSejo6boy4A",

"shard": "2",

"index": "music"

},

"status": 409

}

關(guān)鍵錯(cuò)誤信息:versionconflictengine_exception,版本沖突,將version升到3,模擬失敗后重試,此時(shí)更新成功。

真實(shí)的場(chǎng)景,重試的次數(shù)跟線程并發(fā)數(shù)有關(guān),線程越多,更新越頻繁,就可能需要重試多次才可能更新成功。

使用外部_version實(shí)戰(zhàn)樂觀鎖控制效果

ES允許不使用內(nèi)置的version進(jìn)行版本控制,可以自定義使用外部的version,例如常見的使用Elasticsearch做數(shù)據(jù)查詢加速的經(jīng)典方案,關(guān)系型數(shù)據(jù)庫作為主數(shù)據(jù)庫,然后使用Elasticsearch做搜索數(shù)據(jù),主數(shù)據(jù)會(huì)同步數(shù)據(jù)到Elasticsearch中,而主數(shù)據(jù)庫并發(fā)控制,本身就是使用的樂觀鎖機(jī)制,有自己的一套version生成機(jī)制,數(shù)據(jù)同步到ES那里時(shí),直接使用更方便。

請(qǐng)求語法上加上version_type參數(shù)即可:POST /music/children/2?version=2&version_type=external

{

"doc": {

"length": 56

}

}

唯一的區(qū)別內(nèi)置version,只有當(dāng)你提供的version與es中的version完全一樣的時(shí)候,才可以進(jìn)行更新,否則報(bào)錯(cuò);

外部version,只有當(dāng)你提供的version比es中的version大的時(shí)候,才能完成修改。

Replica Shard數(shù)據(jù)同步并發(fā)控制

在Elasticsearch內(nèi)部,每當(dāng)primary shard收到新的數(shù)據(jù)時(shí),都需要向replica shard進(jìn)行數(shù)據(jù)同步,這種同步請(qǐng)求特別多,并且是異步的。如果同一個(gè)document進(jìn)行了多次修改,Shard同步的請(qǐng)求是無序的,可能會(huì)出現(xiàn)”后發(fā)先至”的情況,如果沒有任何的并發(fā)控制機(jī)制,那結(jié)果將無法相像。

Shard的數(shù)據(jù)同步也是基于內(nèi)置的_version進(jìn)行樂觀鎖并發(fā)控制的。

例如Java客戶端向Elasticsearch某條document發(fā)起更新請(qǐng)求,共發(fā)出3次,Java端有嚴(yán)謹(jǐn)?shù)牟l(fā)請(qǐng)求控制,在ElasticSearch的primary shard中寫入的結(jié)果是正確的,但Elasticsearch內(nèi)部數(shù)據(jù)啟動(dòng)同步時(shí),順序不能保證都是先到先得,情況可能是這樣,第三次更新請(qǐng)求比第二次更新請(qǐng)求先到,如下圖:

如果Elasticsearch內(nèi)部沒有并發(fā)的控制,這個(gè)document在replica的結(jié)果可能是text2,并且與primary shard的值不一致,這樣肯定錯(cuò)了。

預(yù)期的更新順序應(yīng)該是text1–>text2–>text3,最終的正確結(jié)果是text3。那Elasticsearch內(nèi)部是如何做的呢?

Elasticsearch內(nèi)部在更新document時(shí),會(huì)比較一下version,如果請(qǐng)求的version與document的version相等,就做更新,如果document的version已經(jīng)大于請(qǐng)求的version,說明此數(shù)據(jù)已經(jīng)被后到的線程更新過了,此時(shí)會(huì)丟棄當(dāng)前的請(qǐng)求,最終的結(jié)果為text3。此時(shí)的更新順序?yàn)閠ext1–>text3,最終結(jié)果也是對(duì)的。

小結(jié)

本篇主要介紹并發(fā)場(chǎng)景出現(xiàn)數(shù)據(jù)錯(cuò)亂的原因,Elasticsearch樂觀鎖的實(shí)原理,以及ES內(nèi)部數(shù)據(jù)同步時(shí)的并發(fā)控制,有不正確之處或未詳盡之處請(qǐng)知會(huì)修改,謝謝。

專注Java高并發(fā)、分布式架構(gòu),更多技術(shù)干貨分享與心得,請(qǐng)關(guān)注公眾號(hào):Java架構(gòu)社區(qū)

https://juejin.im/post/5de8437d6fb9a0166316c02e

總結(jié)

以上是生活随笔為你收集整理的python乐观锁代码实现_Elasticsearch系列—并发控制及乐观锁实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。