軟件系統高可用架構思考

近期在重新評估我們系統的高可用性和彈性擴展能力,因此今天再整理下軟件系統高可用架構方面的內容。重點還是對裏面的一些關鍵點展開說明。

對於高可用整體概述,我在前面專門一篇文章寫過,先做個說明:

高可用性整體概述

對於業務系統的高可用性,實際上包括了高可靠,高性能和高擴展三個方面的內容。而且三方面相互之間還存在相互的依賴和影響關係。

對於三者的關係,我們可以用下圖進行描述。

上圖可以看到高可靠性,高性能和高擴展性三者之間的關係。

  • 對於高可靠性來說,傳統的HA架構,冗餘設計都可以滿足高可靠性要求,但是並不代表系統具備了高可靠性能和可擴展性能力。反過來說,當系統具備了高擴展性的時候,一般我們在設計擴展性的時候都會考慮到同時兼顧冗餘和高可靠,比如我們常說的集羣技術。
  • 對於高性能和高擴展性兩點來說,高擴展性是高性能的必要條件,但是並不是充分條件。一個業務系統的高性能不是簡單的具備擴展能力就可以,而是需要業務系統本身軟件架構設計,代碼編寫各方面都滿足高性能設計要求。
  • 對於高可靠和高性能,兩者反而表現出來一種相互制約的關係,即在高性能支撐的狀態下,往往是對系統的高可靠性形成嚴峻挑戰,也正是這個原因我們會看到類似限流熔斷,SLA服務降級等各種措施來控制異常狀態下的大併發訪問和調用。推薦:高性能、高可用平臺架構的演變過程

早期的軟件系統高可用

軟件基礎架構早期的高可靠性更多是圍繞高可靠性展開的。

簡單來說就是一個軟件系統的部署應該採用HA或集羣部署,整個IT基礎設施架構裏面不應該有任何的單點故障。常見的早期IT部署方式一般爲:

所以你會看到整個高可用實現起來並不複雜,應用中間件可以實現負載均衡集羣具備擴展性,數據庫往往會成爲瓶頸。所以數據庫你也可以採用集羣部署,類似Oracle RAC集羣。通過數據庫集羣來實現數據庫層面的擴展能力。

共享存儲

不論是HA架構,還是數據庫集羣,都可以看到類似SAN共享存儲是關鍵。也就是說必須要有共享存儲才能夠實現HA架構或者集羣架構。在新的分佈式架構下可以看到新的分佈式架構會實現數據庫本身也是分佈式的,多副本存儲,可以直接採用本地磁盤。

應用服務器集羣

一個集羣,如果本身是無狀態的,那麼就很容易上層增加負載均衡設備來實現負載均衡。一個軟件系統中間件集羣,常說的狀態即Session保持。

爲了更好地解決集羣節點本身無狀態的話,可以看到Session保持本身是從集羣節點移出的。要不是在客戶端進行Session保存,要不就是下移到數據庫或Redis庫來保存Session會話信息。其目的都是讓集羣節點本身無狀態化。

高可靠 - 集羣和可擴展

前面已經看到,如果僅僅是高可靠性保障, 實際上是比較簡單的事情。整個IT基礎架構的複雜性實際上是爲了高性能和可擴展,引入了集羣和分佈式架構導致。

對於集羣和分佈式實際兩個概念經常在混淆使用。

在這裏強調下分佈式實際更多會談數據本身的分佈式存儲問題,這個分佈式存儲是和前面集中化共享存儲最大的一個差異點。即數據需要存儲在多個分佈式節點,可以是每個節點都存儲全量(讀寫分離集羣),也可以是每個節點都只存儲部分數據,並採用多副本機制保障數據的高可靠性。

對於集羣更多會在大量請求過來進行請求分發的時候使用,即集羣節點本身也是分佈式的,但是針對的是多個請求的均衡,一般不涉及狀態問題,同時也不會再對單個完整請求進行拆分處理。

CP優先還是AP優先

一個分佈式架構一定會涉及到CAP定律。原因重點還是引入了狀態保持和數據的持久化存儲問題,這個本身就引入了一致性問題需要解決。

對於CP來說一致性優先,那麼數據必須多節點複製同步成功請求才能夠成功,那麼自然就犧牲了高可用性,也就是說一個請求本身可能由於底層多節點數據同步問題,導致請求超時。而對於AP來說或高可用性優化,那麼就容易引入類似髒讀等問題,導致數據不一致性。

分佈式架構的實現往往就在兩者之間進行權衡。比如Zookeeper採用CP一致性優先,而對於微服務註冊中心Eureka則採用AP高可用優先原則。

當應用中間件集羣無狀態化後,實際問題就變成了如何解決數據庫,緩存庫,服務註冊和配置中心本身的分佈式架構和集羣擴展問題。

中心化還是去中心化

在微服務架構下,我們會更多地思考中心化和去中心化的問題。

類似服務註冊中心Eureka則是一個去中心化的架構模式,其控制流和數據流是分離的,即數據流並不會經過註冊中心進行路由分發和中轉。當然註冊中心你本身也要集羣化,類似Eureka可以進行多節點集羣部署,並且實現多個節點之間註冊信息和配置信息的狀態同步。

而對於中心化情況下,往往就有一箇中心化的控制節點來管理多節點之間的狀態和數據同步,即這些數據同步不是節點之間相互複製完成的,而是由控制節點來管理的。

對應到Dubbo註冊中心來看,其集羣中各個節點之間的配置信息和狀態同步則是通過Zookeeper來配合完成的。也就是在一個分佈式架構下,啓用一箇中心化控制節點來完成一致性協調和事務管理等問題。

數據庫-主從,雙主,讀寫分離

對於數據庫本身,首先解決高可用性問題,其次解決性能擴展問題。

對於高可用在前面談到如果存在集中存儲模式實際上簡單採用HA架構就可以解決。那麼在採用本次盤進行存儲的時候就一定涉及到數據庫同步複製。

數據庫基於日誌的同步複製是一個基礎能力。

類似Mysql的雙主數據庫配置,讀寫分離集羣配置等都需要採用到讀寫分離方式實現。這個時候實際上每個節點都存儲的全量數據信息。

主從配置和一對多配置

對於Mysql數據庫你可以採用Dual Master架構解決高可用問題。當然可以可以是雙Master架構+多個讀節點實現讀寫分離來解決數據庫性能和擴展問題。

在數據庫讀取場景佔主要業務場景的時候,這種方法本身可行。實際在實現的時候一般需要在Mysql上架構一個DaaS數據庫中間件來實現SQL解析,路由等關鍵能力。

數據庫Cluster集羣

對於Mysql數據庫本身也有Cluster集羣,但是當前應用場景並不多見,其本身通過Cluster來擴展的性能提升也不明顯。

RAC集羣機制的簡化

一個分佈式數據庫集羣,可以看到最難的就是數據一致性保障,如果多個節點都能夠同時讀寫,那麼這個事務一致性保障是相對難實現的。類似Oracle RAC集羣就採用的這個機制。而當前阿里的PolarDB數據庫集羣實際對這個進行了簡化,即仍然是採用共享存儲(這個共享存儲是分佈式節點進行整合後的共享存儲能力,類似Ceph實現等),但是多節點配置下,僅僅一個節點寫,其它節點僅僅是讀節點。這個可以參考下PolarDB的一些文檔說明。

數據庫拆分

數據庫層面性能擴展另外一個方法就是數據庫拆分,既可以是水平拆分,也可以是垂直拆分。而對於垂直拆分一般就是和當前的微服務架構規劃設計放在一起,不同的微服務可以獨立獨立的數據庫完成拆分工作。

數據庫拆分應該對上層應用訪問透明,因此需要在切片完成的數據庫節點上面架構一個分佈式數據庫訪問中間件,一般我們叫DaaS數據庫即服務中間件。比如Cobar,MyCat等各種開源實現等。

在微服務架構演進下,實際可以看到DaaS反而用得越來越少,其核心原因就是進來減少了跨庫的一些關聯查詢和聚合等SQL操作,而是將類似操作上移到應用層去解決。

負載均衡和分佈式集羣

對於負載均衡來說實際不能算一個分佈式集羣,僅僅是做請求的路由分發工作。當談到分佈式集羣的時候一般就會談到兩個點。

其一是狀態和配置信息在集羣節點的實時同步,其二就是集羣節點的心跳檢查,當節點出現問題的時候要實時從集羣列表中去除掉直到恢復。

當前構建分佈式集羣比較常用的如ZookeeperEtcd等,Dubbo分佈式集羣採用了Zookeeper,而對於Kurbernetes集羣則採用Etcd來構建分佈式集羣管控。但是不論哪種開源實現,類似分佈式鎖,數據一致性保證,軟負載均衡,心跳檢查等都是最核心的基礎能力。

心跳檢查KeepAlive

在前面談Mysql雙主模式的時候,實際本質仍然還是主從模式。其關鍵就是需要實時心跳檢查主節點當前狀態,當心跳檢查出現問題的時候需要能夠及時地將從節點切換爲主節點。這個過程需要自動切換和完成,以提升整體高可用性。

Redis主從到哨兵機制

一個高可用的Redis集羣一般會涉及到6個節點,即三個哨兵節點,三個主從節點。Redis 官方的高可用解決方案

簡單的主從架構下雖然可以實現高可用,但是無法實現在監測到主節點出現問題後自動切換到從節點,也正是這個原因引入了sentinel節點。也就是說sentinel節點做的是類似KeepAlive心跳檢查的事情。

sentinel節點自身也需要高可用,因此這裏至少就需要兩個節點來確保sentinel節點本身的高可用性。那麼爲何要引入三節點?

可以看到當前主流的分佈式架構集羣中,管理節點往往都引入3節點模式。

即當兩個節點的時候,容易出現一種情況:

  • sentinel-A節點監測到master當前可用
  • sentinel-B節點監測到master當前可用

那麼這個時候就出現了矛盾,不清楚聽誰的。因此需要引入更多的一個節點來進行投票,具體是否主從切換聽票數多的。

對於高可用集羣的搭建思路,在這裏還是需要重新進行下總結和梳理。

首先在前面強調了一個點,即集羣節點本身不要存在大量的本地數據或文件存儲,如果存在那麼就需要考慮兩個思路來解決。其一是掛接集中存儲或共享存儲,其二是需要有一個機制來實施實時或準實時的數據或文件同步複製。

其次,對於集羣搭建是否需要統一的出口IP,比如一個浮動VIP地址。實際這裏是可以兩種做法,一個是增加一個軟負載均衡類似HaProxy來提供統一的VIP地址,其次就是不提供VIP地址,那麼在服務提供端或消費端需要配置一個IP地址串。

集羣節點本身也包括兩種類型。

一種是僅僅爲了高可靠性,一種是要進行實際的大流量負載分發。第一種情況往往存在通過心跳檢查來進行主從切換的問題;而第二種情況往往還需要搭配軟負載均衡能力,即管理端對於註冊進入的節點,一方面可以進行負載均衡,一方面又可以通過心跳檢查動態增刪節點。類似k8s的分佈式集羣,自然是需要具備以上兩個方面的能力。

如果你還是採用傳統的負載均衡方式來實現集羣,如果集羣節點存在類似配置文件等有狀態信息的下發你無法很好地完成,其次就是集羣節點持續故障的時候很難做到的自動化的管理能力,比如出現問題後的自動卸載,恢復後的自動掛接等。

即使你使用硬件負載均衡來做大併發請求的路由分發,你仍然需要一個分佈式集羣的管理組件來實現集羣節點的動態管理。比如我們在採用Weblogic的時候,對於整個集羣仍然採用Weblogic Cluster來進行管理,包括節點檢測,服務的部署等。但是對於所有節點又統一配置到硬件負載均衡設備上來提升負載均衡本身的性能。

注:以上內容有部分沒有經過自己實踐驗證,因此內容有差錯可反饋指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章