對于高可用性實際應該包括了高可靠性,高性能和高擴展性。因此談微服務架構(gòu)的高可用性,首先需要梳理三者之間的關(guān)系。
高可用性三個維度和相互關(guān)系
對于業(yè)務系統(tǒng)的高可用性,實際上包括了高可靠,高性能和高擴展三個方面的內(nèi)容。而且三方面相互之間還存在相互的依賴和影響關(guān)系。
對于三者的關(guān)系,我們可以用下圖進行描述。

上圖可以看到高可靠,高性能和高擴展性三者之間的關(guān)系。
對于高可靠性來來說,傳統(tǒng)的HA架構(gòu),冗余設計都可以滿足高可靠性要求,但是并不代表系統(tǒng)具備了高性能和可擴展性能力。反過來說,當系統(tǒng)具備了高擴展性的時候,一般我們在設計擴展性的時候都會考慮到同時兼顧冗余和高可靠,比如我們常說的集群技術(shù)。
對于高性能和高擴展性兩點來說,高擴展性是高性能的必要條件,但是并不是充分條件。一個業(yè)務系統(tǒng)的高性能不是簡單的具備擴展能力就可以,而是需要業(yè)務系統(tǒng)本身軟件架構(gòu)設計,代碼編寫各方面都滿足高性能設計要求。
對于高可靠和高性能,兩者反而表現(xiàn)出來一種相互制約的關(guān)系,即在高性能支撐的狀態(tài)下,往往是對系統(tǒng)的高可靠性形成嚴峻挑戰(zhàn),也正是這個原因我們會看到類似限流熔斷,SLA服務降級等各種措施來控制異常狀態(tài)下的大并發(fā)訪問和調(diào)用。
數(shù)據(jù)庫的高可用性
在我前面談微服務架構(gòu)的時候就談到,在微服務架構(gòu)下傳統(tǒng)的單體應用要進行拆分,這個拆分不僅僅是應用層組件的拆分,還包括了數(shù)據(jù)庫本身的拆分。
如果一個傳統(tǒng)的單體應用規(guī)劃為10個微服務,則可能會垂直拆分為10個獨立的數(shù)據(jù)庫。這實際上減小了每一個數(shù)據(jù)庫本身面對的性能負荷,同時提升了數(shù)據(jù)庫整體的處理能力。
同時在拆分后雖然引入了各種跨庫查詢,分布式事務等問題,但是實際很多跨庫操作,復制的數(shù)據(jù)處理計算都不在數(shù)據(jù)庫里面完成,數(shù)據(jù)庫更多的是提供單純的CRUD類操作接口,這本身也是提升數(shù)據(jù)庫性能的一個關(guān)鍵。
如果采用Mysql數(shù)據(jù)庫。
要滿足高可靠性,你可以采用Dual-Master雙主架構(gòu),即兩個主節(jié)點雙活,但是僅一個節(jié)點提供數(shù)據(jù)庫接口能力,另外一個節(jié)點實時同步數(shù)據(jù)庫日志,作為備節(jié)點。當主節(jié)點出現(xiàn)故障的時候,備節(jié)點自動轉(zhuǎn)變?yōu)橹鞴?jié)點服務。
簡單的雙主架構(gòu)兩節(jié)點間安裝代理,通過Binlog日志復制,上層通過類似Haproxy+Keepalive實現(xiàn)通過的VIP浮動IP提供和心跳監(jiān)測。
可以看到雙主架構(gòu)更多的是為高可靠服務。
如果要滿足高性能,常采用的是讀寫分離集群。即1個主節(jié)點承擔讀寫操作,多個從節(jié)點承擔讀操作。從節(jié)點仍然是通過Binlog日志進行主節(jié)點信息同步。當有數(shù)據(jù)訪問請求進入的時候,前端Proxy可以自動分析是CUD類請求,還是R讀請求,以進行請求的路由轉(zhuǎn)發(fā)。
當我們進行訂單新增操作的時候,當新增成功的時候需要快速的刷新當前訂單列表界面,第二次的刷新本身是讀操作,但是和前面的寫綁定很緊,實際上不太適合從Slave節(jié)點讀取數(shù)據(jù)的。這個時候可以在進行Sql調(diào)用的時候明確指定是否仍然從主節(jié)點獲取數(shù)據(jù)。
當然,大部分時候可能需要兩者結(jié)合,既提供足夠的高可靠性,又提供足夠的高性能。因此Mysql集群在搭建的時候既需要進行雙主設置,又需要進行多個從節(jié)點設置。

在上圖這種邏輯部署架構(gòu)下,基本就可以同時滿足高可靠和高性能兩個方面的需求。但是從上面架構(gòu)部署可以看到,備節(jié)點的主和從都處于一種熱備無法實際提供能力狀態(tài)。
是否可以將所有Slave掛到一個Master上?
如果這樣設計,那么當主Master出現(xiàn)故障的時候,就需要對多個Slave節(jié)點進行自動化漂移。這一方面是整體實現(xiàn)比較復雜,另外就是可靠性也不如上面這種架構(gòu)。
對數(shù)據(jù)庫性能擴展的思考
首先來看前面架構(gòu)本身的一些潛在問題點:
第一就是CUD操作仍然是單節(jié)點提供能力。對于讀操作占大部分場景的,基本可以通過雙主+讀寫分離集群實現(xiàn)很好的性能擴展。但是如果CUD操作頻繁仍然可能出現(xiàn)性能問題。
其次,數(shù)據(jù)庫性能問題一般分為兩個層面,其一就是大并發(fā)請求下的性能,這個可以通過集群負載均衡去解決,其二是單個請求訪問大數(shù)據(jù)庫表模糊查詢性能,這個是服務通過負載去解決的。
也就是說上面的設計,在大并發(fā)的CUD操作,對大數(shù)據(jù)表的關(guān)聯(lián)查詢或模糊查詢操作仍然可能出現(xiàn)明顯的性能問題。
如何來解決這個問題?

簡單來說就是寫入通過消息中間件來將同步轉(zhuǎn)異步,進行前端削峰。而對于查詢則進行內(nèi)容緩存或創(chuàng)建二級索引,提升查詢效率。
對于查詢本身又包括了偏結(jié)構(gòu)化數(shù)據(jù)查詢和處理,類似采用Redis庫或Memcached進行緩存;而對于非結(jié)構(gòu)化數(shù)據(jù),類似消息報文,日志等采用Solr或ElasticSearch構(gòu)建二級索引并實現(xiàn)全文檢索能力。
當面臨大量的數(shù)據(jù)寫入操作類操作的時候,單個Master節(jié)點往往性能很難支撐住,這個時候采用類似RabbitMQ,RocketMQ,Kafka等消息中間件來進行異步銷峰處理就是必要的。這個異步實際上涉及到兩個層面的異步。
其一是對于發(fā)短信,記錄日志,啟流程等接口服務異步。其二是對長耗時寫入操作異步,先反饋用戶請求收到,處理完再通知用戶拿結(jié)果。
而對于查詢操作,前面談到的并發(fā)查詢可以進行集群負載。
但是對于大數(shù)據(jù)量表,比如上億記錄的大表模糊查詢,這塊就必須進行二級索引。對這種大的數(shù)據(jù)表的查詢即使沒有并發(fā)查詢,如果不進行二級索引,查詢效率和響應速度仍然很慢。
對半結(jié)構(gòu)化信息啟用分布式存儲

對于類似日志,接口服務調(diào)用日志等半結(jié)構(gòu)化信息,本身數(shù)據(jù)量很大,如果全部存儲在結(jié)構(gòu)化數(shù)據(jù)庫中,那么對存儲空間需求很大,而且很難擴展。特別是前面的Mysql集群方案本身還是采用本地磁盤進行存儲的情況下。
因此需要對歷史日志進行清除,同時將歷史日志遷移到分布式存儲庫,比如Hdfs或Hbase庫,然后基于分布式存儲再構(gòu)建二級緩存能力。
構(gòu)建DaaS數(shù)據(jù)層進行水平擴展

前面談到在拆分了微服務后已經(jīng)進行了垂直擴展,比如一個資產(chǎn)管理系統(tǒng)可以拆分為資產(chǎn)新增,資產(chǎn)調(diào)撥,資產(chǎn)折舊,資產(chǎn)盤點等10個微服務模塊。
但是在拆分后仍然發(fā)現(xiàn)資產(chǎn)數(shù)據(jù)量極大,比如在集團集中化這種大型項目可以看到,一個省的資產(chǎn)數(shù)據(jù)表就接近上億條記錄。這種時候?qū)⑺惺?shù)據(jù)全部集中化在一個數(shù)據(jù)庫管理不現(xiàn)實。因此需要進一步按省份或組織域進行水平拆分。
在水平拆分后,在上層構(gòu)建DaaS層提供統(tǒng)一對外訪問能力。
應用集群擴展
對于應用集群擴展實際比數(shù)據(jù)庫層要簡單,應用中間件層可以很方便的結(jié)合集群管理節(jié)點或者獨立的負載均衡硬件或軟件進行集群能力擴展。對于應用集群擴展,本身就是提升整個性能的關(guān)鍵方式。在集群的擴展過程中還是有些問題需要進一步討論。
集群做到完全的無狀態(tài)化
如果集群做到完全的無狀態(tài)化,那么集群就可以做到和負載均衡設備或軟件結(jié)合來實現(xiàn)負載均衡擴展能力。比如硬件常用的F5或radware等,軟件如HAProxy,Nginx等。
Session會話信息如何處理?對于Session本身是有狀態(tài)的,因此對于Session信息可以考慮存儲到數(shù)據(jù)庫或Redis緩存庫中。
集群節(jié)點在啟動的時候往往需要讀取一些全局變量或配置文件信息,這些信息如果簡單的存在在本地磁盤往往難以集中化管理。因此當前主流思路是啟用全局的配置中心來統(tǒng)一管理配置。
如果應用功能實現(xiàn)中存在文件的上傳和存儲,那么這些文件存儲在磁盤本地本身也是有狀態(tài)的,因此對于這些文件本身也需要通過文件服務能力或分布式對象存儲服務能力來實現(xiàn)。
微服務架構(gòu)下各個微服務間本身存在接口交互和協(xié)同,對于接口調(diào)用的具體地址信息也需要通過服務注冊中心獲取,獲取后可以緩存在本地,但是必須有變更后實時更新機制。
四層負載和七層負載

首先看下最簡單的四層負載和七層負載的一個說明:
- 四層負載:即在OSI第4層工作,就是TCP層,可以根據(jù)IP+端口進行負載均衡。此種Load Balance不理解應用協(xié)議(如HTTP/FTP/MySQL等等)。
- 七層負載:工作在OSI的最高層,應用層,可以基于Http協(xié)議和URL內(nèi)容進行負載均衡。此時負載均衡能理解應用協(xié)議。
當前可以看到對于F5,Array等硬件負載均衡設備本身也是支持7層負載均衡的,同時在四層負載均衡的時候我們還可以設置是否進行會話保持等高級特性。要明白四層負載均衡本質(zhì)是轉(zhuǎn)發(fā),而七層負載本質(zhì)是內(nèi)容交換和代理。
也就是說在不需要進行狀態(tài)保留和基于內(nèi)容的路由的時候,我們完全可以啟用四層負載均衡來獲取更好的性能。
在微服務架構(gòu)前后端分離開發(fā)后。
后端微服務組件可以完全提供Rest API接口服務能力,那么本身就無狀態(tài)。而對于前端微服務組件直接面對最終用戶訪問,需要保持Session狀態(tài)。在這種情況下就可以進行兩層負載均衡設計,即前端采用七層負載,而后端采用四層負載均衡。
前端緩存
前端緩存主要是分為HTTP緩存和瀏覽器緩存。其中HTTP緩存是在HTTP請求傳輸時用到的緩存,主要在服務器代碼上設置;而瀏覽器緩存則主要由前端開發(fā)在前端js上進行設置。緩存可以說是性能優(yōu)化中簡單高效的一種優(yōu)化方式了。一個優(yōu)秀的緩存策略可以縮短網(wǎng)頁請求資源的距離,減少延遲,并且由于緩存文件可以重復利用,還可以減少帶寬,降低網(wǎng)絡負荷。
具體可以參考:
https://www.jianshu.com/p/256d0873c398
軟件性能問題分析和診斷

對于業(yè)務系統(tǒng)性能診斷,如果從靜態(tài)角度我們可以考慮從以下三個方面進行分類
- 操作系統(tǒng)和存儲層面
- 中間件層面(包括了數(shù)據(jù)庫,應用服務器中間件)
- 軟件層面(包括了數(shù)據(jù)庫SQL和存儲過程,邏輯層,前端展現(xiàn)層等)
那么一個業(yè)務系統(tǒng)應用功能出現(xiàn)問題了,我們當然也可以從動態(tài)層面來看實際一個應用請求從調(diào)用開始究竟經(jīng)過了哪些代碼和硬件基礎設施,通過分段方法來定位和查詢問題。
比如我們常見的就是一個查詢功能如果出現(xiàn)問題了,首先就是找到這個查詢功能對應的SQL語句在后臺查詢是否很慢,如果這個SQL本身就慢,那么就要優(yōu)化優(yōu)化SQL語句。如果SQL本身快但是查詢慢,那就要看下是否是前端性能問題或者集群問題等。
軟件代碼的問題往往是最不能忽視的一個性能問題點
對于業(yè)務系統(tǒng)性能問題,我們經(jīng)常想到的就是要擴展數(shù)據(jù)庫的硬件性能,比如擴展CPU和內(nèi)存,擴展集群,但是實際上可以看到很多應用的性能問題并不是硬件性能導致的,而是由于軟件代碼性能引起的。對于軟件代碼常見的性能問題我在以往的博客文章里面也談過到,比較典型的包括了。
- 循環(huán)中初始化大的結(jié)構(gòu)對象,數(shù)據(jù)庫連接等
- 資源不釋放導致的內(nèi)存泄露等
- 沒有基于場景需求來適度通過緩存等方式提升性能
- 長周期事務處理耗費資源
- 處理某一個業(yè)務場景或問題的時候,沒有選擇最優(yōu)的數(shù)據(jù)結(jié)構(gòu)或算法
以上都是常見的一些軟件代碼性能問題點,而這些往往需要通過我們進行Code Review或代碼評審的方式才能夠發(fā)現(xiàn)出來。因此如果要做全面的性能優(yōu)化,對于軟件代碼的性能問題排查是必須的。
其次就是可以通過APM性能監(jiān)控工具來發(fā)現(xiàn)性能問題。
傳統(tǒng)模式下,當出現(xiàn)CPU或內(nèi)存滿負荷的時候,如果要查找到具體是哪個應用,哪個進程或者具體哪個業(yè)務功能,哪個sql語句導致的往往并不是容易的事情。在實際的性能問題優(yōu)化中往往也需要做大量的日志分析和問題定位,最終才可能找到問題點。
而通過APM可以很好的解決這個問題。
比如在我們最近的項目實施中,結(jié)合APM和服務鏈監(jiān)控,我們可以快速的發(fā)現(xiàn)究竟是哪個服務調(diào)用出現(xiàn)了性能問題,或者快速的定位出哪個SQL語句有驗證的性能問題。這個都可以幫助我們快速的進行性能問題分析和診斷。
資源上承載的是應用,應用本身又包括了數(shù)據(jù)庫和應用中間件容器,同時也包括了前端;在應用之上則是對應到具體的業(yè)務功能。因此APM一個核心就是要將資源-》應用-》功能之間進行整合分析和銜接。通過APM來發(fā)現(xiàn)應用運行中的性能問題并解決。
原文鏈接:https://www.toutiao.com/a6903759514290405899/