舉個例子,好比是電商場景下,假設說,咱們有個程序,工做的流程是這樣子的:緩存
咱們好比我們的程序就是多線程的,因此可能有多個線程併發的去執行上述的3步驟流程多線程
有一個牙膏,庫存100件,如今,同時有兩我的都過來讀取了牙育的數據,而後下單購買了這管牙膏,此時兩個線程併發的服務於兩我的,同時在進行商品庫存數據的修改併發
總有一個線程是先到的,假設就是線程A ,此時線程A就會先將牙育的庫存設置爲99件,而後線程B再次將牙育的庫存設置爲99件,此時結果就已經錯了異步
正確的狀況下,咱們指望的,應該是說,線程A將庫存-1,設置爲99件;而後線程B接着這個99件,將庫存-1,變爲98件,而後設置到ES中。最終ES中應該庫存是98件纔對啊.spa
普通的ES操做流程:線程
上面說的這個流程和過程,其實就是ES中的併發衝突問題,會致使數據不許確:版本控制
優缺點:code
悲觀鎖併發控制方案,就是在各類狀況下,都上鎖。上鎖以後,就只有一個線程能夠操做這一條數據了,固然,不一樣的場景下,上的敏不一樣,行級鎖,表級鎖,讀鎖,寫鎖。blog
樂觀鎖是不加鎖的, ,每一個線程均可以任意操做內存
線程B去判斷,當前數據的版本號,version=1,與es中的數據的版本號, version=2,是否相同?明顯是不一樣的。版本號不一樣,說明數據已經被其餘人修改過了。此時用戶B不會用99去更新。而是從新去es中讀取最新的數據版本,99件,再次減 1,變爲98件,再執行上述流程,就能夠寫入
示例數據:
PUT /test_index/test_type/6 { "test_field": "test test" }
{ "_index": "test_index", "_type": "test_type", "_id": "6", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true }
第一次建立一個document的時候,它的_version內部版本號就是1;之後,每次對這個document執行修改或者刪除操做,都會對這個_version版本號自動加1;哪怕是刪除,也會對這條數據的版本號加1
{ "found": true, "_index": "test_index", "_type": "test_type", "_id": "6", "_version": 4, "result": "deleted", "_shards": { "total": 2, "successful": 1, "failed": 0 } }
咱們會發現,在刪除一個document以後,能夠從一個側面證實,它不是當即物理刪除掉的,由於它的一些版本號等信息仍是保留着的。先刪除一條document,再從新建立這條document,其實會在delete version基礎之上,再把version號加1
ES後臺同步:知識點: es的後臺,不少的這種相似於replica同步請求,都是多線程異步的,也就是說,多個修改請求之間,是亂序的,沒有順序的,可能後修改的先到,先修改的後到
假設es內部沒有樂觀鎖併發控制機制:
es內部的多線程異步併發修改時,是基於本身的_version版本號進行,在後修改先到時,那麼field-test3, version=2,先修改後到時,先修改的field=test2 , version-1 ,此時會比較一下version號,是否相等,若是不相等的話,那麼就直接將 field-test2這條數據給扔掉,就不須要了,這樣的話,結果就會保持爲一個正確的狀態, field-test3