天天看點

分布式系統關注點——「無狀态」詳解

如果這是第二次看到我的文章,歡迎文末掃碼訂閱我的公衆号(跨界架構師)喲~  >

本文長度為2728字,建議閱讀8分鐘。

堅持原創,每一篇都是用心之作~

前面聊完的2個章節「資料一緻性」和「高可用」其實本質是一個通過提升複雜度讓整體更完善的方式。

接下去我們開始聊一些讓系統更簡單,更容易維護的東西——「易伸縮」,首當其沖的第一篇文章就是「stateless」,也叫「無狀态」。

z哥帶你先來認識一下「狀态」是什麼。

一、初識「狀态」

之前在「負載均衡」的第四篇(分布式系統關注點——做了「負載均衡」就可以随便加機器了嗎?)中提到過一個例子,我們再翻出來一下。

開發Z哥對運維Y弟喊:“Y弟,現在系統好卡,剛上了一波活動,趕緊幫我加幾台機器上去頂一下。”

Y弟回複說:“沒問題,分分鐘搞定”。

然後就發現資料庫的壓力迅速上升,DBA就吼了:“Z哥,你丫的搞什麼呢?資料庫要被你弄垮了”。

然後客服那邊接框也爆炸了,越來越多的使用者說剛登陸後沒多久,操作着就退出了,接着登陸,又退出了,到底還做不做生意了。

這個案例中的問題,産生的根本原因是因為系統中存在着大量「有狀态」的業務處理過程。

「有狀态」和「無狀态」

 N.Wirth曾經在它1984年出版的書中将程式的定義經典的概括為:程式=資料結構+算法。(這個概括也是這本書的書名)

這是一個很有意思的啟發,受它的影響,z哥認為程式做的事情本質就是“資料的移動群組合”,以此來達到我們所期望的結果。而如何移動、如何組合是由“算法”來定的,是以z哥延伸出一個新的定義:資料+算法=成果。

通過程式處理所得到的“成果”其實和你平時生活中完成的任何事情所得到的“成果”是一樣的。任何一個“成果”都是你通過一系列的“行動”将最開始的“原料”進行加工、轉化,最終得到你所期望的“成果”。

分布式系統關注點——「無狀态」詳解

比如,你将常溫的水,通過“倒入水壺”、“通電加熱”等工作後變成了100度的水,就是這樣一個過程。

正如燒水的例子,大多數時候得到一個“成果”往往需要好幾道“行動”才能完成。

分布式系統關注點——「無狀态」詳解

這個時候如果想降低這幾道“行動”總的成本(如:時間)該怎麼辦呢?

自然就是提煉出反複要做的事情,讓其隻做一次。而這個事情在程式中,就是将一部分“資料”放到一個「暫存區」(一般就是本地記憶體),以提供給相關的“行動”共用。 

分布式系統關注點——「無狀态」詳解

但是如此一來,就導緻了需要增加一道關系,以表示每一個“行動”與哪一個「暫存區」關聯。因為在程式裡,“行動”可能是「多線程」的。

這時,這個“行動”就變成「有狀态」的了。

分布式系統關注點——「無狀态」詳解
題外話:共用同一個「暫存區」的多個“行動”所處的環境經常被稱作「上下文」。

我們再來深入聊聊「有狀态」。

「暫存區」裡存的是「資料」,是以可以了解為“有資料”就等價于“有狀态”。

「資料」在程式中的作用範圍分為「局部」和「全局」(對應局部變量和全局變量),是以「狀态」其實也可以分為兩種,一種是局部的「會話狀态」,一種是全局的「資源狀态」。

題外話:因為有些服務端不單單負責運算,還會提供其自身範圍内的「資料」出去,這些「資料」屬于服務端完整的一部分,被稱作「資源」。是以,理論上「資源」可以被每個「會話」來使用,是以是全局的狀态。

本文聊的「有狀态」都指的是「會話狀态」。

與「有狀态」相反的是「無狀态」,「無狀态」意味着每次“加工”的所需的“原料”全部由外界提供,服務端内部不做任何的「暫存區」。并且請求可以送出到服務端的任意副本節點上,處理結果都是完全一樣的。

有一類方法天生是「無狀态」,就是負責表達移動群組合的“算法”。因為它的本質就是:

  1. 接收“原料”(入參)
  2. “加工”并傳回“成果”(出參)

為什麼網上主流的觀點都在說要将方法多做成「無狀态」的呢?

因為我們更習慣于編寫「有狀态」的代碼,但是「有狀态」不利于系統的易伸縮性和可維護性。

在分布式系統中,「有狀态」意味着一個使用者的請求必須被送出到儲存有其相關狀态資訊的伺服器上,否則這些請求可能無法被了解,導緻伺服器端無法對使用者請求進行自由排程(例如雙11的時候臨時加再多的機器都沒用)。

同時也導緻了容錯性不好,倘若保有使用者資訊的伺服器當機,那麼該使用者最近的所有互動操作将無法被透明地移送至備用伺服器上,除非該伺服器時刻與主伺服器同步全部使用者的狀态資訊。

這兩個問題在負載均衡的第四篇(分布式系統關注點——做了「負載均衡」就可以随便加機器了嗎?)中也有提到。

但是如果想獲得更好的伸縮性,就需要盡量将「有狀态」的處理機制改造成「無狀态」的處理機制。

「無狀态」化處理

将「有狀态」的處理過程改造成「無狀态」的,思路比較簡單,内容不多。

首先,狀态資訊前置,豐富入參,将處理需要的資料盡可能都通過上遊的用戶端放到入參中傳過來。

分布式系統關注點——「無狀态」詳解

當然,這個方案的弊端也很明顯:網絡資料包的大小會更大一些。

另外,用戶端與服務端的互動中如果涉及到多次互動,則需要來回傳遞後續服務端進行中所需的資料,以避免需要在服務端暫存。

分布式系統關注點——「無狀态」詳解

這些改造的目的都是為了盡量少出現類似下面的代碼。

func(){

    return i++;

}

而是變成:

func(i){

    return i+1;

}

要更好的做好這個「無狀态」化的工作,依賴于你在架構設計或者項目設計中的合理分層。

盡量将會話狀态相關的處理上浮到最前面的層,因為隻有最前面的層才與系統使用者接觸,如此一來,其它的下層就可以将「無狀态」作為一個普遍性的标準去做。

與此同時,由于會話狀态集中在最前面的層,是以哪怕真的狀态丢失了,重建狀态的成本相對也小很多。

比如三層架構的話,保證BLL和DAL都不要有狀态,代碼的可維護性大大提高。

如果是分布式系統的話,保證那些被服務化的程式都不要有狀态。除了能提高可維護性,也大大有利于做灰階釋出、A/B測試。

題外話:在這裡,提到做分層的目的是為了說明,隻有将IO密集型程式和CPU密集型程式分離,才是通往「無狀态」真正的出路。一旦分離後,CPU密集型的程式自然就是「無狀态」了。

如此也能更好的做「彈性擴容」。因為常見的需要「彈性擴容」的場景一般指的就是CPU負荷過大的時候。

最後,如果前面的都不合适,可以将共享存儲作為降級預案來運用,如遠端緩存、資料庫等。然後當狀态丢失的時候可以從這些共享存儲中恢複。

是以,最理想的狀态存放點。要麼在最前端,要麼在最底層的存儲層。

分布式系統關注點——「無狀态」詳解

總結

任何事物都是有兩面性的,正如前面提到的,我們并不是要所有的業務處理都改造成「無狀态」,而隻是挑其中的一部分。最終還是看“價值”,看“成本效益”。

比如,将一個以“狀态”為核心的即時聊天工具的所有處理過程都改造成「無狀态」的,就有點得不償失了。

相關文章:

  • 分布式系統關注點——初識「高可用」
  • 分布式系統關注點——僅需這一篇,吃透「負載均衡」妥妥的
  • 分布式系統關注點——「負載均衡」到底該如何實施?
  • 分布式系統關注點——做了「負載均衡」就可以随便加機器了嗎?這三招來幫你!
  • 分布式系統關注點——99%的人都能看懂的「熔斷」以及最佳實踐
  • 分布式系統關注點——想通關「限流」?隻要這一篇
  • 分布式系統關注點——讓你的系統“堅挺不倒”的最後一個大招——「降級」
  • 分布式系統關注點——99%的人都能看懂的「補償」以及最佳實踐

作者:Zachary

出處:https://www.cnblogs.com/Zachary-Fan/p/stateless.html

如果你喜歡這篇文章,可以點一下右側的「推薦」。

這樣可以給我一點回報。: )

謝謝你的舉手之勞。

▶關于作者:張帆(Zachary,個人微信号:Zachary-ZF)。堅持用心打磨每一篇高品質原創。歡迎掃描下方的二維碼~。

定期發表原創内容:架構設計丨分布式系統丨産品丨營運丨一些思考。

如果你是初級程式員,想提升但不知道如何下手。又或者做程式員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注我的公衆号「跨界架構師」,回複「技術」,送你一份我長期收集和整理的思維導圖。

如果你是營運,面對不斷變化的市場束手無策。又或者想了解主流的營運政策,以豐富自己的“倉庫”。歡迎關注我的公衆号「跨界架構師」,回複「營運」,送你一份我長期收集和整理的思維導圖。

分布式系統關注點——「無狀态」詳解

繼續閱讀