您好,登錄后才能下訂單哦!
如果這是第二次看到我的文章,歡迎文末掃碼訂閱我個人的公眾號(跨界架構師)喲~
本文長度為2728字,建議閱讀8分鐘。
堅持原創,每一篇都是用心之作~
前面聊完的2個章節「數據一致性」和「高可用」其實本質是一個通過提升復雜度讓整體更完善的方式。
接下去我們開始聊一些讓系統更簡單,更容易維護的東西——「易伸縮」,首當其沖的第一篇文章就是「stateless」,也叫「無狀態」。
z哥帶你先來認識一下「狀態」是什么。
之前在「負載均衡」的第四篇(分布式系統關注點——做了「負載均衡」就可以隨便加機器了嗎?)中提到過一個例子,我們再翻出來一下。
開發Z哥對運維Y弟喊:“Y弟,現在系統好卡,剛上了一波活動,趕緊幫我加幾臺機器上去頂一下。”
Y弟回復說:“沒問題,分分鐘搞定”。
然后就發現數據庫的壓力迅速上升,DBA就吼了:“Z哥,你丫的搞什么呢?數據庫要被你弄垮了”。
然后客服那邊接框也爆炸了,越來越多的用戶說剛登陸后沒多久,操作著就退出了,接著登陸,又退出了,到底還做不做生意了。
這個案例中的問題,產生的根本原因是因為系統中存在著大量「有狀態」的業務處理過程。
N.Wirth曾經在它1984年出版的書中將程序的定義經典的概括為:程序=數據結構+算法。(這個概括也是這本書的書名)
這是一個很有意思的啟發,受它的影響,z哥認為程序做的事情本質就是“數據的移動和組合”,以此來達到我們所期望的結果。而如何移動、如何組合是由“算法”來定的,所以z哥延伸出一個新的定義:數據+算法=成果。
通過程序處理所得到的“成果”其實和你平時生活中完成的任何事情所得到的“成果”是一樣的。任何一個“成果”都是你通過一系列的“行動”將最開始的“原料”進行加工、轉化,最終得到你所期望的“成果”。
比如,你將常溫的水,通過“倒入水壺”、“通電加熱”等工作后變成了100度的水,就是這樣一個過程。
正如燒水的例子,大多數時候得到一個“成果”往往需要好幾道“行動”才能完成。
這個時候如果想降低這幾道“行動”總的成本(如:時間)該怎么辦呢?
自然就是提煉出反復要做的事情,讓其只做一次。而這個事情在程序中,就是將一部分“數據”放到一個「暫存區」(一般就是本地內存),以提供給相關的“行動”共用。
但是如此一來,就導致了需要增加一道關系,以表示每一個“行動”與哪一個「暫存區」關聯。因為在程序里,“行動”可能是「多線程」的。
這時,這個“行動”就變成「有狀態」的了。
題外話:共用同一個「暫存區」的多個“行動”所處的環境經常被稱作「上下文」。
我們再來深入聊聊「有狀態」。
「暫存區」里存的是「數據」,所以可以理解為“有數據”就等價于“有狀態”。
「數據」在程序中的作用范圍分為「局部」和「全局」(對應局部變量和全局變量),因此「狀態」其實也可以分為兩種,一種是局部的「會話狀態」,一種是全局的「資源狀態」。
題外話:因為有些服務端不單單負責運算,還會提供其自身范圍內的「數據」出去,這些「數據」屬于服務端完整的一部分,被稱作「資源」。所以,理論上「資源」可以被每個「會話」來使用,因此是全局的狀態。
本文聊的「有狀態」都指的是「會話狀態」。
與「有狀態」相反的是「無狀態」,「無狀態」意味著每次“加工”的所需的“原料”全部由外界提供,服務端內部不做任何的「暫存區」。并且請求可以提交到服務端的任意副本節點上,處理結果都是完全一樣的。
有一類方法天生是「無狀態」,就是負責表達移動和組合的“算法”。因為它的本質就是:
接收“原料”(入參)
“加工”并返回“成果”(出參)
為什么網上主流的觀點都在說要將方法多做成「無狀態」的呢?
因為我們更習慣于編寫「有狀態」的代碼,但是「有狀態」不利于系統的易伸縮性和可維護性。
在分布式系統中,「有狀態」意味著一個用戶的請求必須被提交到保存有其相關狀態信息的服務器上,否則這些請求可能無法被理解,導致服務器端無法對用戶請求進行自由調度(例如雙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)。堅持用心打磨每一篇高質量原創。歡迎掃描下方的二維碼~。
定期發表原創內容:架構設計丨分布式系統丨產品丨運營丨一些思考。
如果你是初級程序員,想提升但不知道如何下手。又或者做程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注我的公眾號「跨界架構師」,回復「技術」,送你一份我長期收集和整理的思維導圖。
如果你是運營,面對不斷變化的市場束手無策。又或者想了解主流的運營策略,以豐富自己的“倉庫”。歡迎關注我的公眾號「跨界架構師」,回復「運營」,送你一份我長期收集和整理的思維導圖。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。