1. 程式人生 > >2017上海QCon之旅總結(下)

2017上海QCon之旅總結(下)

最終 方式 這場 監控 第一個 -c 感覺 服務端 備份

本來這個公眾號的交流消息中間件相關的技術的。十月去上海參加了QCon,第一次參加這樣的技術會議,感受挺多的,所以整理一下自己的一些想法接公眾號和大家交流一下。

三天的內容還挺多的,之前已經有上篇和中篇,這一片是最後一篇,內容包含以下三個議題:

  • 《攜程第四代架構之軟負載SLB實踐之路》
  • 《恒生中間件如何助理證券經紀業務發展》
  • 《Heron的Exactly-Once實現》

《攜程第四代架構之軟負載SLB實踐之路》

這場分享主要介紹了攜程軟負載的設計和實現。

首先我們先弄清楚什麽是軟負載,然後再來看這篇分享的內容。

這裏的軟負載一詞確切的含義應該是通過軟件進行負載均衡。負載均衡可以通過硬件設備實現,也可以通過軟件實現。而由於硬件成本高,所以往往當系統的量達到一定階段(這個時候堆硬件的成本已經不可以接受了)就會轉向采用軟件進行負載均衡的方式。LVS是業界最著名的軟負載。

回到攜程軟負載的分享中,這場分享主要介紹了攜程遇到的一些問題及解決方案:

  1. 如何設計一個業務開發人員可以使用的軟負載系統?
  2. 如何提供高頻調用且穩定返回的API?
  3. 如何解決多角色運維沖突的問題?
  4. 如何解決心跳檢測的瓶頸問題?
  5. 如何利用好這個絕佳的監控場所?

第一個問題:如何設計一個業務開發人員可以使用的軟負載系統?

攜程對應用進行了抽象,將所有提供統一服務的應用抽象為一個group,group有如下屬性:

  • id
  • domain和path
  • 健康檢測鏈接health-check
  • 機器列表servers

技術分享

這層抽象主要是為了屏蔽掉Nignx的只是壁壘,因此業務人員就不在需要了解Nignx的配置內容。

第二個問題:如何提供高頻調用且穩定返回的API?

這個問題的來源是抽象出來的Group文件的變更合並到配置文件,這些變更導致寫修改配置文件的時間變長的問題。

技術分享

攜程采用了增加隊列,然後合並操作的方式,PPT中稱為偽並發的方式解決Group變更導致的寫入問題。

第三個問題:如何解決多角色運維沖突的問題?

技術分享

這個其實非常簡單的小技巧了,用多個位來標識不同的狀態,最終根據值的結果來提供服務。

因為SLB節點的狀態無非兩種:提供服務 or 不提供服務,這裏只要有一位為1就標識不可提供服務。

第四個問題:如何解決心跳檢測的瓶頸問題?

技術分享

SLB服務器是有限的,遠小於應用數量的,如上圖,隨著應用不斷增加,心跳數據就會成為SLB服務器的一個負擔。

技術分享

攜程的處理方式也非常簡單:將健康檢測模塊單獨抽離出去,且健康檢測模塊也可以水平擴容,這樣解決掉SLB服務端的壓力。

不過這裏隱含著一個問題,其實在網絡環境中去判定一臺機器是否可用是一個非常復雜的問題。

思考一下,如果Checker認為Server1不可用,這個時候可能是Checker本身存在問題或者Checker和Server1之間的網絡存在問題,並不能斷定Server1不可用。

又比如在網絡分區的情況下,可能Checker認為Server1可用,但是其他應用可能無法通過網絡訪問到Server1。

分享現場我提出了這個問題,攜程研發總監王興朝給出的答復是這個問題確實非常復雜,確實通過單checker的方式是無法確定Server狀態的(其實多Checker也很難)。攜程的解決方式是由和應用在同一網段的checker去檢查應用,盡量減少網絡帶來的問題。同時對一些狀態比如5XX、4XX等會做記錄,會有一些人工接入的處理措施。

其實我對這個實現並不是很滿意,因為這個最困難的問題並沒有解決,只是說結合人工去處理了。

第五個問題:如何利用好這個絕佳的監控場所?

這個是一個拓展的話題了,本身SLB是所有流量的入口,所以如何用好這塊做好監控也是值得討論的一個問題。

資料參考搜索2017上海QCon進行下載。


《恒生中間件如何助理證券經紀業務發展》

證券業務其實和平時接觸的互聯網業務相差還是比較大的,不過沖著“中間件”的標題就去聽了這場分享。

這場分享除去一些證券業務背景的介紹,主要分享了一下幾個問題:

  1. 如何將交易狀態返回給客戶端?
  2. 如何讓用戶以最快的速度下單?
  3. 如何縮短券商的清算時間?
  4. 業務開發要快速並且沒有缺陷?

第一個問題:如何將交易狀態返回給客戶端?

技術分享

引用了OSPF算法,在B節點異常的時候,D節點的處理結果可以通過D->C->A的路徑反饋給A。

關於這個算法我並不了解,有興趣可以自己研究下。

第二個問題:如何讓用戶以最快的速度下單?

這塊的解決方案技術含量挺高的,主要考慮到了CPU的親和性、緩存對齊等問題,這些是Java程序員很難考慮到的點(可能99%的程序員也不會考慮到這麽底層的優化)。

第三個問題:如何縮短券商的清算時間?

這個結合了證券業務的特點,在非交易時段機器都是空閑的,恒生中間件利用這個特點在非交易時段使用Docker的方式,更大限度的利用機器資源來做清算,提升效率(也是非常高效的利用機器,非常好的優化點)。

技術分享

第四個問題:業務開發要快速並且沒有缺陷?

技術分享

看到這個的時候還是有點震驚的,恒生把證券業務的場景不斷的固話下來,最終把這些場景的業務都插件化,做業務開發的時候都可以用這種偽代碼的方式(且是中文)來實現。

真的是超出了我原本對業務開發的認知。

這樣在恒生做業務開發的程序員還有加之嗎,以後還找得到工作嗎?答:轉行到券商去,寫代碼這麽累的事就留給別人幹吧:)

這場分享幹貨還是挺多的,特別是優化的實現上的很多小技巧。


《Heron的Exactly-Once實現》

這場分享完全是沖著Exactly-Once去的,但是實際聽下來感覺重點不在Exactly-Once上,更多在他們公司的產品介紹上。

不過借這個題目聊一聊Exactly-Once語義。

Exactly-Once語義更多的是在消息隊列的場景中,比如Kafka就提供了它支持Exactly-Once語義。

在消息隊列中,消息分發的語義(Message Delivery Semantics)有如下幾種:

  • At Most Once:消息可能丟失,但不會重復投遞
  • At Least Once:消息不會丟失,但是可能會重復投遞
  • Exactly Once:消息不丟失、不重復,且只被投遞一次

要弄清楚這些語義,首先先弄清楚消息為什麽會丟失和重復。

技術分享

簡單畫了一下消息的生命周期,

發送流程有三個階段:

  1. Producer向Server寫入消息
  2. Server存儲消息
  3. Server響應Producer寫入結果

消費也有三個階段:

  1. Server將消息投遞給Consumer
  2. Consumer在本地執行消費邏輯
  3. Consumer應答Server自己的消費結果

在上述的步驟中,以下情況都將導致消息丟失或重復:

  • 步驟①超時,此時Producer並不能確定消息是發送成功還是發送失敗
    • 如果Producer選擇重新發送消息,那麽Server可能存儲了兩條相同的消息,即消息重復
    • 如果Producer選擇不發送消息,可能Server一條消息都沒有存儲,那麽消息就丟失了
  • 步驟③的情況和步驟①是完全一致的,如果步驟②可能成功也可能失敗,如果步驟③超時,則Producer也無法確定消息的情況
  • 步驟1超時,此時Server不知道Consumer是否接收到了消息
    • 如果Server重新發一次消息給Consumer,那麽Consumer就會消費兩次
    • 如果Server不發送消息給Consumer,那麽Consumer就可能沒消費到消息
  • 同樣步驟3即響應給Server進度信息,如果超時,情況和步驟1完全一致

上面的流程並不準確,比如消費流程中,可能是收到消息後先ack給服務端,之後再執行消費,即步驟2、3的順序調換。

語義的選擇

  • At Most Once:消息可能丟失,但不會重復投遞
  • At Least Once:消息不會丟失,但是可能會重復投遞
  • Exactly Once:消息不丟失、不重復,且只被投遞一次

三種語義中,At Most Once、At Least Once都比較容易實現,Exactly Once在網絡環境中則是非常困難的。

實際中,我們可能根據業務特點選擇不同的語義支持(說白了是因為做不到支持Exactly Once),比如一些統計類的業務可以接受數據丟失那麽可以選擇At Most Once;而對於不能接受丟失的,采用At Least Once加業務實現冪等消費來支持。

簡單粗暴的支持At Most Once語義的方式即:

  1. 遇到超時則不重發
  2. Consumer在收到數據後先ack進行進度更新,之後再進行消費(如果此時Crash了,下一次則從已經更新的進度開始繼續消費,所以會丟失數據)

對於At Least Once語義支持:

  1. 遇到超時場景就重發
  2. 業務自己實現冪等(重復消費一條消息對業務無影響)
  3. Consumer消費完消息後再ack進度(可能消費完了消息未更新進度,此時Crash下一次獲取的消息是上次消費過的)

Exactly Once

能做到支持Exactly Once嗎?

Exactly Once是理想的消息分發語義(誰不期望消息補充不丟呢),業務方不需要過多的考慮消息的語義。

根據上面的消息生命周期,要實現這個語義,我們需要做哪些事情呢?

  1. 消息發送不重復(或發送重復的消息不會被存儲下來)
  2. 已經發送成功的消息不會丟失
  3. 保證消費時,如果消息被消費了,那麽進度一定被更新;如果消息沒被消費,進度一定不會更新

對於第一步,保證發送不會重復或者重復的消息不會被存儲下來

首先,消息需要唯一的ID,來識別兩條消息是否是同一條消息。

(這裏的唯一ID設計又是一個有趣的問題)

其次,Server端保證冪等,即如果收到的消息的ID相同,過濾掉消息。

這裏涉及Server端需要緩存多久的消息來判斷消息是否重復呢?不能每條消息過來之後把歷史消息遍歷一遍進行判斷吧?

如果消息的ID是連續的會不會有一些幫助?

第二步,保證發送成功的消息不會丟失

這裏涉及到數據的可靠性,一般消息中間件中我們都會對消息進行持久化,即寫入到磁盤中。

然後通過主備或者其它方式來增加數據備份,保證數據可靠性。

第三步,保證消費進度和消費行為一致

在消費之前跟新進度則可能丟失消息;

在消費之後更新進度則可能重復消費;

那就是消費和進度要同時更新!

“保證消費時,如果消息被消費了,那麽進度一定被更新;如果消息沒被消費,進度一定不會更新”——這個描述,很容易想到事務。

這裏可以通過將業務結果和消費進度在一個事務裏面進行保存來達到一致。

比如借助MySQL來存儲業務結果和消費進度(業務結果本身可能就是存在MYSQL中),通過事務保證了如果業務結果存儲成功,那麽進度一定保存成功;業務結果保存失敗,那麽進度也不會保存。

(業務結果沒保存成功自然可以理解為沒有做業務,可以重新消費消息重做業務)。

完成以上步驟,好像可以一定程度上滿足Exactly Once語義。


總結

以上是最後一篇關於2017上海QCon的總結。

3天的QCon之旅,還是收獲挺多的,也認識了一些朋友。如果有機會,去參加一些類似的技術會議,對個人成長還是有一些幫助的。

2017QCon上海站PPT下載:PPT下載

歡迎關註公眾號交流。

技術分享

2017上海QCon之旅總結(下)