成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我只是下了個(gè)訂單,鬼知道我在微服務(wù)里經(jīng)歷了什么?

原創(chuàng)
開(kāi)發(fā) 架構(gòu) 開(kāi)發(fā)工具
面試的時(shí)候,面試官問(wèn):用戶(hù)在電商網(wǎng)站中購(gòu)買(mǎi)成功了,那么它在微服務(wù)中經(jīng)歷了什么?你該如何作答?

【51CTO.com原創(chuàng)稿件】面試的時(shí)候,面試官問(wèn):用戶(hù)在電商網(wǎng)站中購(gòu)買(mǎi)成功了,那么它在微服務(wù)中經(jīng)歷了什么?你該如何作答?

當(dāng)我傻啊,用戶(hù)在電商網(wǎng)站購(gòu)買(mǎi)成功,還在微服務(wù)中,那肯定就是有一套微服務(wù)架構(gòu)的電商系統(tǒng)。

[[268423]] 

設(shè)計(jì)一套電商系統(tǒng)還不簡(jiǎn)單?簡(jiǎn)單想象一下,既然是一個(gè)電商系統(tǒng),有用戶(hù)去購(gòu)買(mǎi),就肯定得有一個(gè)用戶(hù)模塊,購(gòu)買(mǎi)什么東西總不是西北風(fēng)吧,購(gòu)買(mǎi)肯定是商品吧,省掉購(gòu)物車(chē),就得有商品模塊吧。

商品總得有庫(kù)存吧,庫(kù)存就暫時(shí)跟商品放一起吧,什么倉(cāng)儲(chǔ)物流先別管,就當(dāng)作是虛擬商品好了,反正題目也沒(méi)說(shuō)不能是虛擬商品。^_^

購(gòu)買(mǎi)成功了,那就必須有訂單吧,加個(gè)訂單模塊,下完單總得支付吧,不付錢(qián)人家憑什么把東西給你,那就得有個(gè)支付模塊。

 

簡(jiǎn)單粗暴,四個(gè)模塊,如上圖:

  • 用戶(hù)模塊
  • 商品模塊(庫(kù)存)
  • 訂單模塊
  • 支付模塊

好,幾個(gè)模塊搞定,外加下單流程圖:

[[268426]] 

等等,貌似題目說(shuō)是微服務(wù),既然是微服務(wù)就涉及到拆分服務(wù)的問(wèn)題。

DDD 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)

剛剛確實(shí)是梳理了一下模塊,既然是微服務(wù),就得進(jìn)行服務(wù)的拆分,服務(wù)怎么進(jìn)行拆分呢?

貌似按照剛次梳理模塊來(lái)劃分也是可以的,不過(guò)這樣好像顯得我很是不專(zhuān)業(yè),聽(tīng)說(shuō)現(xiàn)在很多人都要使用 DDD(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))來(lái)指導(dǎo)微服務(wù)的拆分。

 

參考 DDD 的設(shè)計(jì),DDD 官方的架構(gòu)草圖,總體架構(gòu)分為四層:

  • Infrastructure(基礎(chǔ)實(shí)施層)
  • Domain(領(lǐng)域?qū)?
  • Application(應(yīng)用層)
  • Interfaces(表示層,也叫用戶(hù)界面層或是接口層)

微服務(wù)結(jié)合 DDD

不過(guò)對(duì)于領(lǐng)域設(shè)計(jì)而言,代碼層其實(shí)不是最重要,最重要的是如何去劃分領(lǐng)域,劃分好邊界。

而對(duì)于微服務(wù)而言,非常適合從業(yè)務(wù)上去劃分各個(gè) Modules,劃分好各個(gè)業(yè)務(wù)板塊,微服務(wù) + DDD,個(gè)人覺(jué)得首先從微服務(wù)的角度考慮去劃分大的業(yè)務(wù)模塊,每個(gè)微服務(wù)都應(yīng)該是一個(gè)可以獨(dú)立部署,各司其職的模塊。

簡(jiǎn)單的說(shuō),在微服務(wù)實(shí)際的開(kāi)發(fā)中,結(jié)合 DDD 的思想去劃分所有屬于自己的領(lǐng)域。

實(shí)施 DDD 的關(guān)鍵

第一點(diǎn)是使用通過(guò)的語(yǔ)言建立所有的聚合,實(shí)體,值對(duì)象。

第二點(diǎn)也就是最關(guān)鍵的“建模”:

劃分“戰(zhàn)略建模”,從一種宏觀的角度去審核整個(gè)項(xiàng)目,劃分出“界限上下文”,形成具有上帝視角的“上下文映射圖”。

還有一個(gè)建模是“戰(zhàn)術(shù)建模”,在我們的“戰(zhàn)略建模”劃分出來(lái)的“界限上下文”中進(jìn)行“聚合”,“實(shí)體”,“值對(duì)象”,并按照模塊分組。

構(gòu)建電商系統(tǒng)的上下文映射圖

先來(lái)確定我們的戰(zhàn)略核心的領(lǐng)域是什么?我們的目的是什么?

作為一個(gè)電商系統(tǒng),我們的核心肯定是賣(mài)出更多的商品,獲取更多訂單更多的利潤(rùn),那么銷(xiāo)售可以作為我們的一個(gè)核心的領(lǐng)域。

這個(gè)作為一個(gè)明確核心域確立下來(lái):

 

確定完核心子域后,根據(jù)對(duì)這個(gè)領(lǐng)域的理解劃分出各個(gè)上下文,然后根據(jù)上下文再確定其他的相關(guān)領(lǐng)域。

 

初步我們可以看出圍繞銷(xiāo)售核心域的包含的幾大塊內(nèi)容,價(jià)格,銷(xiāo)售方式,購(gòu)買(mǎi)的方式,已經(jīng)購(gòu)買(mǎi)。

然后我們對(duì)支撐著核心域的子域也做了劃分,支撐著核心域的有商品域,用戶(hù)域,通用域有訂單域,物流域,支付域。

回到我們的主題,我們這次沒(méi)有購(gòu)物車(chē),也沒(méi)有各個(gè)會(huì)員銷(xiāo)售價(jià)格,把一些上下文拿掉,并建立映射。

 

領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)看似簡(jiǎn)單,其實(shí)很難實(shí)施,因?yàn)樵诟鱾€(gè)環(huán)節(jié)中都需要對(duì)應(yīng)的領(lǐng)域?qū)<业膮⒓踊蛑笇?dǎo),這樣才能設(shè)計(jì)出最符合實(shí)際的上下文映射圖。

而且我們花費(fèi)的精力可能相比以后的數(shù)據(jù)驅(qū)動(dòng)開(kāi)發(fā)模式更多,但在整體對(duì)項(xiàng)目的把控性能上說(shuō),領(lǐng)域比數(shù)據(jù)驅(qū)動(dòng)更加抽象,更加的頂層設(shè)計(jì),在對(duì)應(yīng)互聯(lián)網(wǎng)的多變情況看得更遠(yuǎn)。

我們將微服務(wù)拆分為 5 個(gè)領(lǐng)域,分別是:

  • 銷(xiāo)售域
  • 商品域
  • 用戶(hù)域
  • 訂單域
  • 支付域

完美,接下來(lái)就可以開(kāi)始開(kāi)發(fā)了。 ^ _ ^

[[268428]] 

等等,兵馬未動(dòng),糧草先行;代碼未動(dòng),圖先行,先把時(shí)序圖畫(huà)出來(lái)。

時(shí)序圖

一個(gè)簡(jiǎn)單的下單流程,涵蓋了幾個(gè)領(lǐng)域:

 

完美,接下來(lái)就可以開(kāi)發(fā)微服務(wù)了。^ _ ^

 

[[268428]]

等等,微服務(wù)的技術(shù)棧還未選型。

微服務(wù)技術(shù)棧選型

服務(wù)拆分完了,時(shí)序圖也畫(huà)完了,可以開(kāi)始我們的微服務(wù)之旅了,目前主流的微服務(wù)有阿里大名鼎鼎的 Dubbo 和 Spring Cloud 全家桶,還有新浪的 Motan。

比較熟悉的還是 Dubbo 和 Spring Cloud,也都使用過(guò),究竟應(yīng)該選用哪一個(gè)呢?

因?yàn)橹岸际褂眠^(guò),做點(diǎn)簡(jiǎn)單,粗暴的總結(jié)。Dubbo 在很早之前就開(kāi)始使用,當(dāng)時(shí)的微服務(wù)還沒(méi)有現(xiàn)在這么火,很多理論體系也未完善,Dubbo 更像是一套 RPC 整合框架,Spring Cloud 則更傾向微服務(wù)架構(gòu)的生態(tài)。

相比 Dubbo,Spring Cloud 可以說(shuō)是微服務(wù)一整套的解決方案,在功能上是 Dubbo 的一個(gè)超級(jí)。

Dubbo 和 Spring Cloud 比喻,Dubbo 架構(gòu)的微服務(wù)就像組裝電腦,各個(gè)環(huán)節(jié)自由度很高。Spring Cloud 更像品牌機(jī)。

基于不折騰,簡(jiǎn)單快捷,更傾向選擇 Spring Cloud。OK,就定下來(lái)技術(shù)棧使用 Spring Cloud,愉快的決定。 

[[268428]]

等等,就這么草率就決定用 Spring Cloud 做為微服務(wù),難道不需要把微服務(wù)的利弊先弄清楚嗎?

微服務(wù)的利和弊

既然選擇了微服務(wù),就得知道微服務(wù)的利和弊,特別是弊,引入了微服務(wù),就等于引入了一套復(fù)雜的體系,一套復(fù)雜的體系帶來(lái)的各種挑戰(zhàn)必須事先了解清楚。

 

①?gòu)?qiáng)模塊化邊界

我們知道做軟件架構(gòu),軟件設(shè)計(jì),模塊化是非常重要的一點(diǎn),一開(kāi)始我們寫(xiě)程序做軟件,我們采用類(lèi)的方式來(lái)做模塊化,后面開(kāi)始采用組件或類(lèi)庫(kù)的方式做模塊化,可以做到工程上的重用和分享給其他團(tuán)隊(duì)來(lái)使用。

微服務(wù)在組件的層次上面又高了一層,以服務(wù)的方式來(lái)做模塊化,每個(gè)團(tuán)隊(duì)獨(dú)立開(kāi)始和維護(hù)自己的服務(wù),有明顯的一個(gè)邊界。

開(kāi)發(fā)完一個(gè)服務(wù),其他團(tuán)隊(duì)可以直接調(diào)用這個(gè)服務(wù),不需要像組件通過(guò) Jar 或源碼的方式去進(jìn)行分享,所以微服務(wù)的邊界是比較清晰的。

②可獨(dú)立部署

③技術(shù)多樣性

弊(或者說(shuō)挑戰(zhàn))

①分布式復(fù)雜性

在原來(lái)單塊應(yīng)用就是一個(gè)應(yīng)用,一個(gè)對(duì)單塊應(yīng)用的架構(gòu)比較熟悉的人可以對(duì)整個(gè)單塊應(yīng)用有一個(gè)很好的把控。

但是到了分布式系統(tǒng),微服務(wù)化了以后可能涉及到的服務(wù)有好幾十個(gè),一些大公司可能涉及到的服務(wù)上百個(gè),服務(wù)與服務(wù)之間是通過(guò)相互溝通來(lái)實(shí)現(xiàn)業(yè)務(wù)。

那么這個(gè)時(shí)候整個(gè)系統(tǒng)就變成非常復(fù)雜,一般的開(kāi)發(fā)人員或一個(gè)團(tuán)隊(duì)都無(wú)法理解整個(gè)系統(tǒng)是如何工作的,這個(gè)就是分布式帶來(lái)的復(fù)雜性。

②最終一致性

微服務(wù)的數(shù)據(jù)是分散式治理的,每個(gè)團(tuán)隊(duì)都有自己的數(shù)據(jù)源和數(shù)據(jù)拷貝,比方說(shuō)團(tuán)隊(duì) A 有訂單數(shù)據(jù),B 團(tuán)隊(duì)也有訂單數(shù)據(jù),團(tuán)隊(duì) A 修改了訂單數(shù)據(jù)是否應(yīng)該同步給團(tuán)隊(duì) B 的數(shù)據(jù)呢?

這里就涉及到數(shù)據(jù)一致性問(wèn)題,如果沒(méi)有很好的解決一致性問(wèn)題,就可能造成數(shù)據(jù)的不一致,這個(gè)在業(yè)務(wù)上是不可以接受的。

③運(yùn)維復(fù)雜性

以往的運(yùn)維需要管理的是機(jī)器+單塊的應(yīng)用,分布式系統(tǒng)和單塊應(yīng)用不一樣的是,分布式系統(tǒng)需要很多的服務(wù),服務(wù)與服務(wù)之間相互協(xié)同。

那么對(duì)分布式系統(tǒng)的資源,容量規(guī)劃,監(jiān)控,對(duì)整個(gè)系統(tǒng)的可靠性穩(wěn)定性都非常具備挑戰(zhàn)的。

只有在清楚了解微服務(wù)帶來(lái)的挑戰(zhàn),明知道山有虎偏向虎山行,才能夠真正的勝任挑戰(zhàn),最重要的是,要清楚明了里面有什么坑,怎么避免踩坑。

完美,已經(jīng)了解微服務(wù)帶來(lái)的好處和挑戰(zhàn),接下來(lái)就可以開(kāi)始開(kāi)發(fā)了。^ _ ^ 

[[268428]]

等等,微服務(wù)還沒(méi)有做邏輯分層。

微服務(wù)怎么做邏輯分層

目前我們的微服務(wù)里面有幾個(gè)服務(wù),分別是訂單,商品,用戶(hù)。

如果客戶(hù)端向查看 “我的訂單” 這么一個(gè)接口;如果客戶(hù)端假定是 PC 端,就需要請(qǐng)求三次接口,分別對(duì)接訂單,商品,用戶(hù)三個(gè)服務(wù),分別拿完三次調(diào)用數(shù)據(jù),再將三次調(diào)用數(shù)據(jù)進(jìn)行整合輸出展示。

要知道 PC 調(diào)用后端服務(wù)是走外網(wǎng),這無(wú)疑大大增加了網(wǎng)絡(luò)的開(kāi)銷(xiāo),而且讓 PC 端變成更為復(fù)雜。

假定在中間加多一個(gè)層為聚合服務(wù)層,即對(duì)網(wǎng)絡(luò)開(kāi)銷(xiāo)進(jìn)行減少,因?yàn)槲⒎?wù)內(nèi)部是通過(guò)內(nèi)網(wǎng)進(jìn)行數(shù)據(jù)傳輸,也讓 PC 端的業(yè)務(wù)變得比較簡(jiǎn)單。

 

圖中的 “PC 聚合服務(wù)” 也是一個(gè)微服務(wù),只不過(guò)它是屬于聚合服務(wù)中間層,我們將為微服務(wù)進(jìn)行邏輯劃分,分為 2 個(gè)層:

 

①微服務(wù)基礎(chǔ)服務(wù)層

基礎(chǔ)服務(wù)一般屬于互聯(lián)網(wǎng)平臺(tái)基礎(chǔ)性的支撐服務(wù),比方說(shuō),電商網(wǎng)站的基礎(chǔ)服務(wù)有訂單服務(wù),商品服務(wù),用戶(hù)服務(wù)等。

這些都屬于比較基礎(chǔ)和原子性,下沉一個(gè)公司的基礎(chǔ)設(shè)施的低層,向下承接存儲(chǔ),向上提供業(yè)務(wù)能力,有些公司叫基礎(chǔ)服務(wù),中間層服務(wù),公共服務(wù),Netflix 成為中間層服務(wù)。我們暫且統(tǒng)稱(chēng)為基礎(chǔ)服務(wù)。

②微服務(wù)聚合服務(wù)層

已經(jīng)有了基礎(chǔ)服務(wù)能提供業(yè)務(wù)能力,為什么還需要聚合服務(wù),因?yàn)槲覀冇胁煌慕尤攵耍?App 和 H5,PC 等等,它們看似調(diào)用大致相同的數(shù)據(jù),但其實(shí)存在很多差異。

例如 PC 需要展示更多信息,App 需要做信息裁剪等等。一般低層服務(wù)都是比較通用的,基礎(chǔ)服務(wù)應(yīng)該對(duì)外輸出相對(duì)統(tǒng)一的服務(wù),在抽象上做得比較好。

但是對(duì)不同的外界 App 和 PC 的接入,我們需要作出不同的適配,這個(gè)時(shí)候需要有一個(gè)層去做出聚合裁剪的工作。

例如一個(gè)商品詳情在 PC 端展示和 App 端的展示,PC 可能會(huì)展示更多的信息,而 App 則需要對(duì)信息作出一些裁剪。

如果基礎(chǔ)服務(wù)直接開(kāi)放接口給到 PC 和 App,那么基礎(chǔ)服務(wù)也需要去做成各種設(shè)配,這個(gè)很不利于基礎(chǔ)服務(wù)的抽象。

所以我們?cè)诨A(chǔ)層之上加入聚合服務(wù)層,這個(gè)層可以針對(duì) PC 和 App 做成適當(dāng)?shù)脑O(shè)配進(jìn)行相應(yīng)的裁剪。

那么我們的微服務(wù)中,又增加了一個(gè)服務(wù),屬于聚合服務(wù)。

 

好了,接下來(lái)可以愉快的 Coding...

  

[[268428]]

等等,貌似不對(duì),如果是單塊應(yīng)用加上事務(wù)應(yīng)該沒(méi)問(wèn)題,這里是分布式,恐怕得考慮加分布式事務(wù)。

分布式事務(wù)

我們來(lái)理一理創(chuàng)建訂單和扣件庫(kù)存模塊之間的關(guān)系:

 

可以發(fā)現(xiàn),因?yàn)槲⒎?wù)的原因,我們把服務(wù)進(jìn)行了分布式,隨著各個(gè)數(shù)據(jù)庫(kù)也隨著變成分布式每個(gè)數(shù)據(jù)庫(kù)不一定存在相同的物理機(jī)中。

那么這個(gè)時(shí)候單個(gè)數(shù)據(jù)庫(kù)的 ACID 已經(jīng)不能適應(yīng)這種情況,而在這種集群中想去保證集群的 ACID 幾乎很難達(dá)到,或者即使能達(dá)到那么效率和性能會(huì)大幅下降,最為關(guān)鍵的是再很難擴(kuò)展新的分區(qū)了。

這個(gè)時(shí)候如果再追求集群的 ACID 會(huì)導(dǎo)致我們的系統(tǒng)變得很差,這時(shí)我們就需要引入一個(gè)新的理論原則來(lái)適應(yīng)這種集群的情況,就是 CAP。

CAP 定理

CAP 必須滿(mǎn)足以下的 3 個(gè)屬性:

  • 一致性(C):在分布式系統(tǒng)中的所有數(shù)據(jù)備份,在同一時(shí)刻是否同樣的值。(等同于所有節(jié)點(diǎn)訪問(wèn)同一份最新的數(shù)據(jù)副本)
  • 可用性(A):在集群中一部分節(jié)點(diǎn)故障后,集群整體是否還能響應(yīng)客戶(hù)端的讀寫(xiě)請(qǐng)求。(對(duì)數(shù)據(jù)更新具備高可用性)
  • 分區(qū)容錯(cuò)性(P):以實(shí)際效果而言,分區(qū)相當(dāng)于對(duì)通信的時(shí)限要求。系統(tǒng)如果不能在時(shí)限內(nèi)達(dá)成數(shù)據(jù)一致性,就意味著發(fā)生了分區(qū)的情況,必須就當(dāng)前操作在 C 和 A 之間做出選擇。

簡(jiǎn)單的來(lái)說(shuō),在一個(gè)分布式系統(tǒng)中,最多能支持上面的兩種屬性。但顯然既然是分布式注定我們是必然要進(jìn)行分區(qū),既然分區(qū),我們就無(wú)法百分百避免分區(qū)的錯(cuò)誤。因此,我們只能在一致性和可用性去作出選擇。

在分布式系統(tǒng)中,我們往往追求的是可用性,它的重要性比一致性要高,那么如何實(shí)現(xiàn)高可用,這里又有一個(gè)理論,就是 BASE 理論,它給 CAP 理論做了進(jìn)一步的擴(kuò)充。

BASE 理論

BASE 理論指出:

  • Basically Available(基本可用)
  • Soft state(軟狀態(tài))
  • Eventually consistent(最終一致性)

BASE 理論是對(duì) CAP 中的一致性和可用性進(jìn)行一個(gè)權(quán)衡的結(jié)果,理論的核心思想就是:我們無(wú)法做到強(qiáng)一致,但每個(gè)應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹?lái)使系統(tǒng)達(dá)到最終一致性。

好了,說(shuō)了一大頓理論,程序員們都等急了,趕快來(lái)看看分布式事務(wù)的解決方案有哪些,可以進(jìn)行接下去的 Coding...

來(lái)吧,討論技術(shù)方案:

 

幾個(gè)方案拿出來(lái)了,因?yàn)槲覀儾皇菍?zhuān)門(mén)來(lái)講解分布式事務(wù)的機(jī)制和原理,主要還是來(lái)做分布式事務(wù)的技術(shù)選型。

先排除掉我們應(yīng)該不會(huì)選擇的方案,一個(gè)是 XA 兩階段提交,這個(gè)在很多傳統(tǒng)型公司會(huì)被使用,但不適合互聯(lián)網(wǎng)微服務(wù)的分布式系統(tǒng),鎖定資源時(shí)間長(zhǎng),性能影響大,排除。

另一個(gè)是阿里的 GTS,并沒(méi)有開(kāi)源,目前已經(jīng)開(kāi)源了 Fescar,不過(guò)目前尚缺少調(diào)研,可能在下個(gè)階段研究后會(huì)使用,目前先排除。

剩下的是 TCC 和 MQ 消息事務(wù)兩種。

MQ 消息事務(wù):RocketMQ

先說(shuō)說(shuō) MQ 的分布式事務(wù),RocketMQ 在 4.3 版本已經(jīng)正式宣布支持分布式事務(wù),在選擇 RokcetMQ 做分布式事務(wù)請(qǐng)務(wù)必選擇 4.3 以上的版本。

事務(wù)消息作為一種異步確保型事務(wù), 將兩個(gè)事務(wù)分支通過(guò) MQ 進(jìn)行異步解耦,RocketMQ 事務(wù)消息的設(shè)計(jì)流程同樣借鑒了兩階段提交理論,整體交互流程如下圖所示:

 

這個(gè)時(shí)候我們基本可以認(rèn)為,只有 MQ 發(fā)送方自己的本地事務(wù)執(zhí)行完畢,那么 MQ 的訂閱方必定百分百能夠接收到消息,我們?cè)賹?duì)下單減庫(kù)存的步驟進(jìn)行改造。

這里涉及到一個(gè)異步化的改造,我們理一下,如果是同步流程中的各個(gè)步驟:

  • 查看商品詳情(或購(gòu)物車(chē))
  • 計(jì)算商品價(jià)格和目前商品存在庫(kù)存(生成訂單詳情)
  • 商品扣庫(kù)存(調(diào)用商品庫(kù)存服務(wù))
  • 訂單確認(rèn)(生成有效訂單)

訂單創(chuàng)建完成后,發(fā)布一個(gè)事件“orderCreate” 到消息隊(duì)列中,然后由 MQ 轉(zhuǎn)發(fā)給訂閱該消息的服務(wù),因?yàn)槭腔谙⑹聞?wù),我們可以認(rèn)為訂閱該消息的商品模塊是百分百能收到這個(gè)消息的。

 

商品服務(wù)接受到 orderCreate 消息后就執(zhí)行扣減庫(kù)存的操作,注意⚠,這里可能會(huì)有一些不可抗的因素導(dǎo)致扣減庫(kù)存失敗。

無(wú)論成功或失敗,商品服務(wù)都將發(fā)送一個(gè)扣減庫(kù)存結(jié)果的消息“stroeReduce”到消息隊(duì)列中,訂單服務(wù)會(huì)訂閱扣減庫(kù)存的結(jié)果。

訂單服務(wù)收到消息后有兩種可能:

  • 如果扣減庫(kù)存成功,將訂單狀態(tài)改為 “確認(rèn)訂單” ,下單成功。
  • 如果扣減庫(kù)存失敗,將訂單狀態(tài)改為 “失效訂單” ,下單失敗。

 

這種模式將確認(rèn)訂單的流程變成異步化,非常適合在高并發(fā)的使用,但是,切記了,這個(gè)需要前端用戶(hù)體驗(yàn)的一些改變,要配合產(chǎn)品來(lái)涉及流程。

完美,使用 MQ 分布式事務(wù)就可以解決調(diào)一致性問(wèn)題。 

[[268428]]

等等,MQ 消息事務(wù)方案的風(fēng)險(xiǎn)了解一下。

上面使用 MQ 的方式確實(shí)是可以完成 A 和 B 操作,但是 A 和 B 并不是嚴(yán)格一致性,而是最終一致性。

我們犧牲掉嚴(yán)格一致性,換來(lái)性能的提升,這種很適合在大促高并發(fā)場(chǎng)景使用。

但是如果 B 一直執(zhí)行不成功,那么一致性也會(huì)被破壞,后續(xù)應(yīng)該考慮到更多的兜底方案,方案越細(xì)系統(tǒng)就將越復(fù)雜。

TCC 方案

TCC 是服務(wù)化的二階段變成模型,每個(gè)業(yè)務(wù)服務(wù)都必須實(shí)現(xiàn) Try,Confirm,Calcel 三個(gè)方法。

這三個(gè)方式可以對(duì)應(yīng)到 SQL 事務(wù)中 Lock,Commit,Rollback:

  • Try 階段:Try 只是一個(gè)初步的操作,進(jìn)行初步的確認(rèn),它的主要職責(zé)是完成所有業(yè)務(wù)的檢查,預(yù)留業(yè)務(wù)資源。
  • Confirm 階段:Confirm 是在 Try 階段檢查執(zhí)行完畢后,繼續(xù)執(zhí)行的確認(rèn)操作,必須滿(mǎn)足冪等性操作,如果 Confirm 中執(zhí)行失敗,會(huì)有事務(wù)協(xié)調(diào)器觸發(fā)不斷的執(zhí)行,直到滿(mǎn)足為止。
  • Cancel:是取消執(zhí)行,在 Try 沒(méi)通過(guò)并釋放掉 Try 階段預(yù)留的資源,也必須滿(mǎn)足冪等性,跟 Confirm 一樣有可能被不斷執(zhí)行。

接下來(lái)看看,我們的下單扣減庫(kù)存的流程怎么加入 TCC:

在 Try 的時(shí)候,會(huì)讓庫(kù)存服務(wù)預(yù)留 n 個(gè)庫(kù)存給這個(gè)訂單使用,讓訂單服務(wù)產(chǎn)生一個(gè)“未確認(rèn)”訂單,同時(shí)產(chǎn)生這兩個(gè)預(yù)留的資源。

在 Confirm 的時(shí)候,會(huì)使用在 Try 預(yù)留的資源,在 TCC 事務(wù)機(jī)制中認(rèn)為,如果在 Try 階段能正常預(yù)留的資源,那么在 Confirm 一定能完整的提交:

在 Try 的時(shí)候,有任務(wù)一方為執(zhí)行失敗,則會(huì)執(zhí)行 Cancel 的接口操作,將在 Try 階段預(yù)留的資源進(jìn)行釋放。

完美,可以把我們的系統(tǒng)引入 TCC。^ _ ^ 

[[268428]]

等等,有同學(xué)提問(wèn):

  • 有同學(xué)可能會(huì)問(wèn)了,如果在 Confirm 或 Cancel 中,有一方的操作失敗了,可能出現(xiàn)異常等情況該怎么解決。

這個(gè)就涉及 TCC 的事務(wù)協(xié)調(diào)器了,事務(wù)協(xié)調(diào)器就 Confirm 或 Cancel 沒(méi)有得到返回的時(shí)候,會(huì)啟用定時(shí)器不斷的進(jìn)行 Confirm 或 Cancel 的重試。

這個(gè)也就是我們強(qiáng)調(diào),Confirm,Cancel 接口必須是冪等性的一個(gè)原因了。

  • 還有同學(xué)會(huì)問(wèn)了,為什么事務(wù)協(xié)調(diào)器知道 Confirm,或 Cancel 沒(méi)有完成。

這個(gè)就涉及到了 TCC 也做了一張本地消息表,會(huì)記錄一次事務(wù),包括主事務(wù),子事務(wù),事務(wù)的完成情況都會(huì)記錄在這種表中(當(dāng)然未必是表,可能是 ZK,Redis 等等介質(zhì)),然后啟用一個(gè)定時(shí)器去檢查這種表。

  • 還有同學(xué)會(huì)問(wèn),事務(wù)怎么傳遞,這個(gè)就涉及使用的 TCC 的框架了,一般來(lái)說(shuō)用的都是隱式傳參的方式。

在主事務(wù)創(chuàng)建的時(shí)候用隱式傳參調(diào)用子事務(wù),子事務(wù)包含 Try,Confirm,Cancel 都會(huì)記錄到事務(wù)表里面。

這里推薦 TCC 的開(kāi)源框架使用 mengyun 的 TCC,然后也可以其他的,無(wú)所謂。

完美,下單的流程開(kāi)發(fā)完畢了,可以讓 QA 接入。^ _ ^ 

[[268428]]

等等,微服務(wù)的保護(hù)措施做了嗎?

熔斷限流隔離降級(jí)

微服務(wù)分布式依賴(lài)關(guān)系錯(cuò)綜復(fù)雜,比方說(shuō)前端的一個(gè)請(qǐng)求,這來(lái)到后端會(huì)被轉(zhuǎn)為為很多個(gè)請(qǐng)求。

這個(gè)時(shí)候后臺(tái)的服務(wù)出現(xiàn)不穩(wěn)定或者延遲,如果沒(méi)有好的限流熔斷措施,可能會(huì)造成用戶(hù)體驗(yàn)的下降,嚴(yán)重的時(shí)候會(huì)出現(xiàn)雪崩效應(yīng),把整個(gè)網(wǎng)站給搞垮。

如果像阿里巴巴在雙 11 等活動(dòng)中,如果沒(méi)有一套好的限流熔斷措施,這是不可想象的,可能是根本無(wú)法支撐那么大的并發(fā)容量。

Netflix 在 2012 年前也沒(méi)有設(shè)計(jì)好的限流容錯(cuò),當(dāng)時(shí)也是飽受著系統(tǒng)穩(wěn)定性的困擾,好幾次網(wǎng)站因?yàn)闆](méi)有好的熔斷措施把網(wǎng)站搞垮。

在 2012 年 Netflix 啟動(dòng)了彈性工程項(xiàng)目,其中有一個(gè)產(chǎn)品叫 Hystrix,這個(gè)產(chǎn)品主要用來(lái)解決微服務(wù)的可靠性。

有了這個(gè)系統(tǒng)之后,Netflix 在系統(tǒng)穩(wěn)定性上上了一個(gè)大的臺(tái)階,在此之后就沒(méi)有出現(xiàn)過(guò)大規(guī)模的雪崩事故。

下面使用 Hystrix 例子來(lái)講解一下限流熔斷。

幾個(gè)概念:熔斷,隔離,限流,降級(jí),這幾個(gè)概念是分布式容錯(cuò)最重要的概念和模式。

①熔斷:如果說(shuō)房子里面安裝了電路熔斷器,當(dāng)你使用超大功率的電路時(shí),有熔斷設(shè)備幫你保護(hù)不至于出問(wèn)題的時(shí)候把問(wèn)題擴(kuò)大化。

②隔離:我們知道計(jì)算資源都是有限的,CPU,內(nèi)存,隊(duì)列,線程池都是資源。

他們都是限定的資源數(shù),如果不進(jìn)行隔離,一個(gè)服務(wù)的調(diào)用可能要消耗很多的線程資源,把其他服務(wù)的資源都給占用了,那么可能出現(xiàn)因?yàn)橐粋€(gè)服務(wù)的問(wèn)題連帶效應(yīng)造成其他服務(wù)不能進(jìn)行訪問(wèn)。

③限流:讓大流量的訪問(wèn)沖進(jìn)去我們的服務(wù)時(shí),我們需要一定的限流措施,比方說(shuō)我們規(guī)則一定時(shí)間內(nèi)只允許一定的訪問(wèn)數(shù)從我們的資源過(guò),如果再大的話系統(tǒng)會(huì)出現(xiàn)問(wèn)題,那么就需要限流保護(hù)。

④降級(jí):如果說(shuō)系統(tǒng)后臺(tái)無(wú)法提供足夠的支撐能力,那么需要一個(gè)降級(jí)能力,保護(hù)系統(tǒng)不會(huì)被進(jìn)一步惡化,而且可以對(duì)用戶(hù)提供比較友好的柔性方案,例如告知用戶(hù)暫時(shí)無(wú)法訪問(wèn),請(qǐng)?jiān)谝欢螘r(shí)候后重試等等。

Hystrix

Hystrix 就把上面說(shuō)的熔斷,隔離,限流,降級(jí)封裝在這么一個(gè)組件里面,下圖是 Hystrix 內(nèi)部設(shè)計(jì)和調(diào)用流程:

大致的工作流如下:

  • 構(gòu)建一個(gè) HystrixCommand 對(duì)象,用于封裝請(qǐng)求,并在構(gòu)造方法配置請(qǐng)求被執(zhí)行需要的參數(shù)。
  • 執(zhí)行命令,Hystrix 提供了幾種執(zhí)行命令的方法,比較常用到的是 Synchrous 和 Asynchrous。
  • 判斷電路是否被打開(kāi),如果被打開(kāi),直接進(jìn)入 Fallback 方法。
  • 判斷線程池/隊(duì)列/信號(hào)量是否已經(jīng)滿(mǎn),如果滿(mǎn)了,直接進(jìn)入 Fallback 方法。
  • 執(zhí)行 Run 方法,一般是 HystrixCommand.run(),進(jìn)入實(shí)際的業(yè)務(wù)調(diào)用,執(zhí)行超時(shí)或者執(zhí)行失敗拋出未提前預(yù)計(jì)的異常時(shí),直接進(jìn)入 Fallback 方法。
  • 無(wú)論中間走到哪一步都會(huì)進(jìn)行上報(bào) Metrics,統(tǒng)計(jì)出熔斷器的監(jiān)控指標(biāo)。
  • Fallback 方法也分實(shí)現(xiàn)和備用的環(huán)節(jié)。
  • 最后是返回請(qǐng)求響應(yīng)。

完美,把 Hystrix 加入我們系統(tǒng)吧,這樣突然有洪峰流量也不至于我們的系統(tǒng)一下就沖垮。^ _ ^ 

[[268428]]

等等,Hystrix 的限流數(shù)值,錯(cuò)誤數(shù)熔斷,超時(shí)熔斷,嘗試恢復(fù)比率這些需要我們配置的數(shù)值應(yīng)該怎么定呢?

這個(gè)就取決你的系統(tǒng)壓測(cè)的指標(biāo)和你部署的規(guī)模了,這里還涉及到一個(gè)容量設(shè)計(jì)的問(wèn)題,一會(huì)我們將系統(tǒng)部署上線的時(shí)候再來(lái)詳細(xì)說(shuō)道。

剛剛提到一個(gè)問(wèn)題,就是這些限流數(shù)值,錯(cuò)誤數(shù)熔斷這些數(shù)字,我們現(xiàn)在都寫(xiě)在配置文件里面。

例如說(shuō)寫(xiě)在 Properties,YML 里面,當(dāng)有一天突然需要把限流數(shù)下調(diào)(可能是系統(tǒng)遭受到什么壓力打擊),那我們只能把代碼拉下來(lái),巴拉巴拉改了。

然后重新上傳打包,發(fā)布重啟,一個(gè)流程下來(lái),不說(shuō)個(gè)把小時(shí)吧,十來(lái)分鐘總少不了吧。

想辦法我們把這些配置項(xiàng)放到一個(gè)集中式配置中心。

集中式配置中心

自己寫(xiě)配置中心還挺麻煩的,去菜市場(chǎng)逛逛吧,菜市場(chǎng)里面有,Spring Cloud Config,百度的 Disconf,阿里的 Diamond,還有攜程的 Apollo。

基本上他們的原理都差不多,配置中心可以簡(jiǎn)單的理解為一個(gè)服務(wù)模塊,開(kāi)發(fā)人員或運(yùn)維人員可以通過(guò)界面對(duì)配置中心進(jìn)行配置。

下面相關(guān)的微服務(wù)連接到配置中心上面就可以實(shí)時(shí)連接獲取到配置中心上面修改的參數(shù)。

更新的方式一般有兩種:

  • Pull 模式,服務(wù)定時(shí)去拉取配置中心的數(shù)據(jù)。
  • Push 模式,服務(wù)一直連接到配置中心上,一旦配置有變成,配置中心將把變更的參數(shù)推送到對(duì)應(yīng)的微服務(wù)上。

 

Pull 和 Push 兩種模式各有優(yōu)缺點(diǎn):

  • Pull 一般使用定時(shí)器拉取,就算某一個(gè)網(wǎng)絡(luò)抖動(dòng)沒(méi)有 Pull 成功,在下一次定時(shí)器的時(shí)候,終將能保證獲取最新的配置。
  • Push 可以避免 Pull 定時(shí)器存在的延時(shí),基本可以做到實(shí)時(shí)獲取數(shù)據(jù),但也有問(wèn)題就是網(wǎng)絡(luò)抖動(dòng)的時(shí)候可能會(huì)丟失更新。

攜程的 Apollo

 

攜程的 Apollo 比較有特色的是融合了 Pull 和 Push 兩種模式,把兩者的優(yōu)點(diǎn)進(jìn)行了結(jié)合,開(kāi)發(fā)或運(yùn)維人員在配置中心進(jìn)行修改,配置中心服務(wù)將實(shí)時(shí)將修改推送 Push 到 Apollo 的客戶(hù)端。

但考慮到可能由于某些網(wǎng)絡(luò)抖動(dòng)沒(méi)有推送成功,客戶(hù)端還具備了定時(shí)向 Apollo 服務(wù)端拉取 Pull 數(shù)據(jù)的功能。

就算推送沒(méi)成功,但是只要一定時(shí)間周期,客戶(hù)端還是會(huì)主動(dòng)去拉取同步數(shù)據(jù),保證能把最終配置同步到服務(wù)中。這個(gè)也是 Apollo 在高可用方面上非常有特色的設(shè)計(jì)。

Apollp 在高可用上也做了保證,客戶(hù)端獲取到數(shù)據(jù)會(huì)把數(shù)據(jù)緩存在內(nèi)存,還會(huì) Sync 到本地磁盤(pán)。

就算 Apollo 服務(wù)器掛掉了,就算客戶(hù)端服務(wù)重啟了,也可以從本地磁盤(pán)中拉取回來(lái)數(shù)據(jù),繼續(xù)提供對(duì)外服務(wù),從這點(diǎn)來(lái)看 Apollo 的配置中心在高可用上考慮還是比較周到的。

把配置中心配置上去后,我們就可以把 Hystrix 還有 MySQL 的用戶(hù)密碼,還有一些業(yè)務(wù)開(kāi)關(guān)等等的配置參數(shù)放上去了。

完美,開(kāi)發(fā)基本完工了,其實(shí)就幾個(gè)模塊,一個(gè)簡(jiǎn)單的下單購(gòu)物流程,當(dāng)我們把系統(tǒng)交付給運(yùn)維,運(yùn)維喊道,日志呢,做微服務(wù)怎么可以沒(méi)有調(diào)用鏈日志呢?

調(diào)用鏈監(jiān)控&日志

確實(shí),微服務(wù)是一個(gè)分布式非常復(fù)雜的系統(tǒng),如果沒(méi)有一套調(diào)用鏈監(jiān)控,如果服務(wù)之間依賴(lài)出現(xiàn)問(wèn)題就很難進(jìn)行定位。

下圖是阿里在鷹眼系統(tǒng)給出的微服務(wù)之“熵”:

 

目前各大主流互聯(lián)網(wǎng)公司中,阿里有非常出色的鷹眼系統(tǒng),點(diǎn)評(píng)也有一套很出名的調(diào)用鏈監(jiān)控系統(tǒng) CAT。

調(diào)用鏈監(jiān)控其實(shí)最早是 Google 提出來(lái)的,2010 年 Google 發(fā)表了一篇調(diào)用鏈的論文,論文以它內(nèi)部的調(diào)用鏈系統(tǒng) Dapper 命名。

這個(gè)論文中講解調(diào)用鏈在 Google 使用的經(jīng)驗(yàn)和原理,大致的原理如下圖:

 

這里可以采用 ELK 的方式去記錄和展示調(diào)用鏈監(jiān)控日志,當(dāng)我們一條調(diào)用為一行記錄存儲(chǔ)下來(lái)。

 

通過(guò) TraceId 和 ParentSpanId 就可以串聯(lián)起來(lái)為一個(gè)整體的鏈路,并可以從這個(gè)鏈路去分析錯(cuò)誤或者調(diào)用延時(shí)和調(diào)用次數(shù)等等。

 

目前市面主流的調(diào)用鏈選型有 Zipkin,Pinpoint,Cat,Skywalking,他們之間各有一些偏重點(diǎn)。

值得一說(shuō)的是 Skywalking 是國(guó)人出品的一款新的調(diào)用鏈工具,采用開(kāi)源的基于字節(jié)碼注入的調(diào)用鏈分析,接入段無(wú)代碼入侵。

而且開(kāi)源支持多種插件,UI 在幾款工具來(lái)說(shuō)比較功能比較強(qiáng)大,而且 UI 也比較賞心悅目,目前已經(jīng)加入了 Apache 孵化器。

采用 Skywalking 作為調(diào)用鏈工具

為何會(huì)采用 Skywaling,在低層原理的實(shí)現(xiàn),這幾款產(chǎn)品都差不多,但在實(shí)現(xiàn)和使用的細(xì)節(jié)相別還是很大:

  • 首先在實(shí)現(xiàn)方式上,Skywalking 基本對(duì)于代碼做到了無(wú)入侵,采用 Java 探針和字節(jié)碼增強(qiáng)的方式,而在 Cat 還采用了代碼埋點(diǎn),而 Zipkin 采用了攔截請(qǐng)求,Pinpoint 也是使用 Java 探針和字節(jié)碼增強(qiáng)。
  • 其次在分析的顆粒度上,Skywaling 是方法級(jí),而 Zipkin 是接口級(jí),其他兩款也是方法級(jí)。
  • 在數(shù)據(jù)存儲(chǔ)上,Skywalking 可以采用日志體系中比較出名的 ES,其他幾款,Zipkin 也可以使用 ES,Pinpoint 使用 Hbase,Cat 使用 MySQL 或 HDFS,相對(duì)復(fù)雜。

由于目前公司對(duì) ES 熟悉的人才比較有保證,選擇熟悉存儲(chǔ)方案也是考慮技術(shù)選型的重點(diǎn)。

  • 還有就是性能影響,根據(jù)網(wǎng)上的一些性能報(bào)告,雖然未必百分百準(zhǔn)備,但也具備參考價(jià)值,Skywalking 的探針對(duì)吞吐量的影響在 4 者中間是最效的,經(jīng)過(guò)對(duì) Skywalking 的一些壓測(cè)也大致證明。

完美,把微服務(wù)的包打好,上傳到服務(wù)器就可以運(yùn)行了。^ _ ^ 

[[268428]]

等等,微服務(wù)包都打好了,剩下就是 Jar 包或 War 包一個(gè)一個(gè)上傳到服務(wù)器上,然后用個(gè)腳本 Start,在以前單塊應(yīng)用還好,現(xiàn)在微服務(wù)幾十幾百個(gè)應(yīng)用,請(qǐng)問(wèn),運(yùn)營(yíng)人員怕不怕?

聽(tīng)說(shuō),Docker + Kubernetes 和微服務(wù)更配喔。

Docker + Kubernetes

就幾個(gè)服務(wù),先不用容器化部署了...乍一看,沒(méi)完沒(méi)了,還有 CICD,灰度發(fā)布...容易編排...

下次再講吧,先把服務(wù)部署上去吧。

部署到生產(chǎn),預(yù)估容量

該把服務(wù)部署上線了,一個(gè)服務(wù)上線肯定得評(píng)估下或者預(yù)估下訪問(wèn)量有多少用戶(hù),有多少訪問(wèn),這個(gè)涉及到該配置多少的機(jī)器資源,這應(yīng)該怎么去估算呢,反正程序員在家里怎么算都算不出來(lái)。

評(píng)估訪問(wèn)量

①問(wèn)運(yùn)營(yíng),如果是一個(gè)已經(jīng)上線的產(chǎn)品,肯定存在已有的用戶(hù)數(shù)和訪問(wèn)數(shù)據(jù),就算存在偏差,也是可控的范圍。

②問(wèn)產(chǎn)品,確定一個(gè)什么樣形態(tài)的產(chǎn)品,例如是拼團(tuán),例如是秒殺,各種處理方式都不同。

評(píng)估平均訪問(wèn)量 QPS

一天 86400 秒,一般認(rèn)為請(qǐng)求大部分發(fā)生在白天,就按照 40000 計(jì)算,日平均訪問(wèn)量=日總訪問(wèn)量/40000。

評(píng)估高峰 QPS

可以把之前每日的訪問(wèn)曲線圖拉出來(lái)看看,峰值是根據(jù)業(yè)務(wù)不同而定的,例如,有些業(yè)務(wù)是白天早上 10 點(diǎn)的流量偏多,有些業(yè)務(wù)是晚上人家休閑類(lèi)的流量偏多。

總之,根據(jù)業(yè)務(wù)去估算出日均的峰值,類(lèi)似于電商類(lèi)的服務(wù),一般峰值是日均流量的 5 倍左右。

還有例如一些大促活動(dòng)可能會(huì)更高,這個(gè)都要跟運(yùn)營(yíng)人員提前溝通好的,還有一些活動(dòng)例如,秒殺,這個(gè)就不是靠預(yù)估出來(lái),秒殺是另一種的考慮情況,采取的應(yīng)對(duì)策略跟普通訂單是完全不同。

評(píng)估系統(tǒng),單機(jī)極限 QPS

在上線之前需要跟測(cè)試人員一起做壓力測(cè)試,針對(duì)每個(gè)服務(wù)每臺(tái)機(jī)器去做,一般來(lái)說(shuō),會(huì)把一個(gè)服務(wù)一臺(tái)機(jī)器壓到極限,在逐步的進(jìn)行優(yōu)化。

思考一個(gè)問(wèn)題,假定單臺(tái)機(jī)器最大的 QPS 是 1000,我們峰值是 5000,那需要用多少臺(tái)機(jī)器去抗?答案是大于等于 6 臺(tái),最少的容錯(cuò)不得少于 1 臺(tái)。

貌似一個(gè)非常簡(jiǎn)單的微服務(wù)就差不多了,不過(guò)貌似還是差了很多,數(shù)一下:

  • 監(jiān)控系統(tǒng)哪去了(基礎(chǔ)設(shè)施監(jiān)控,系統(tǒng)監(jiān)控,應(yīng)用監(jiān)控,業(yè)務(wù)監(jiān)控)
  • 網(wǎng)關(guān)哪里去了
  • 統(tǒng)一的異常處理哪里去了
  • API 文檔哪里去了
  • 容器化哪里去了
  • 服務(wù)編排哪里去了
  • ...

[[268438]] 

作者:陳于喆

簡(jiǎn)介:十余年的開(kāi)發(fā)和架構(gòu)經(jīng)驗(yàn),國(guó)內(nèi)較早一批微服務(wù)開(kāi)發(fā)實(shí)施者。曾任職國(guó)內(nèi)互聯(lián)網(wǎng)公司網(wǎng)易和唯品會(huì)高級(jí)研發(fā)工程師,后在創(chuàng)業(yè)公司擔(dān)任技術(shù)總監(jiān)/架構(gòu)師,目前在洋蔥集團(tuán)任職技術(shù)研發(fā)副總監(jiān)。負(fù)責(zé)技術(shù)部門(mén)研發(fā)體系建設(shè),團(tuán)建建設(shè),人才培養(yǎng),推動(dòng)整個(gè)技術(shù)架構(gòu)演進(jìn)以及升級(jí),帶領(lǐng)技術(shù)團(tuán)隊(duì)構(gòu)建微服務(wù)架構(gòu)體系、平臺(tái)架構(gòu)體系、自動(dòng)化運(yùn)維體系。

【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】

 

責(zé)任編輯:武曉燕 來(lái)源: 51CTO技術(shù)棧
相關(guān)推薦

2018-05-03 06:56:43

項(xiàng)目經(jīng)理代碼項(xiàng)目管理

2019-09-09 13:58:07

2020-04-14 10:06:20

微服務(wù)Netflix語(yǔ)言

2019-07-25 09:04:41

Javascript數(shù)組for循環(huán)

2021-09-09 08:02:46

項(xiàng)目Bundleless架構(gòu)

2014-03-18 10:05:37

程序員碼農(nóng)

2023-12-26 18:47:32

2015-08-17 11:02:27

創(chuàng)業(yè)經(jīng)歷

2015-08-07 10:51:00

Android App第一個(gè)

2023-07-23 17:19:34

人工智能系統(tǒng)

2016-05-18 14:50:57

運(yùn)維PortfastAPI

2014-05-26 15:20:13

產(chǎn)品細(xì)節(jié)工匠情懷

2020-06-09 08:19:25

微服務(wù)網(wǎng)站架構(gòu)

2017-12-04 09:26:56

架構(gòu)師碼農(nóng)菜鳥(niǎo)

2012-07-25 09:56:52

編程程序員

2023-01-17 10:12:11

udpTCP端口

2023-10-12 00:07:27

Service單體微服務(wù)

2019-03-06 15:04:35

Google安全WebView

2018-09-21 13:48:14

IT運(yùn)維

2012-07-12 14:35:31

面試經(jīng)歷
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 精品av | 欧美mv日韩mv国产网站91进入 | 成人免费视频一区二区 | 久久国产精品免费一区二区三区 | 亚洲一区二区三区免费在线观看 | 成人黄页在线观看 | 天天综合永久入口 | 成人在线视频免费看 | 夜久久| www.婷婷| 国产精品99久久久久久久久 | 久久在线 | 欧美性受xxxx白人性爽 | 精精久久| 日韩精品在线网站 | 99精品一区二区 | 99在线免费视频 | av黄在线观看 | 黄片毛片 | 国产精品18久久久久久白浆动漫 | 欧美小视频在线观看 | 中文字幕蜜臀av | 日本a视频 | 午夜欧美 | 亚洲v区| 久久久蜜臀国产一区二区 | 看片地址 | 久久久人| 国产高清在线精品 | 国产日韩一区二区 | 亚洲成人激情在线观看 | 久久www免费视频 | 在线一区视频 | 精品产国自在拍 | 伊人网91| 免费毛片网站在线观看 | 成人免费区一区二区三区 | 中文字幕 国产精品 | 古装人性做爰av网站 | 欧美一级黄色片免费观看 | 亚洲精品视频导航 |