★微服務系列
微服務1:微服務及其演進史
微服務2:微服務全景架構
微服務3:微服務拆分策略
微服務4:服務注冊與發現
微服務5:服務注冊與發現(實踐篇)
微服務6:通信之網關
微服務7:通信之RPC
微服務8:通信之RPC實踐篇(附源碼)
微服務9:服務治理來保證高可用
微服務10:系統服務熔斷、限流
微服務11:熔斷、降級的Hystrix實現(附源碼)
微服務12:流量策略
1 微服務的基本流量策略
微服務提供了一些技術來實現對微服務的流量的管理,其中最典型的就是對流量進行拆分和轉發。
具體體現在金絲雀發布(灰度發布)、ABTesting 以及流量染色 等策略方案上。
2 流量策略實現流控的本質
雲原生基礎場景下,如果想要實現流控和調度,需要具備以下幾個條件:
- 請求的流量中,需要附帶某些特征,如流量的請求的Header、Cookies、queryParams等 中帶有某些信息。
- 部署在kubernetes上的服務(svc)的實例(pod),打上版本標簽,如 label: default、label: version1、label:version2 等。
- 在雲原生基礎組件(如 Service-Mesh平台)上對相關的服務配上策略:當請求的流量帶有某些特征(如header中帶有Dep=SO)時,流量路由到對應標簽(如 version = version1 )的服務實例Pod上。
- 不符合條件的路由則默認走到默認版本中(如 version = default)。
所以,流控調度的本質上是通過在流量中攜帶一些特征(如流量的請求的Header、Cookies、queryParams等),而Mesh會根據這些請求的特征進行路由匹配,轉發到對應的帶有某些特征的服務實例上。
未匹配成功的流量則走到默認版本或者給定的具體版本中,從而實現多個版本和跟默認版本的業務隔離的目標。這種模式下,實現 灰度發布、ABTesting 以及流量染色 都是很方便的。

3 流量染色流轉的原理
這邊以Istio 實現的 Service-Mesh為案例
3.1 Istio支持的策略模型

基於上述的策略模型,如果你想配置如下:請求的header 帶有 username = brand 或者 departname = hr 的時候,將流量轉發到服務的v1版本,否着轉發到default版本。
則策略代碼如下:
# 說明:VirtualService 流量染色,根據不同的條件將流量發往不同特征的版本中,假設這邊有default、v1、v2 版本
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: test-service1-vs
spec:
hosts:
- test-service1 # 治理發往test-service1服務的流量
exportTo:
- "."
http: # 加各種路由條件,比如匹配人員、部門進行路由
- match # 用戶匹配 brand,部門匹配 hr 部門時
- headers:
username:
exact: brand
- headers:
departname:
exact: hr
route:
destination:
# todo 匹配條件的流量路由到對應的服務上......
- route:
- destination:
# todo 不匹配條件的流量路由到對應的服務上......
3.2 Kubernetes中服務的部署模式
雲原生基礎平台上的服務遵循如下層級結構,namespace對標應用,svc對標服務。

假設你給你的服務配置了多個版本,比如你發布了default(默認版本)、v1版本。
檢查kubernetes的信息會發現,service保持不變,這個命名為testsvc-admin-default的服務下,對應兩個deployment,兩個pod。
root@xxxxxxxxxxxxxx:~# kubectl -n testsvc-debug get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
testsvc-admin-429mvh 1/1 1 1 18m
testsvc-admin-default 1/1 1 1 142m
root@xxxxxxxxxxxxxx:~# kubectl -n testsvc-debug get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
testsvc-admin-default ClusterIP 172.100.110.220 <none> 80/TCP 142m
root@xxxxxxxxxxxxxx:~# kubectl -n testsvc-debug get pods
NAME READY STATUS RESTARTS AGE
testsvc-admin-429mvh-5b567969b4-nq4zp 2/2 Running 0 17m
testsvc-admin-default-85467f8f79-xzfgz 2/2 Running 0 23m
看看兩個deployment的信息對比,labels中的app屬性一致,version屬性不一致。所以,服務按照同一個app尋址,不同的version進行流量shift的方式進行。
root@xxxxxxxxxxxxxx:~# kubectl -n testsvc-debug get deployment testsvc-admin-default -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "2"
creationTimestamp: "2022-01-14T06:40:22Z"
generation: 2
labels:
app: testsvc-admin-default
appName: testsvc-admin
appType: java
projectName: testsvc-debug
version: default
workspaceName: SPACE_BASIC_SERVE
name: testsvc-admin-default
namespace: testsvc-debug
resourceVersion: "335716111"
uid: 7531a9b3-53eb-475d-ae0b-75df957badb9
root@xxxxxxxxxxxxxx:~# kubectl -n testsvc-debug get deployment testsvc-admin-429mvh -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
creationTimestamp: "2022-01-14T08:45:03Z"
generation: 1
labels:
app: testsvc-admin-default
appName: testsvc-admin
appType: java
projectName: testsvc-debug
version: 429mvh
workspaceName: SPACE_BASIC_SERVE
name: testsvc-admin-429mvh
namespace: testsvc-debug
resourceVersion: "335719639"
uid: 85c0e1f2-b56d-4afc-8c51-ccb887e420b6
現在,envoy的流轉規則有了,服務的特征也有了,完整策略匹配代碼如下:
# 說明:VirtualService 流量染色,根據不同的條件將流量發往不同特征的版本中,假設這邊有default、v1、v2 版本
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: test-svc-vs
spec:
hosts:
- test-svc # 治理發往test-svc服務的流量
exportTo:
- "."
http: # 加各種路由條件,比如匹配人員、部門進行路由
- match # 用戶匹配 brand,部門匹配 hr 人事部時
- headers:
username:
exact: brand
- headers:
departname:
exact: hr
route:
destination:
host: test-svc
subset: v1 # 匹配條件的流量路由到對應的服務的v1版本上
- route:
- destination:
host: test-svc # 剩余的流量走到default版本上
subset: default
3.3 流量的解析和流轉
規則下發之后,envoy存儲在本地,當流量出去的時候,outbound 那邊會做一個判斷。
如果是header中帶上 username = brand 或者 departname = hr ,流量轉發到帶有v1 標簽的pod中,
否則流量轉發到帶有default標簽的pod中。

4 總結
豐富的流量管理策略為我們系統的穩定性,以及流量的多樣化(金絲雀發布、ABTesting、分級擴散流量、流量染色)使用提供了保證。
