新聞中心
這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
mongoDB中的冪等性
最近在學習MongoDB的過程中,接觸到一個新名詞——冪等性。
先來看一下度娘的解釋。
冪等(idempotent、idempotence)是一個數(shù)學與計算機學概念,常見于抽象代數(shù)中。
在編程中,一個冪等操作的特點是其任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同。
冪等函數(shù),或冪等方法,是指可以使用相同參數(shù)重復執(zhí)行,并能獲得相同結果的函數(shù)。這些函數(shù)不會影響系統(tǒng)狀態(tài),也不用擔心重復執(zhí)行會對系統(tǒng)造成改變。例如,“setTrue()”函數(shù)就是一個冪等函數(shù),無論多次執(zhí)行,其結果都是一樣的.更復雜的操作冪等保證是利用唯一交易號(流水號)實現(xiàn)。
看懂了嗎?這個解釋比較抽象,不要著急。接下來看一下什么是冪等性問題。
所謂冪等,簡單地說,就是對接口的多次調(diào)用所產(chǎn)生的結果和調(diào)用一次是一致的。擴展一下,這里的接口,可以理解為對外發(fā)布的HTTP接口或者其他接口,也可以是接收消息的內(nèi)部接口,甚至是一個內(nèi)部方法或操作。
那么我們?yōu)槭裁葱枰涌诰哂袃绲刃阅兀吭O想一下以下情形:
在分布式環(huán)境中,網(wǎng)絡環(huán)境更加復雜,因前端操作抖動、網(wǎng)絡故障、消息重復、響應速度慢等原因,對接口的重復調(diào)用概率會比集中式環(huán)境下更大,尤其是重復消息在分布式環(huán)境中很難避免。
分布式環(huán)境中,有些接口是天然保證冪等性的,如查詢操作。有些對數(shù)據(jù)的修改是一個常量,并且無其他記錄和操作,那也可以說是具有冪等性的。其他情況下,所有涉及對數(shù)據(jù)的修改、狀態(tài)的變更就都有必要防止重復性操作的發(fā)生。通過間接的實現(xiàn)接口的冪等性來防止重復操作所帶來的影響,成為了一種有效的解決方案。
看了上面App的例子好理解多了。那冪等性在并發(fā)系統(tǒng)中如何保證呢?
在系統(tǒng)開發(fā)過程中,經(jīng)常遇到數(shù)據(jù)重復插入、重復更新、消息重發(fā)發(fā)送等等問題,因為應用系統(tǒng)的復雜邏輯以及網(wǎng)絡交互存在的不確定性,會導致這一重復現(xiàn)象,但是有些邏輯是需要有冪等特性的,否則造成的后果會比較嚴重,例如訂單重復創(chuàng)建,這時候帶來的問題可是非同一般啊。
一、系統(tǒng)的冪等性
冪等是數(shù)據(jù)中得一個概念,表示N次變換和1次變換的結果相同。
二、高并發(fā)的系統(tǒng)如何保證冪等性
1、查詢
查詢的API,可以說是天然的冪等性,因為你查詢一次和查詢兩次,對于系統(tǒng)來講,沒有任何數(shù)據(jù)的變更,所以,查詢一次和查詢多次一樣的;
2、MVCC方案
多版本并發(fā)控制,update with condition更新帶條件,這也是在系統(tǒng)設計的時候,合理的選擇樂觀鎖,通過version或者其他條件,來做樂觀鎖,這樣保證更新及時在并發(fā)的情況下,也不會有太大的問題。
例如update table_xxx set name=#name#,version=version+1 where version=#version# ,或者是 update table_xxx set quality=quality-#subQuality# where quality-#subQuality# >= 0
3、單獨的去重表
如果涉及到的去重的地方特別多,例如ERP系統(tǒng)中有各種各樣的業(yè)務單據(jù),每一種業(yè)務單據(jù)都需要去重,這時候,可以單獨搞一張去重表,在插入數(shù)據(jù)的時候,插入去重表,利用數(shù)據(jù)庫的唯一索引特性,保證唯一的邏輯;
4、分布式鎖
還是拿插入數(shù)據(jù)的例子,如果是分布是系統(tǒng),構建唯一索引比較困難,例如唯一性的字段沒法確定,這時候可以引入分布式鎖,通過第三方的系統(tǒng),在業(yè)務系統(tǒng)插入數(shù)據(jù)或者更新數(shù)據(jù),獲取分布式鎖,然后做操作,之后釋放鎖,這樣其實是把多線程并發(fā)的鎖的思路,引入多多個系統(tǒng),也就是分布式系統(tǒng)中得解決思路;
5、刪除數(shù)據(jù)
刪除數(shù)據(jù),僅僅第一次刪除是真正的操作數(shù)據(jù),第二次甚至第三次刪除,直接返回成功,這樣保證了冪等;
6、插入數(shù)據(jù)的唯一索引
插入數(shù)據(jù)的唯一性,可以通過業(yè)務主鍵來進行約束,例如一個特定的業(yè)務場景,三個字段肯定確定唯一性,那么,可以在數(shù)據(jù)庫表添加唯一索引來進行標示。
這里有一個場景,API層面的冪等,例如提交數(shù)據(jù),如何控制重復提交,這里可以在提交數(shù)據(jù)的form表單或者客戶端軟件,增加一個唯一標示,然后服務端,根據(jù)這個UUID來進行去重,這樣就能比較好的做到API層面的唯一標示
看到這里,你也許對冪等性已經(jīng)有了深入的理解。最后,我們看一下MongoDB中的冪等性。
MongoDB是由C++語言所編寫的一種面向文檔的非關系型數(shù)據(jù)庫(是一種NoSql數(shù)據(jù)庫實現(xiàn)),也是介于關系型數(shù)據(jù)庫和非關系型數(shù)據(jù)庫之間的數(shù)據(jù)存儲產(chǎn)品,其提供了高性能、高可用、高可拓展及基于分布式存儲的數(shù)據(jù)庫,是非關系型數(shù)據(jù)庫中功能最豐富,最類似關系型數(shù)據(jù)庫的一種集合、文檔格式的數(shù)據(jù)庫。
在MongoDB中,文檔的操作不支持事務,但是其對文檔的保存,修改及刪除等都是原子的,也就是要么操作完成,要么操作不完成,不存在中間不確定狀態(tài),因此可以保證數(shù)據(jù)的完整性。
MongoDB官方提供了一種做法,就是分兩階段提交,基本原理就是利用寫操作的冪等性,但是有個前提條件:業(yè)務實現(xiàn)過程中,可以忽略中間態(tài)的不一致性,但最終結果是一致的,實際上絕大多數(shù)需求,只要結果一致就可,也希望MongoDB在這方面做更好的拓展和優(yōu)化。
1、數(shù)據(jù)模型
舉個例子,不過我們需要為文檔新增一個計數(shù)器字段,它沒有實際的業(yè)務作用,只是用來作為操作原子性的標志位avaliable,具體代碼如下:
{
"_id" :ObjectId("57e89964b316d2e13cc0ba9b"),
"username" :"marky@123.com",
"nickname" : "marky",
"address" : "云端路1024號,柯南私募基金大廈",
"contact" :"13141250012",
"created" : "2012-07-07",
"orders" : [
ObjectId("57e89b3ab316d2e13cc0ba9c"),
ObjectId("57e89bcfb316d2e13cc0ba9d")
],
"available": 1
}
注意:
此種添加一個計數(shù)器標志位的方式雖然可以實現(xiàn)原子性,但對于業(yè)務的緊密度及可理解方面不友好,所以實際上,我們只在比較敏感的文檔操作時才使用,比如:金錢交易等。
2、如何操作
如何操作?其實就是使用findAndModify()方法實現(xiàn)即可,如果找到的文檔的計數(shù)器available值不為-1為大于0時,則代表有新的操作狀態(tài),然后在更新新的操作,同時同步修改available為默認值,具體如下:
>db.user.findAndModify({query:{_id:ObjectId("57e89964b316d2e13cc0ba9b"), available:{$gt:0}},update:{$inc:{ available:-1},$set:{created:'2012-07-08'}}})
返回的結果:
{
"_id" : ObjectId("57e89964b316d2e13cc0ba9b"),
"username" :"marky@123.com",
"nickname" : "marky",
"address" : "云端路1024號,柯南私募基金大廈",
"contact" :"13141250012",
"created" :"2012-07-08",
"orders" : [
ObjectId("57e89b3ab316d2e13cc0ba9c"),
ObjectId("57e89bcfb316d2e13cc0ba9d")
],
" available" : 0
}
~~~~~~~ the end~~~~~~~~~
hoegh
2017.04.05
網(wǎng)頁名稱:mongoDB中的冪等性
網(wǎng)站網(wǎng)址:http://ef60e0e.cn/article/gojsod.html
先來看一下度娘的解釋。
冪等
在編程中,一個冪等操作的特點是其任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同。
冪等函數(shù),或冪等方法,是指可以使用相同參數(shù)重復執(zhí)行,并能獲得相同結果的函數(shù)。這些函數(shù)不會影響系統(tǒng)狀態(tài),也不用擔心重復執(zhí)行會對系統(tǒng)造成改變。例如,“setTrue()”函數(shù)就是一個冪等函數(shù),無論多次執(zhí)行,其結果都是一樣的.更復雜的操作冪等保證是利用唯一交易號(流水號)實現(xiàn)。
看懂了嗎?這個解釋比較抽象,不要著急。接下來看一下什么是冪等性問題。
冪等性問題
那么我們?yōu)槭裁葱枰涌诰哂袃绲刃阅兀吭O想一下以下情形:
- 在App中下訂單的時候,點擊確認之后,沒反應,就又點擊了幾次。在這種情況下,如果無法保證該接口的冪等性,那么將會出現(xiàn)重復下單問題。
- 在接收消息的時候,消息推送重復。如果處理消息的接口無法保證冪等,那么重復消費消息產(chǎn)生的影響可能會非常大。
在分布式環(huán)境中,網(wǎng)絡環(huán)境更加復雜,因前端操作抖動、網(wǎng)絡故障、消息重復、響應速度慢等原因,對接口的重復調(diào)用概率會比集中式環(huán)境下更大,尤其是重復消息在分布式環(huán)境中很難避免。
分布式環(huán)境中,有些接口是天然保證冪等性的,如查詢操作。有些對數(shù)據(jù)的修改是一個常量,并且無其他記錄和操作,那也可以說是具有冪等性的。其他情況下,所有涉及對數(shù)據(jù)的修改、狀態(tài)的變更就都有必要防止重復性操作的發(fā)生。通過間接的實現(xiàn)接口的冪等性來防止重復操作所帶來的影響,成為了一種有效的解決方案。
看了上面App的例子好理解多了。那冪等性在并發(fā)系統(tǒng)中如何保證呢?
高并發(fā)系統(tǒng)中如何保證數(shù)據(jù)冪等性
一、系統(tǒng)的冪等性
冪等是數(shù)據(jù)中得一個概念,表示N次變換和1次變換的結果相同。
二、高并發(fā)的系統(tǒng)如何保證冪等性
1、查詢
查詢的API,可以說是天然的冪等性,因為你查詢一次和查詢兩次,對于系統(tǒng)來講,沒有任何數(shù)據(jù)的變更,所以,查詢一次和查詢多次一樣的;
2、MVCC方案
多版本并發(fā)控制,update with condition更新帶條件,這也是在系統(tǒng)設計的時候,合理的選擇樂觀鎖,通過version或者其他條件,來做樂觀鎖,這樣保證更新及時在并發(fā)的情況下,也不會有太大的問題。
例如update table_xxx set name=#name#,version=version+1 where version=#version# ,或者是 update table_xxx set quality=quality-#subQuality# where quality-#subQuality# >= 0
3、單獨的去重表
如果涉及到的去重的地方特別多,例如ERP系統(tǒng)中有各種各樣的業(yè)務單據(jù),每一種業(yè)務單據(jù)都需要去重,這時候,可以單獨搞一張去重表,在插入數(shù)據(jù)的時候,插入去重表,利用數(shù)據(jù)庫的唯一索引特性,保證唯一的邏輯;
4、分布式鎖
還是拿插入數(shù)據(jù)的例子,如果是分布是系統(tǒng),構建唯一索引比較困難,例如唯一性的字段沒法確定,這時候可以引入分布式鎖,通過第三方的系統(tǒng),在業(yè)務系統(tǒng)插入數(shù)據(jù)或者更新數(shù)據(jù),獲取分布式鎖,然后做操作,之后釋放鎖,這樣其實是把多線程并發(fā)的鎖的思路,引入多多個系統(tǒng),也就是分布式系統(tǒng)中得解決思路;
5、刪除數(shù)據(jù)
刪除數(shù)據(jù),僅僅第一次刪除是真正的操作數(shù)據(jù),第二次甚至第三次刪除,直接返回成功,這樣保證了冪等;
6、插入數(shù)據(jù)的唯一索引
插入數(shù)據(jù)的唯一性,可以通過業(yè)務主鍵來進行約束,例如一個特定的業(yè)務場景,三個字段肯定確定唯一性,那么,可以在數(shù)據(jù)庫表添加唯一索引來進行標示。
這里有一個場景,API層面的冪等,例如提交數(shù)據(jù),如何控制重復提交,這里可以在提交數(shù)據(jù)的form表單或者客戶端軟件,增加一個唯一標示,然后服務端,根據(jù)這個UUID來進行去重,這樣就能比較好的做到API層面的唯一標示
看到這里,你也許對冪等性已經(jīng)有了深入的理解。最后,我們看一下MongoDB中的冪等性。
MongoDB中的冪等性
在MongoDB中,文檔的操作不支持事務,但是其對文檔的保存,修改及刪除等都是原子的,也就是要么操作完成,要么操作不完成,不存在中間不確定狀態(tài),因此可以保證數(shù)據(jù)的完整性。
MongoDB官方提供了一種做法,就是分兩階段提交,基本原理就是利用寫操作的冪等性,但是有個前提條件:業(yè)務實現(xiàn)過程中,可以忽略中間態(tài)的不一致性,但最終結果是一致的,實際上絕大多數(shù)需求,只要結果一致就可,也希望MongoDB在這方面做更好的拓展和優(yōu)化。
1、數(shù)據(jù)模型
舉個例子,不過我們需要為文檔新增一個計數(shù)器字段,它沒有實際的業(yè)務作用,只是用來作為操作原子性的標志位avaliable,具體代碼如下:
{
"_id" :ObjectId("57e89964b316d2e13cc0ba9b"),
"username" :"marky@123.com",
"nickname" : "marky",
"address" : "云端路1024號,柯南私募基金大廈",
"contact" :"13141250012",
"created" : "2012-07-07",
"orders" : [
ObjectId("57e89b3ab316d2e13cc0ba9c"),
ObjectId("57e89bcfb316d2e13cc0ba9d")
],
"available": 1
}
注意:
此種添加一個計數(shù)器標志位的方式雖然可以實現(xiàn)原子性,但對于業(yè)務的緊密度及可理解方面不友好,所以實際上,我們只在比較敏感的文檔操作時才使用,比如:金錢交易等。
2、如何操作
如何操作?其實就是使用findAndModify()方法實現(xiàn)即可,如果找到的文檔的計數(shù)器available值不為-1為大于0時,則代表有新的操作狀態(tài),然后在更新新的操作,同時同步修改available為默認值,具體如下:
>db.user.findAndModify({query:{_id:ObjectId("57e89964b316d2e13cc0ba9b"), available:{$gt:0}},update:{$inc:{ available:-1},$set:{created:'2012-07-08'}}})
返回的結果:
{
"_id" : ObjectId("57e89964b316d2e13cc0ba9b"),
"username" :"marky@123.com",
"nickname" : "marky",
"address" : "云端路1024號,柯南私募基金大廈",
"contact" :"13141250012",
"created" :"2012-07-08",
"orders" : [
ObjectId("57e89b3ab316d2e13cc0ba9c"),
ObjectId("57e89bcfb316d2e13cc0ba9d")
],
" available" : 0
}
~~~~~~~ the end~~~~~~~~~
hoegh
2017.04.05
網(wǎng)頁名稱:mongoDB中的冪等性
網(wǎng)站網(wǎng)址:http://ef60e0e.cn/article/gojsod.html