除了「加機器」,其實你的微服務(wù)還能這樣優(yōu)化
?生產(chǎn)實踐中,如果遇到業(yè)務(wù)流量變高導致服務(wù)負載升高甚至報警,我們的第一反應往往是「加機器」。
俗話說,能用錢解決的問題都不是問題。
俗話又說,充錢你就能變得更強。
但是,作為一個有理想有抱負的架構(gòu)師,除了「加機器」,其實你的微服務(wù)還能更優(yōu)雅、更精細地進行優(yōu)化。
本文預計閱讀時間 10分鐘,將從以下三個方面展開:
- 從「AKF擴展立方」說起
- Y軸擴展的常用模式
- z軸擴展的思想與應用
1.從「AKF擴展立方」說起
在上一篇文章,我們從「服務(wù)維度」學習架構(gòu)師的常用能力——微服務(wù)設(shè)計與治理。
圍繞著微服務(wù)生命周期的七個階段,總結(jié)了常用的16條原則。
其中原則15在微服務(wù)服務(wù)治理實踐中非常重要,本文將重點進行拆解分析。
原則15:參考「AKF擴展立方」模型,服務(wù)除了「水平擴容」外,還可以考慮「功能拆分」或者 「數(shù)據(jù)分區(qū)」。
所謂AKF擴展立方體(AKF Scale Cube),是一個描述從單體應用到一個分布式可擴展架構(gòu)的模型概念。
- X軸:服務(wù)和數(shù)據(jù)的水平擴容。
- Y軸:功能/業(yè)務(wù)拆分
- Z軸:沿客戶邊界的服務(wù)和數(shù)據(jù)分區(qū)?
「水平擴容」比較容易理解,就是我們常見的操作——加機器。
根據(jù)AKF模型,面對服務(wù)負載升高的情況,其實除了加機器外,我們還可以考慮「功能拆分」或者 「數(shù)據(jù)分區(qū)」。
2.Y軸擴展的常用模式
「Y軸擴展」相對復雜,我總結(jié)了幾種模式:
微服務(wù)拆分。根據(jù)具體業(yè)務(wù)模型、領(lǐng)域模型拆分更細粒度的微服務(wù)。
業(yè)務(wù)隔離拆分。利用消息隊列,將在線業(yè)務(wù)(OLTP)和耗費大量資源的計算任務(wù)拆分隔離。
核心與非核心隔離。對于一個微服務(wù),可以將SKA客戶與普通客戶進行隔離,SKA客戶使用獨立的集群資源,提高穩(wěn)定性。
2.1 微服務(wù)拆分
某個微服務(wù)負載過高,一個非常常見的原因就是這個微服務(wù)承擔了過多的職責。這個時候,我們需要根據(jù)具體業(yè)務(wù)模型、領(lǐng)域模型拆分更細粒度的微服務(wù)。也是我們常說的「垂直拆分」。
最典型的拆分方法論就是按照領(lǐng)域驅(qū)動設(shè)計(DDD)進行拆分。
以電商領(lǐng)域為例,按照領(lǐng)域可以拆分為:
- 用戶服務(wù)
- 商品服務(wù)
- 訂單服務(wù)
- 評價服務(wù)
- 其他
系統(tǒng)按照領(lǐng)域拆分為多個微服務(wù)后,各個微服務(wù)由單獨的團隊負責整個生命周期的維護,單獨部署運行。
這種隔離拆分的方式,能帶來以下優(yōu)勢:
- 提高整體系統(tǒng)的負載能力
- 各個微服務(wù)間具備 獨立擴縮容、故障隔離 等能力。
2.2 耗時任務(wù)隔離拆分
「Y軸擴展」除了按照領(lǐng)域進行服務(wù)拆分之外,另外一種非常重要的拆分方式,是將在線業(yè)務(wù)(OLTP)類型服務(wù)中「耗時任務(wù)」進行隔離拆分。
我們服務(wù)一般會采用Tomcat或者Jetty部署,同時采用同步調(diào)用的方式。以Jetty為例,默認線程池最大線程數(shù)為200。如果請求中有耗時任務(wù),影響了同步請求的RT,那么線程池滿后就會阻塞請求。
正如利特爾法則(Little's law)表述的:在一個穩(wěn)定的系統(tǒng)(L)中,長期的平均顧客人數(shù),等于長期的有效抵達率(λ),乘以顧客在這個系統(tǒng)中平均的等待時間(W);或者,我們可以用一個代數(shù)式來表達:
因此,耗時任務(wù)會顯著提高服務(wù)負載、降低在線業(yè)務(wù)服務(wù)的吞吐能力。
通過引入消息隊列或者任務(wù)隊列框架,我們可以將耗時任務(wù)從在線業(yè)務(wù)服務(wù)中進行隔離拆分。
這種隔離拆分的方式,能帶來以下優(yōu)勢:
- 提高在線服務(wù)的吞吐能力
- 避免耗時任務(wù)影響在線業(yè)務(wù)的穩(wěn)定性。
2.3 核心與非核心隔離拆分
「Y軸擴展」的第三種方式,是將 核心 與 非核心 進行拆分。
比如,我們通常可能會將「核心接口」與「非核心」接口通過一個服務(wù)內(nèi)的不同線程池實現(xiàn)隔離。但是在節(jié)點資源(cpu/內(nèi)存/帶寬等)上并不能實現(xiàn)隔離。
因此,我們可以更進一步,通過集群拆分的形式進行隔離。
通過服務(wù)路由的配置,將核心接口路由到核心集群(一般節(jié)點配置更高),非核心接口路由到非核心集群。
另外,也有saas服務(wù),通常會對SKA客戶做獨立集群,也是類似的邏輯。
其實按用戶拆分隔離跟「數(shù)據(jù)分區(qū)」有一點類似,也可以歸類到「z軸擴展」
這種隔離拆分的方式,能帶來以下優(yōu)勢:
- 精細化提高服務(wù)吞吐能力(針對核心接口、核心客戶)
- 核心業(yè)務(wù)獨享資源,提高核心業(yè)務(wù)穩(wěn)定性
- 避免非核心接口/用戶 影響 核心接口/用戶 的穩(wěn)定性
3.Z軸擴展的思想與應用
Z軸擴展的核心思想,是基于請求者或用戶獨特的需求,進行系統(tǒng)劃分,并使得劃分出來的子系統(tǒng)是相互隔離但又是完整的。
生產(chǎn)實踐中,常用的z軸擴展有兩種應用:
- 單元化架構(gòu)
- 數(shù)據(jù)分區(qū)
3.1 單元化架構(gòu)
單元化架構(gòu)主要關(guān)注的是應用部署、調(diào)用層面的問題。
一個單元,是一個五臟俱全的縮小版全站,它部署了所有微服務(wù)。
但它又不是真正的全站,因為每個單元只能操作一部分數(shù)據(jù)。
從這里我們也能看出,單元化架構(gòu)要求系統(tǒng)必須具備的一項能力——數(shù)據(jù)分區(qū)。
當然,僅把數(shù)據(jù)分區(qū)了還不夠,單元化的另外一個必要條件是,全站所有業(yè)務(wù)數(shù)據(jù)分區(qū)所用的拆分維度和拆分規(guī)則都必須一樣。
一般來說,我們絕大多數(shù)系統(tǒng)都是面向用戶的,按用戶維度對數(shù)據(jù)分區(qū),是一個最佳實踐。
當然,如果是全球化部署的單元化架構(gòu),還需要考慮按照地域進行分區(qū)。
3.2 數(shù)據(jù)分區(qū)
數(shù)據(jù)分區(qū)(shard),即是將全局數(shù)據(jù)按照某一個維度水平劃分開來,每個分區(qū)的數(shù)據(jù)內(nèi)容互不重疊,這也就是數(shù)據(jù)庫「水平拆分」所做的事情。
前面提到了「數(shù)據(jù)分區(qū)」是「單元化」的必要條件,但是「數(shù)據(jù)分區(qū)」還有其他很多場景應用。
最典型的,就是MySQL單機瓶頸后,需要進行「分庫分表」。在服務(wù)中需要引入一些支持數(shù)據(jù)拆分和路由的中間件,如sharding-jdbc、mycat等,在數(shù)據(jù)層面需要配置相應的分片邏輯。
另外,其他數(shù)據(jù)庫的分區(qū)擴展(如redis集群、mongo集群等),也是非常典型的應用場景。
一般包括以下幾種數(shù)據(jù)劃分的方式:
- 數(shù)據(jù)類型(如:業(yè)務(wù)類型)
- 數(shù)據(jù)范圍(如:時間段,用戶 ID)
- 數(shù)據(jù)熱度(如:用戶活躍度,商品熱度)
- 按讀寫分(如:商品描述,商品庫存)
4.小結(jié)
本文從「AKF擴展立方」說起,介紹了提高服務(wù)負載能力的幾種服務(wù)治理方式。
除了X軸擴展(加機器)外,還可以通過Y軸擴展(功能/業(yè)務(wù)拆分)、Z軸擴展(數(shù)據(jù)分區(qū))等方式,更優(yōu)雅、更精細地進行優(yōu)化。?