日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

后端风云

發(fā)布時(shí)間:2025/3/21 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 后端风云 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

經(jīng)過(guò)一個(gè)月的折騰,終于分家了。

原來(lái)的訂單模塊,庫(kù)存模塊,積分模塊,支付模塊......搖身一變,成為了一個(gè)個(gè)獨(dú)立系統(tǒng)。

主人給這些獨(dú)立的系統(tǒng)起了一個(gè)時(shí)髦的名字: 微服務(wù)!

有些微服務(wù)是主人的心頭肉,他們“霸占”了一臺(tái)或者多臺(tái)機(jī)器,像我這個(gè)積分模塊,哦不,是積分系統(tǒng),不受人待見(jiàn),只能委屈一下,和另外幾個(gè)家伙共享一臺(tái)機(jī)器了。

主人說(shuō)我們現(xiàn)在是分布式的系統(tǒng)了,大家要齊心協(xié)力,共同完成原來(lái)的任務(wù)。

原來(lái)大伙都居住在一個(gè)JVM中,模塊之間都是直接的函數(shù)調(diào)用,如今每個(gè)人對(duì)外提供的都是基于HTTP的API: 想要訪問(wèn)別人,需要準(zhǔn)備好JSON數(shù)據(jù),然后通過(guò)HTTP發(fā)送給過(guò)去,人家處理以后,再發(fā)送一個(gè)JSON的響應(yīng)。

?

真是麻煩,哪怕一次最簡(jiǎn)單的溝通都要跨越網(wǎng)絡(luò)了。

?

重復(fù)執(zhí)行

提起這網(wǎng)絡(luò)我心里就來(lái)氣, 想想原來(lái)大家都在一個(gè)進(jìn)程中,那調(diào)用速度才叫爽。 現(xiàn)在可好,一是慢如蝸牛,二是不可靠,時(shí)不時(shí)就會(huì)出錯(cuò)。

30毫秒以前,訂單這家伙調(diào)用我的接口,要給一個(gè)叫做U0002的用戶增加200積分,我很樂(lè)意地執(zhí)行了。

POST /xxx/BonusPoint/U0002

{"value:200"}

可是,當(dāng)我想把積分的調(diào)用結(jié)果告訴訂單系統(tǒng)的時(shí)候,發(fā)現(xiàn)網(wǎng)絡(luò)已經(jīng)斷開(kāi),發(fā)送失敗。 怎么辦? 我想反正已經(jīng)執(zhí)行過(guò)了,Forget it !

可是訂單那小子對(duì)我這邊的情況一無(wú)所知,心里琢磨著也許是我這邊出錯(cuò)了, 死心眼的他又發(fā)起了同樣的調(diào)用。

對(duì)我而言,這個(gè)新的調(diào)用和之前的那個(gè)沒(méi)有一毛錢關(guān)系。(不要忘了,HTTP是沒(méi)有狀態(tài)的)我就老老實(shí)實(shí)地再執(zhí)行一遍。

結(jié)果可想而知,用戶"U0002"的積分被無(wú)端地增加了兩次!

訂單小伙說(shuō):“這樣不行啊,你得記住我曾經(jīng)發(fā)起過(guò)調(diào)用,這樣第二次就不用執(zhí)行了!”

“開(kāi)玩笑!HTTP是無(wú)狀態(tài)的, 我怎么可能記錄你曾經(jīng)的調(diào)用?”

“我們可以增加一點(diǎn)兒狀態(tài), 每次調(diào)用,我給你發(fā)一個(gè)Transaction ID, 簡(jiǎn)稱TxID,你處理完以后, 需要把這個(gè)TxID,UserID, ?積分等信息給保存到數(shù)據(jù)庫(kù)中。”

POST /xxx/BonusPoint/U0002

{"txid":"T0001","value":"200"}

我說(shuō):“這有什么用?”

“每次執(zhí)行的時(shí)候,你都可以從數(shù)據(jù)庫(kù)中查一下啊,如果看到同樣的TxID已經(jīng)存在了,那就說(shuō)明之前執(zhí)行過(guò),就不用重復(fù)執(zhí)行了。如果不存在,才真正去執(zhí)行。”

?

這倒是一個(gè)好主意,雖然我增加了一點(diǎn)工作量,需要一點(diǎn)額外的存儲(chǔ)空間(正好借此機(jī)會(huì)要一個(gè)好點(diǎn)兒的服務(wù)器!),但是卻有一個(gè)很好的特性:?對(duì)于同一個(gè)TxID,無(wú)論調(diào)用多少次,那執(zhí)行效果就如同執(zhí)行了一次,肯定不會(huì)出錯(cuò)。

后來(lái)我們才知道,人類把這個(gè)特性叫做冪等性

一般來(lái)說(shuō),在后端數(shù)據(jù)不變的情況下,讀操作都是冪等的,不管讀取多少次,得到的結(jié)果都是一樣的。 但是寫操作就不同了,每次操作都會(huì)導(dǎo)致數(shù)據(jù)發(fā)生變化。要想讓一個(gè)操作可以執(zhí)行多次,而沒(méi)有副作用,一定得想辦法記錄下這個(gè)操作執(zhí)行過(guò)沒(méi)有。

?

遺漏執(zhí)行

我把新API告訴大家: 一定要給我傳遞過(guò)來(lái)一個(gè)TxID啊, 否則別怪我不處理!

這一天,我接收到了兩個(gè)HTTP的調(diào)用,第一次是這樣的:

POST /xxx/BonusPoint/U0002

{"txid":"T0010","value":"200"}

于是我很高興地執(zhí)行了,并且把T0010這個(gè)txid給保存了下來(lái)。

然后第二個(gè)調(diào)用又來(lái)了, 和第一個(gè)一模一樣:

POST /xxx/BonusPoint/U0002

{"txid":"T0010","value":"200"}

我用T0010一查,數(shù)據(jù)庫(kù)已經(jīng)存在,我就知道,不用再處理了, 直接告訴對(duì)方:處理完成。

沒(méi)想到的是, 用戶很快就抱怨了:為什么我增加了兩次積分(每次200),但實(shí)際上只增加了一次呢?

這肯定不是我的鍋, 我這邊沒(méi)有任何問(wèn)題,一切按照設(shè)計(jì)執(zhí)行。 我說(shuō):“剛才是誰(shuí)發(fā)起的調(diào)用,檢查下調(diào)用的日志!”

調(diào)查了調(diào)用方的日志才發(fā)現(xiàn),那兩次調(diào)用是兩個(gè)系統(tǒng)發(fā)出的!

碰巧,這兩個(gè)系統(tǒng)生成了相同的TxID : T0010 ,?這就導(dǎo)致我認(rèn)為是同一個(gè)調(diào)用的兩次嘗試, 實(shí)際上這是這是完全不同的兩次調(diào)用。

真相大白,TxID是罪魁禍?zhǔn)?#xff0c;可見(jiàn)這個(gè)TxID在整個(gè)分布式的系統(tǒng)中不能重復(fù),一定得是唯一的才行。

?

分布式ID

怎么在一個(gè)分布式的系統(tǒng)中生成為一個(gè)唯一的ID呢?

訂單小伙說(shuō):“這很簡(jiǎn)單,我們使用UUID就可以了,UUID中包含了網(wǎng)卡的MAC地址,時(shí)間戳,隨機(jī)數(shù)等信息, 從時(shí)間和空間上保證了唯一性, 肯定不會(huì)重復(fù)。 ”

UUID可以在本機(jī)輕松生成,不用再發(fā)起什么遠(yuǎn)程調(diào)用,效率極高。

844A6D2B-CF7B-47C9-9B2B-2AC5C1B1C56B

我說(shuō):“只是這長(zhǎng)達(dá)128位數(shù)字和字母顯得很凌亂,沒(méi)法排序,也無(wú)法保證有序遞增(尤其是在數(shù)據(jù)庫(kù)中,有序的ID更容易確定位置)。”

大家紛紛點(diǎn)頭,UUID被否定。

MySQL提議:“你們竟然把我忘了! 我可以支持自增的(auto_increment)列啊, 天然的ID啊,同志們,絕對(duì)可以保證有序性。”

“啊? 用數(shù)據(jù)庫(kù)? 你萬(wàn)一要是罷工了怎么辦? 我們沒(méi)有ID可用,什么事兒都干不成了!” ?大家一想到慢吞吞的老頭兒,讓大家去依賴它,把生殺大權(quán)交到它的手上,都有點(diǎn)不樂(lè)意。

Ngnix說(shuō):“你們怕他罷工,就多弄幾個(gè)MySQL唄,比如2個(gè)。

第一個(gè)的初始值是1,每次增加2,它產(chǎn)生的ID就是 1, 3, 5,7......

第二個(gè)的初始值是2,每次也增加2,它產(chǎn)生的ID就是 2,4,6,8,10......

再弄一個(gè)ID生成服務(wù),如果一個(gè)MySQL罷工了,就訪問(wèn)另外一個(gè)。”

?

“如果這個(gè)ID生成服務(wù)也完蛋了呢?” ?有人問(wèn)道。

“那可以多部署幾個(gè)ID生成服務(wù)啊, 這不就是你們微服務(wù)的優(yōu)勢(shì)所在嗎?” Nginx反問(wèn)。

Ngnix不虧是搞負(fù)載均衡的,這個(gè)方法可是相當(dāng)?shù)孛?#xff0c; 不但提高了可用性, ID還能保持趨勢(shì)遞增。

“可是,我每次需要一個(gè)TxID,都需要訪問(wèn)一次數(shù)據(jù)庫(kù)啊,這該多慢啊!” ?訂單小伙說(shuō)道。

負(fù)責(zé)緩存的Redis說(shuō)道:“不要每次都訪問(wèn)數(shù)據(jù)庫(kù),學(xué)我,緩存一些數(shù)據(jù)到內(nèi)存中。”

“緩存? 怎么緩存?”

Redis 說(shuō):“每次訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候,可以獲取一批ID,比如10個(gè), 然后保存的內(nèi)存中,這樣別人就可以直接使用,不用訪問(wèn)數(shù)據(jù)庫(kù)了, 當(dāng)然,數(shù)據(jù)庫(kù)需要記錄下當(dāng)前的最大ID是多少。”

假設(shè)初始的最大ID是1 , 獲取10個(gè)ID, 即 1,2,3......10 ,保存到內(nèi)存中, 此時(shí) 最大ID變成10。

下次再獲取10個(gè),即11,12,13......20 , 最大ID變成20。

“可是,你這個(gè)唯一的MySQL罷工了,系統(tǒng)還是要停擺啊!” 我說(shuō)。

Ngnix說(shuō):“這種事情很簡(jiǎn)單,多加一個(gè)MySQL,弄一個(gè)一主一從的結(jié)構(gòu), 嗯,如果數(shù)據(jù)沒(méi)有及時(shí)從Master復(fù)制到Slave的時(shí)候,Master就罷工了,此時(shí)Slave的中的Max ID就不是最新的,那接下來(lái)就可能出問(wèn)題,也許可以搞一個(gè)雙主的結(jié)構(gòu)......”

唉,搞一個(gè)分布式的唯一ID這么復(fù)雜啊!

Ngnix在那里嘟嘟囔囔,大家都沒(méi)有注意到,一個(gè)新的服務(wù)上線了,一上來(lái)就說(shuō):“嗨,大家好,我是snowflake......”

總結(jié)

以上是生活随笔為你收集整理的后端风云的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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