淺析ServiceMesh和Istio,你學(xué)會了嗎?
1、什么是ServiceMesh?
1.1、從單體到分布式
從后臺服務(wù)發(fā)展之初,其實一直面臨一個問題,就是如何將多臺服務(wù)器組成一個整體提供對外服務(wù)。畢竟單體服務(wù)功能單一,在發(fā)展前期已經(jīng)滿足各種需求,但是隨著互聯(lián)網(wǎng)的發(fā)展,服務(wù)類型越來越多,也越來越復(fù)雜,如果用單體架構(gòu)思考,就會發(fā)現(xiàn)越來越難滿足需求。為了解決這個問題,于是出現(xiàn)了分布式架構(gòu),將單體服務(wù)拆分成多個子服務(wù),每個子服務(wù)負(fù)責(zé)不同的功能,然后通過網(wǎng)關(guān)組合子服務(wù),對外提供服務(wù)??此七@樣已經(jīng)解決了單體服務(wù)的問題,但是隨著子服務(wù)的增多,網(wǎng)關(guān)也會越來越復(fù)雜,而且每個子服務(wù)都需要單獨維護(hù),服務(wù)治理就變得非常復(fù)雜。為了解決這里復(fù)雜性,因此引入各種架構(gòu)概念:
- 用遠(yuǎn)程調(diào)用代替子服務(wù)之間的通信,統(tǒng)一管理通訊協(xié)議;
- 用服務(wù)發(fā)現(xiàn)代替子服務(wù)的注冊,統(tǒng)一管理服務(wù)地址;
- 引入服務(wù)治理組件,統(tǒng)一管理子服務(wù);
- 引入旁路負(fù)載均衡,統(tǒng)一管理流量管理;...
1.2、微服務(wù)架構(gòu)
分布式架構(gòu)下將單獨服務(wù)拆分成子服務(wù),結(jié)合各種架構(gòu)設(shè)計已經(jīng)將分布式基石做好了,但是在業(yè)務(wù)層的架構(gòu)設(shè)計上,還是有很多問題需要解決,比如子服務(wù)更新如何不影響全局,功能迭代如何足夠快,如何細(xì)粒度的監(jiān)控某些服務(wù)狀態(tài)等。為了解決這些問題,于是出現(xiàn)了微服務(wù)架構(gòu),將業(yè)務(wù)從粒度上變成更加輕量,每個服務(wù)負(fù)責(zé)更小的業(yè)務(wù),這樣就可以更快的迭代,更細(xì)粒度的監(jiān)控服務(wù)狀態(tài)等。
1.3、ServiceMesh
雖然分布式基石做好了,微服務(wù)架構(gòu)已經(jīng)能解決業(yè)務(wù)層發(fā)展的一些問題,但是對于工程師來說,關(guān)心底層通訊協(xié)議,服務(wù)發(fā)現(xiàn),負(fù)載均衡等這些細(xì)節(jié),似乎有些繁瑣,就如同使用Linux一樣,如果開發(fā)者還需要關(guān)注什么是文件還是網(wǎng)絡(luò)(在Linux中,一切皆文件),那對于負(fù)擔(dān)太重了。于是隨著Docker和K8S的發(fā)展,ServiceMesh 應(yīng)運而生,作為云原生下的服務(wù)間通訊的中間件,屏蔽了底層通訊協(xié)議,服務(wù)發(fā)現(xiàn),負(fù)載均衡等細(xì)節(jié),讓開發(fā)者只需要關(guān)注業(yè)務(wù)邏輯。
ServiceMesh架構(gòu)圖
發(fā)展最早的是Linkerd,通過 Sidecar 模式托管服務(wù)間的網(wǎng)絡(luò)調(diào)用和調(diào)度,不過由于性能問題被開源社區(qū)放棄;第二代是由google發(fā)展的 Istio,重新開發(fā)了 Envoy 作為網(wǎng)關(guān),將系統(tǒng)定義為數(shù)據(jù)面和控制面,數(shù)據(jù)面負(fù)責(zé)網(wǎng)絡(luò)通訊和負(fù)載均衡,控制面負(fù)責(zé)服務(wù)治理,下面將詳細(xì)介紹其架構(gòu)和設(shè)計方式。
2、ServiceMesh 的開源實現(xiàn):Istio
ServiceMesh有一些開源項目,其當(dāng)前最流行是Google開源實現(xiàn)是 Istio,在2018年10月開源,目前已經(jīng)發(fā)展到了1.2版本,其github地址為:
https://github.com/istio/istio
2.1、Istio架構(gòu)圖
Istio架構(gòu)圖如下:
Istio架構(gòu)圖
提供的功能:
- 針對HTTP,gRPC,WebSocket和TCP協(xié)議提供負(fù)載均衡;
- 精細(xì)的流量控制,比如A/B測試,金絲雀部署等;
- 模塊化的插件設(shè)計,可以通過API進(jìn)行訪問,頻率限制等;
- 全自動的請求遙測,包括請求的追蹤,監(jiān)控和日志;
- 強大的安全功能,比如認(rèn)證,授權(quán),加密等;
2.2、Istio數(shù)據(jù)面
可以看到架構(gòu)圖上,每個服務(wù)都有一個sidecar,也就是 Envoy,這個就是數(shù)據(jù)面,負(fù)責(zé)服務(wù)間通訊和負(fù)載均衡。所有進(jìn)入服務(wù)的請求都經(jīng)過 Envoy,然后根據(jù)路由規(guī)則轉(zhuǎn)發(fā)到相應(yīng)的服務(wù),所以 Envoy 被稱為服務(wù)網(wǎng)格的入口。Envoy 架構(gòu)圖如下:
Envoy
當(dāng)然,Envoy 并不是唯一的數(shù)據(jù)面,還有 Linkerd,Kuma 等,但是Envoy 性能比較好,所以目前使用最多。
2.3、Istio控制面
控制面負(fù)責(zé)服務(wù)治理,比如路由規(guī)則,安全策略等,是服務(wù)網(wǎng)格的控制核心,通過控制面,可以配置服務(wù)網(wǎng)格中各個組件的行為。為了結(jié)構(gòu)化控制面的功能,Istio 將其分為Pilot,Mixer,Citadel組件,其各個部分對應(yīng)的功能:
- Pilot:負(fù)責(zé)服務(wù)發(fā)現(xiàn),負(fù)載均衡,路由規(guī)則等,不過Pilot不提供服務(wù)注冊,只提供標(biāo)準(zhǔn)化的接口,可以方便的對接到各個服務(wù)注冊中心,比如Eureka,Etcd等,然后通過服務(wù)發(fā)現(xiàn)控制Envoy的動態(tài)轉(zhuǎn)發(fā)能力;
- Mixer:負(fù)責(zé)訪問控制,策略執(zhí)行等,在最初的Istio的架構(gòu)設(shè)計中,Mixer是中心化的組件,由于Mixer提供了各種訪問控制策略,所以Mixer的負(fù)載壓力比較大,發(fā)起請求之前做一次邏輯檢查,請求結(jié)束后還需要上報處理,Mixer接收的請求至少漲了原始請求的2倍。為了解決這個問題,Mixer增加了緩存的功能,邏輯處理和上報都由Mixer緩存完成,這樣Mixer的負(fù)載壓力就能緩解;
- Citadel:負(fù)責(zé)安全功能,比如認(rèn)證授權(quán)等,比如那些服務(wù)安全級別比較高,需要對請求做單獨的加密處理或者角色控制,Istio 通過引入Citadel組件,將安全能力透明化;
2.4、詳解 Envoy
Envoy是專為大型現(xiàn)代SOA(面向服務(wù)架構(gòu))設(shè)計的、用C++11開發(fā)的代理和通信總線,作為服務(wù)網(wǎng)格中的數(shù)據(jù)面,負(fù)責(zé)服務(wù)間通訊和負(fù)載均衡。開源地址:https://github.com/envoyproxy/envoy.git
(1)編譯編譯依賴:
- C++11
- bazel
git clone https://github.com/envoyproxy/envoy.git
cd envoy
bazel build //source/exe:envoy-static
(2)配置Envoy的配置文件為 yaml 格式,其配置文件分為兩部分:
- 靜態(tài)配置:在啟動時加載,后續(xù)不會變化;
- 動態(tài)配置:在運行時加載,可以調(diào)用API動態(tài)修改;
- 樣例配置文件:
admin: # 監(jiān)控配置
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 9901 # 監(jiān)聽的端口
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000 # 監(jiān)聽的端口
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager # 過濾器名稱
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: www.envoyproxy.io
cluster: service_envoyproxy_io
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: service_envoyproxy_io
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_envoyproxy_io
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.envoyproxy.io
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: www.envoyproxy.io
(3)服務(wù)啟動和測試
./envoy -c envoy.yaml
curl -v localhost:10000
# 返回數(shù)據(jù)
TODO:
(4)Envoy架構(gòu)
圖片
Envoy包括幾個部分:
- listeners:監(jiān)聽器,負(fù)責(zé)監(jiān)聽端口,接收請求,比如上述的配置文件中監(jiān)聽10000端口;
- filter Chains:過濾器鏈,可以在配置文件配置對于請求的處理鏈路,可以在任何一個套接字上,按我們的需要去拼接多個過濾器,來實現(xiàn)對流量的、不同功能的處理,比如上述的配置文件中的過濾器鏈,在監(jiān)聽器上添加了 HttpConnectionManager 過濾器,這個過濾器負(fù)責(zé)解析HTTP協(xié)議;
- cluster defintios:設(shè)置轉(zhuǎn)發(fā)到下游的upsteam server,比如上述配置文件中的cluster defintios,設(shè)置轉(zhuǎn)發(fā)到www.envoyproxy.io這個域名;
Envoy提供了xDS API標(biāo)準(zhǔn),什么是xDS?xDS是x-discovery service,也就是服務(wù)發(fā)現(xiàn)服務(wù),Envoy通過xDS API獲取配置信息,然后根據(jù)配置信息進(jìn)行轉(zhuǎn)發(fā),包括幾個類型,分別是:EDS(endpoint discovery service),LDS(listener discovery service)和CDS(cluster discovery service),對應(yīng)實現(xiàn)節(jié)點服務(wù)發(fā)現(xiàn),監(jiān)聽器服務(wù)發(fā)現(xiàn)和集群服務(wù)發(fā)現(xiàn)。
Envoy
Envoy支持L3/L4 filter架構(gòu),提供了對L3/L4網(wǎng)絡(luò)代理功能,這是Envoy的核心功能,還支持TCP、UDP、HTTP、TLS證書認(rèn)證、Redis、Postgres、MongoDb等諸多協(xié)議的filter;Envoy支持HTTP L7架構(gòu),提供了對HTTP協(xié)議的filter,支持HTTP1.1、HTTP2、HTTP3,gRPC等協(xié)議;Envoy還提供了健康檢查,負(fù)載均衡,熔斷,限流等功能,并且有強大的可觀測性,包括metrics、tracing等;
(5)Envoy處理請求流程
- 某請求經(jīng)過TCP鏈接被處于某個worker線程的listener接受;
- listener filter鏈被創(chuàng)建,一個listener可以有多個filter鏈,主要用于SNI、相關(guān)等處理,一旦處理完成,listener將匹配一個network filter鏈,如HTTP connection manager;
- listener filter鏈可以與TLS關(guān)聯(lián),以解密被加密的數(shù)據(jù),network filter鏈被創(chuàng)建,如HTTP connection manager;
- HTTP/2編解碼器將TCP流解幀為獨立的stream,每個stream處理一對request/response;
- 對于每個HTTP stream,一個下游http filter被創(chuàng)建,其中最重要的是route filter,它必須位于HTTP filter鏈的末端;
- route filter根據(jù)配置來選定請求要被路由到哪個cluster(route filter將從cluster獲取HTTP connection pool);
- cluster通過負(fù)載均衡策略選定最終的上游節(jié)點,其中還涉及到了斷路器與健康檢查等機制,若HTTP connection pool不存在存活的鏈接,則一個與上游節(jié)點的新鏈接將被建立;
- 對于每個stream,一個上游HTTP filter鏈將被創(chuàng)建,默認(rèn)情況下只有codec filter,它主要負(fù)責(zé)將請求編碼給上游節(jié)點,并將上游節(jié)點的回包解碼;
- 處理與上游節(jié)點相關(guān)的TLS,而后將請求發(fā)送到上游節(jié)點;
- 收到上游節(jié)點的回包后,回包以相反順序依次經(jīng)過HTTP filter,包括上游codec filter,route filter等filter,最終被發(fā)送到下游;
- 最后stream被銷毀,更新整個過程中產(chǎn)生的統(tǒng)計數(shù)據(jù)與日志;
3、Istio實踐
Istio 是基于K8S編排服務(wù),而K8S網(wǎng)絡(luò)相關(guān)的知識點,在《Kubernetes核心原理》做過一些介紹,這里再回顧一下:
- K8S的物理資源是Node,每個Node上運行一個Kubelet進(jìn)程,而Node上運行的Pod,就是K8S的邏輯資源;
- 每個Pod都有一個IP地址,通過該IP地址可以訪問到Pod;
- 如果聲明Deploymnet,則K8S會為該Deployment創(chuàng)建一組Pod,每個Pod的IP地址是不同的,為了這些Pod實現(xiàn)負(fù)載均衡,K8S會為每個Pod創(chuàng)建一個Service,Service的IP地址是固定的,通過該IP地址可以訪問到一組Pod;
- Service的IP地址是虛擬IP,K8S通過iptables規(guī)則將Service的IP地址映射到Pod的IP地址;
- 在K8S中服務(wù)發(fā)現(xiàn),是通過CoreDNS實現(xiàn)的DNS服務(wù)來找到對應(yīng)的Service的IP;
而在Istio中,每個Pod都有一個對應(yīng)的Sidecar,Sidecar負(fù)責(zé)與K8S進(jìn)行通信,可以登陸到業(yè)務(wù)的Pod中執(zhí)行ps aux,會看到proxy的進(jìn)程,具體istio的pods詳細(xì)如下圖:
詳情
如果你想繼續(xù)探究內(nèi)部實現(xiàn),可以嘗試自己安裝Istio,如果你沒有自己的可用集群,可以使用Kubernetes Playground,打開鏈接:https://labs.play-with-k8s.com/具體可以參考這篇文章:https://www.knowledgehut.com/blog/cloud-computing/test-drive-your-first-istio-deployment-using-play-with-kubernetes-platform-cloud-computing
對應(yīng)的腳本已經(jīng)準(zhǔn)備好了,可以先執(zhí)行istio-preinstall.sh:
#!/bin/bash
kubeadm init --apiserver-advertise-address $(hostname -i)
mkdir -p $HOME/.kube
chown $(id -u):$(id -g) $HOME/.kube/config
kubectl apply -n kube-system -f "https://cloud.weave.works/k8s/net?k8s-versinotallow=$(kubectl version | base64 | tr -d '\n')"
然后執(zhí)行istio-install.sh:
#!/bin/bash
curl -L https://git.io/getLatestIstio | sh -
export PATH=$PWD/bin:$PATH
cd istio-1.21.2
istioctl manifest apply --set profile=demo --set values.gateways.istio-ingressgateway.type=ClusterIP
最后執(zhí)行:kubectl -n istio-system get pod 可以看到isito-ingressgateway和istio-pilot的pod狀態(tài)都是running。
參考
(1)https://cloud.tencent.com/developer/article/1351311
(2)https://labs.play-with-k8s.com/
(3)https://blog.csdn.net/KeyarchOS/article/details/135782578