廢話
Sidecar 是一個(gè)很糾結(jié)的名字施蜜,我們在翻譯技術(shù)雷達(dá)時(shí)采用了一個(gè)比較通俗的翻譯曲初,即邊車体谒,而這個(gè)詞隨著微服務(wù)的火熱與 Service Mesh 的逐漸成熟而進(jìn)入人們的視野。雖然很多企業(yè)在自己的后臺(tái)應(yīng)用中已經(jīng)大量的使用了 Sidecar臼婆,但是也是沒有意識到這是一個(gè)極為有用的 pattern抒痒,今天我們就來聊一聊。
什么是 Sidecar 與 Sidecar pattern颁褂?
Sidecar 直接表示就是挎斗摩托車故响,也就是常說的“三蹦子”,如果你經(jīng)常玩吃雞颁独,你一定不陌生彩届。在“三蹦子”中,往往有個(gè)挎子誓酒,它不提供動(dòng)力樟蠕,但是也是這個(gè)機(jī)動(dòng)裝置的一個(gè)重要的組成部分贮聂,如果坐著一個(gè)妹子就可以給開車的你喂水果。
我們目前很多程序都是奔著 Cloud Native 的目標(biāo)去的寨辩,我們的代碼注定是要跑在云上的吓懈,當(dāng)有人問我如果我要做到 Cloud Native 時(shí),有沒有合適的學(xué)習(xí)資料之類的時(shí)靡狞,我會(huì)考慮如果你是有一定經(jīng)驗(yàn)的開發(fā)者耻警,并且對 Design Pattern 有一些了解,那么你非常適合這本來自微軟 P & P Group 的書 Cloud Design Patterns甸怕,雖然這本書很簡單甘穿,實(shí)例也不多,但是更多的是啟發(fā)性梢杭。我也是在 Cloud Design Pattern 這本書中學(xué)到了很多扒磁,sidecar 也是其中之一,并且我們寫了很多很多 Sidecar 用于管理自己的 Service Mesh 式曲。
[Pattern is] a solution to a problem in a context.
為什么你需要 Sidecar妨托?
非常簡單,想象一下你要編寫一堆 Web Service API吝羞,使用 JSON 作為數(shù)據(jù)格式暴露給前端兰伤,這個(gè)應(yīng)用程序是用最常見的 Spring Boot 編寫的,然后你要把他丟在你的虛擬機(jī)或者 k8s 上钧排,你除了寫代碼敦腔,還需要考慮什么?
- DNS
- 反向代理
- 服務(wù)發(fā)現(xiàn)
- 服務(wù)注冊
- 負(fù)載均衡
- HTTPS
- 彈性
- 日志
- 性能監(jiān)控 APM
- 警報(bào)
- 終端安全
- 獲取配置
- 等等
很多同事都對這些事情嗤之以鼻恨溜,畢竟大多數(shù)人的核心工作還是寫代碼符衔,把應(yīng)用做起來,至于這些事情是 ops 做的事兒糟袁,或者工程師可以做一部分判族,比如配置日志、給端點(diǎn)加個(gè)證書配置等等项戴。于是我問一個(gè)朋友形帮,Spring Boot 自帶的 server 你知道怎么配證書和日志,那么 node express 呢周叮?那么 on rails 呢辩撑?那么 play framework 呢?特別是當(dāng)你決心要實(shí)現(xiàn)微服務(wù)架構(gòu)的時(shí)候仿耽,這些看起來比較麻煩又很簡單的事兒合冀,反倒最消耗人,我們不希望給每個(gè)服務(wù)都做一遍项贺,但是又不得不做一遍君躺。所以峭判,sidecar 的出現(xiàn)可以讓我們以更優(yōu)雅的方式解決這個(gè)事情,剛才我們提到的大量的功能都可以用 out-of-process 的方式實(shí)現(xiàn)晰洒,比如說反向代理。
Ruby 的 Unicorn Server 是一個(gè)很好的 Rack 容器啥箭,但是它對慢連接很敏感谍珊,而且不是很好處理 access log,熟悉 NGINX 的你一定想到了急侥,如果我在虛擬機(jī)上開啟一個(gè) NGINX 進(jìn)程砌滞,并且將 443 端口暴露出去,然后在這個(gè) NGINX 中配置好 access log 與證書坏怪,并且將收到的請求使用 linux socket 的方式轉(zhuǎn)發(fā)給 unicorn(或者直接走 docker network)贝润,這樣我的 unicorn server 不就很簡單了,我甚至都不需要配置铝宵。這樣的一個(gè) NGINX 就是一個(gè) sidecar打掘,它實(shí)現(xiàn)了訪問記錄、端點(diǎn)安全鹏秋、進(jìn)程隔離尊蚁、并且輕量。你的應(yīng)用程序不用再在乎這些侣夷,大約長得像這樣:
server {
listen 80;
...
location / {
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Request-Start "t=\${msec}";
proxy_set_header Host \$http_host;
proxy_redirect off;
proxy_pass http://backend;
...
再舉一個(gè)例子横朋,我們每個(gè)應(yīng)用程序都會(huì)記錄日志,而我們并不希望日志保存在每臺(tái)機(jī)器上或者容器中百拓,我們希望每個(gè)應(yīng)用是不產(chǎn)生任何狀態(tài)的琴锭。但是這很難,我們必須開發(fā)所謂的日志收集系統(tǒng)衙传,并且相關(guān)的日志組件决帖,往往我們只能兼顧一兩個(gè)流行語言或平臺(tái),例如 Java 與 JavaScript蓖捶,而且我們還得維護(hù)這些東西古瓤,直到公司倒閉。有沒有更優(yōu)雅的解決辦法呢腺阳?答案是有落君,在 12 factor app: logs 中,我們希望以事件流的方式去處理日志亭引,如果我的應(yīng)用把日志丟到 stdout 與 stderr 中绎速,然后有人來自動(dòng)收集,歸檔并發(fā)送到日志中心呢焙蚓?這就是日志收集器纹冤,這也是一個(gè) sidecar洒宝。
Sidecar 核心思想
Sidecar 不是應(yīng)用程序的必要組成部分,當(dāng)你使用 docker-compose 在本地啟動(dòng)一個(gè)小服務(wù)做開發(fā)測試的時(shí)候萌京,Sidecar 并不會(huì)起作用雁歌,所以它不影響你的核心功能。但是知残,Sidecar 在真正的生產(chǎn)環(huán)境中靠瞎,是和你的應(yīng)用程序綁定在一起的,應(yīng)用在哪里啟動(dòng)求妹,它就出現(xiàn)在哪里乏盐。我們的應(yīng)用不論是在虛擬機(jī)或者是在容器中,每一個(gè)應(yīng)用的實(shí)體制恍,都有大量的 sidecar 來做這種與核心功能無關(guān)的活兒父能。
每個(gè)“三蹦子”都有自己的 sidecar,每個(gè) sidecar 都是緊緊的 attach 到它的“三蹦子”上的净神。
那么何吝,引用并修改一下 sidecar 的特性
- Sidecar 是獨(dú)立于其應(yīng)用程序之外的,不使用應(yīng)用程序的運(yùn)行環(huán)境與編程語言鹃唯。比如你可以使用 JavaScript 去做日志收集器岔霸,而不用關(guān)心應(yīng)用程序用的什么語言,你們使用進(jìn)程通信的方式或者更粗暴的流
- Sidecar 是可以訪問一些相同的系統(tǒng)資源的俯渤,和應(yīng)用程序一樣呆细。這樣你才能進(jìn)行系統(tǒng)監(jiān)控與收集程序的健康數(shù)據(jù)。但是也有一些數(shù)據(jù)是在應(yīng)用程序內(nèi)打樁八匠,然后暴露出去的比如 transaction
- Sidecar 實(shí)際上對性能的損失非常小絮爷,特別是使用了容器化技術(shù)后,本來啟動(dòng)容器就是很廉價(jià)的事情梨树,而且使用 docker image 發(fā)布 sidecar 讓這個(gè)事情成本更低
- Sidecar 同樣可以進(jìn)行應(yīng)用程序擴(kuò)展坑夯,比如說,我們可以將 circuit breaker 實(shí)現(xiàn)在 sidecar 中抡四,這樣就可以避免代碼中使用各種 circuit breaker 的實(shí)現(xiàn)柜蜈,你的代碼依舊可以簡單的 RestTemplate 去做你想做的事兒,也不用擔(dān)心下游服務(wù)的實(shí)效指巡,導(dǎo)致串聯(lián)失效的問題
Sidecar 的適合場景
如果你們公司已經(jīng)開始使用微服務(wù)架構(gòu)淑履,踐行了小組自治,那么大量的應(yīng)用程序會(huì)用各種流行語言編寫藻雪,并且使用了各種不同的框架秘噪,那么 Sidecar 就是你一定要考慮的。使用 out-of-process 的方式封裝共有的一些功能勉耀,讓應(yīng)用程序變得簡單指煎,而這些共有的功能蹋偏,最理想的情況下就是部署腳本中的一些配置。
Sidecar 在微服務(wù)領(lǐng)域是服務(wù)治理的重要工具至壤,也是實(shí)現(xiàn) Service Mesh 的必備工具威始,在 Service Mesh 的概念下,我們希望提供一層額外的抽象來保證服務(wù)的簡單像街、可以相互調(diào)用黎棠,并且?guī)椭覀冚p松的解決服務(wù)發(fā)現(xiàn)、服務(wù)調(diào)用宅广、服務(wù)監(jiān)控葫掉、服務(wù)注冊等等功能些举,這額外的一層可以通過 sidecar 來實(shí)現(xiàn)跟狱。不論是 Istio 還是 conduit 很多關(guān)鍵功能就是這么實(shí)現(xiàn)的。當(dāng)然户魏,很多情況下我們還是會(huì)自己去寫適合自己組織架構(gòu)的 sidecar驶臊,之前我們提到的 NGINX 與日志收集器就是一些很好的例子。而之前我們列舉出一個(gè) Web Service 可能會(huì)需要的功能叼丑,也有一部分是根據(jù)你的云平臺(tái)進(jìn)行裁剪的关翎,比如負(fù)載均衡和彈性,完全可以使用 AWS 的 ELB 與 AutoScaling 來解決鸠信。
那么什么時(shí)候不適用呢纵寝?
- 應(yīng)用程序過小,或者成本問題:如果沒有使用微服務(wù)架構(gòu)或者你的程序就一個(gè) MVC App 就解決了星立,那就不需要使用 sidecar爽茴,畢竟開發(fā)成本很高
- 對性能要求極高:進(jìn)程間通信還是有成本的,有時(shí)也是會(huì)有顯著的延遲或者被阻塞绰垂;docker network 的性能也是趕不上進(jìn)程間通信的室奏,所以如果你的應(yīng)用有小于毫秒級別的性能要求的話,這個(gè) sidecar 不適合你
Sidecar 與 DevOps
我在與別人聊 Sidecar 時(shí)劲装,很多朋友覺得這個(gè)東西的難點(diǎn)不在于創(chuàng)建一個(gè)又一個(gè)的 sidecar胧沫,而是在于如何在部署時(shí),按照應(yīng)用程序的要求將 sidecar 與應(yīng)用程序緊緊的組合在一起占业。這是非常難的绒怨,首先每個(gè)企業(yè)使用的平臺(tái)并不相同,每個(gè)企業(yè)的部署方式也不一樣谦疾,這是沒有通用解的問題窖逗,只能按照現(xiàn)有情況。在之前我們使用 aws ec2 + docker 時(shí)餐蔬,我們會(huì)在 ec2 的 launch config 中去啟動(dòng)不同的 docker image 并且配置其 docker network碎紊,但這是一種比較低效的做法佑附,因?yàn)橹皇鞘褂?docker image 來封裝你的產(chǎn)出物,而不是使用其作為秒級開啟的容器仗考。但是如果在 k8s 上做這件事兒音同,我們更傾向于在一個(gè)容器中把應(yīng)用的事情做好,很難做到每個(gè)應(yīng)用所運(yùn)行的容器上都有 attached sidecars秃嗜。所以這個(gè)話題沒有好的回答权均,只能說是 It depends。
Reference
- https://docs.microsoft.com/en-us/azure/architecture/patterns/
- https://rubygems.org/gems/unicorn/versions/5.1.0
- https://www.nginx.com/blog/what-is-a-service-mesh/
- https://12factor.net
- https://istio.io/
- https://github.com/runconduit/conduit
- https://martinfowler.com/bliki/CircuitBreaker.html
- http://www.baeldung.com/rest-template