天天看點

Go進階訓練營 – 微服務概覽與治理四:多叢集 & 多租戶

為什麼需要多叢集?

L0 服務,一旦故障影響巨大,是以需要保障高可用。

  1. 單一叢集中,多個節點保證可用性,一般采用 N+2 來備援節點。
    • N 通過壓測得出
  2. 出現叢集級别的問題,例如redis叢集出問題了,整個叢集的服務都受影響,是以需要多叢集來保障可用性。每個叢集獨占緩存,帶來更好的性能和備援。
  3. 部署到多個機房,避免單機房故障。

多叢集實作

利用 pass 平台,部署時通過環境變量的形式注入叢集資訊,例如redis cluster資訊,在服務發現注冊的時候,帶入這些元資訊。進而達到多叢集之間的隔離。

多叢集産生的問題

面向各個應用搭建多個叢集,例如給稿件服務提供一個賬号叢集,給遊戲服務提供一個賬号叢集。問題:稿件服務的賬号叢集挂了,對應流量切換遊戲的賬号叢集去,但是遊戲的賬号叢集并沒有稿件的緩存,就會造成 cache hit ratio 下降,DB壓力大。解決:多叢集不區分使用場景,和多節點類似。

多叢集時,會存在多緩存,寫操作時需要更新緩存。可以采用訂閱mysql binlog,廣播到各叢集,清理對應緩存。

多租戶

在一個微服務架構中允許多系統共存是利用微服務穩定性以及子產品化最有效的方式之一,這種方式一般被稱為多租戶(multi-tenancy)。租戶可以是測試,金絲雀釋出,影子系統(shadow systems),甚至服務層或者産品線,使用租戶能夠保證代碼的隔離性并且能夠基于流量租戶做路由決策。

如何解決多套測試環境的問題

背景

測試微服務,是一件很困的事情,在進入dev階段前,每個feature都需要進行單獨的測試。由于服務存在依賴關系,例如feature 1涉及服務A改動,服務A依賴服務B。feature2涉及服務B改動。測試feature 1時,需要保證服務B是穩定版本的。測試期間,有人把服務B更新,用來測試feature 2,進而可能導緻feature 1測試異常。

以前公司的解決方案是,2套測試環境+人為安排測試任務。随着業務複雜,需求多,時間緊,不可能一套測試環境一天内就一個測試同學獨占着,效率太低。再搭建一套測試環境?硬體成本高、維護也困難、硬體環境不同,難以做負載測試,仿真線上真實流量情況。而且,從目前來看,多套測試環境治标不治本。

利用多租戶進行流量隔離

還是剛才的feature。

Go進階訓練營 – 微服務概覽與治理四:多叢集 & 多租戶
  1. feature 1 需要測試時,就部署一個服務

    A-feature-1

    到測試環境,再進行服務注冊時,辨別目前服務為

    A-feature-1

    ,不是A。
  2. 其他服務從注冊中心拉取服務,并以辨別為key,節點數組為value,放到map裡。
  3. 測試同學通過前端設定header:

    test-flag:feature-1

    ,發起請求。
  4. 後端收到請求後,解析header裡的

    test-flag

    ,放入context,服務調用時通過gRPC中繼資料傳遞context裡的

    test-flag

  5. 本次請求的服務調用鍊路中,進行服務調用時,會通過目标服務名+

    test-flag

    ,從本地負載均衡map裡取出對應節點。取不到再通過目标服務名去取,也就是擷取穩定版的服務。

如何進行聯調?

  • 需要聯調的應用打上相同的标簽就可以了

注意事項

  • 應用版本釋出時的資料結構,必須保證向下相容,資料庫采用加新字段,廢棄舊字段,緩存也使用新的key。
  • 測試的時候需要使用不同的測試賬号
  • 注意來自外網的請求中的 header 必須删除,確定安全

如何進行全鍊路壓測

前面提到過,測試環境和生産環境存在差異,導緻壓測資料不準确。那能不能直接在生産環境壓測,但又不影響生産環境業務的正常使用?當然能,使用多租戶的概念即可。

Go進階訓練營 – 微服務概覽與治理四:多叢集 & 多租戶

基于上訴的流量隔離可實作在生産環境壓測,但這樣會影響生産環境的正常業務。可通過影子系統,對基礎設施進行隔離。

  • 需要提前做一些資料初始化的操作,提前進行準備。
  • 壓測時攜帶壓測标簽,将流量自動路由到影子服務進行壓測。
  • 這種方案同樣可以用于灰階發版當中,相對于藍綠釋出,不需要多套叢集。

shadow system

資料庫

  • 在生産環境執行DDL語句時,同步對同一個DB執行個體裡的影子庫執行。影子庫的名字以下劃線開頭(就一個辨別,可自定義)。
  • 使用資料庫時,通過判斷上下文裡的辨別(例如前面的test-flag),通路相應的資料庫。

redis

  • 通過key字首進行隔離,例如壓測的key為下劃線+正常的key。
  • 通過redis的庫(預設16個)進行隔離。

消息隊列

  • 推送消息的時候使用不同的 topic 或者是攜帶一些 metadata 資訊。