ITBear旗下自媒體矩陣:

華爾街見聞:基于騰訊云容器服務(wù)的微服務(wù)架構(gòu)實踐

   時間:2017-05-09 16:43:25 來源:互聯(lián)網(wǎng)編輯:星輝 發(fā)表評論無障礙通道

簡介

華爾街見聞的運營方上海阿牛信息科技有限公司是全球金融信息服務(wù)提供商,每天全平臺為近200萬用戶提供資訊、數(shù)據(jù)、研究等服務(wù)。旗艦產(chǎn)品華爾街見聞APP長期位居各應(yīng)用市場財經(jīng)資訊類客戶端第1位。由于將重大事件、市場的基本面變化和100多種全球資產(chǎn)價格緊密關(guān)聯(lián),在金融領(lǐng)域具有極高滲透率。首創(chuàng)的7x24快訊模式已經(jīng)成為在中文世界理解全球市場的最快來源。也因此,該產(chǎn)品有技術(shù)架構(gòu)復(fù)雜,需要高并發(fā)承載能力等特性。

背景

老系統(tǒng)日益臃腫

原先的系統(tǒng)是PHP monolithic架構(gòu),功能按模塊劃分,日積月累,最后模塊達(dá)到60+個,新人接手項目會拿到一整個系統(tǒng)的代碼,以及需要整個系統(tǒng)的配置,而他可能只需要專注開發(fā)不到1/10的業(yè)務(wù)。

伸縮性

我們的主要業(yè)務(wù)是即時資訊,資訊具有時效性,網(wǎng)站的訪問量會呈現(xiàn)鋸齒形分布。當(dāng)遇到特大新聞如英國退歐、美國大選、法國大選等,我們要能彈性地通過增加服務(wù)資源,提高服務(wù)的容量。

容錯性

我們希望一個低優(yōu)先級服務(wù)出現(xiàn)問題之后,不影響主要服務(wù);一個主要服務(wù)能保證更高的可用性,就算出現(xiàn)問題,也要保證優(yōu)雅降級。

比如在重大事件發(fā)生的時候,我們希望文章API保證不會受到影響。

單體應(yīng)用

PHP單體應(yīng)用在生產(chǎn)環(huán)境服務(wù)的時候,所有業(yè)務(wù)都跑在一個程序里,增加了系統(tǒng)的脆弱性,一個隱藏的性能問題,能在服務(wù)量激增的時候成為壓垮駱駝的一根稻草。

云服務(wù)商成本

由于架構(gòu)落后于需要,我們不得不用硬件彌補性能上的問題,導(dǎo)致云服務(wù)器成本不斷增加。

線上運維

由于沒有方便的監(jiān)控和運維工具,導(dǎo)致排查問題的效率低,使得在系統(tǒng)遇到問題的時候排查困難,耗時過長。

開發(fā)新功能

開發(fā)新任務(wù)的同時,我們需要修復(fù)原有系統(tǒng)的性能問題。

PHP monolithic架構(gòu)圖

每臺服務(wù)器部署相同的服務(wù)端PHP代碼,由PHP-fpm解釋執(zhí)行,通過Nginx進行反向代理。

華爾街見聞微服務(wù)架構(gòu)設(shè)計

因此,在2016年11月至2017年3月,我們采用微服務(wù)架構(gòu)啟動重構(gòu),嘗試解決一部分上述問題,在伸縮性上能以服務(wù)為單位進行拓容,同時,這一設(shè)計會在某些方面增大我們的開發(fā)成本和運維成本。

錯誤排查復(fù)雜

很顯然,以前在單體應(yīng)用中能直接登錄服務(wù)器,查看出錯日志,現(xiàn)在錯誤散落在不同的服務(wù)中,為我們的錯誤排查帶來了困難。

日志源增加

如何把服務(wù)的日志收集并分析。

基礎(chǔ)設(shè)施增加

每個服務(wù)有互相獨立的MySQL、Redis,公共服務(wù)方面需要高可用的服務(wù)發(fā)現(xiàn),調(diào)用鏈路分析,日志收集儲存設(shè)施等。

技術(shù)選型

微服務(wù)架構(gòu)圖

每臺服務(wù)器上均衡地部署服務(wù),LB接受用戶的請求,將請求轉(zhuǎn)發(fā)到API gateway,API gateway向服務(wù)發(fā)現(xiàn)查詢具體服務(wù)的IP和端口,服務(wù)執(zhí)行完業(yè)務(wù)邏輯后向上返回數(shù)據(jù)。

服務(wù)框架

我們選擇golang作為我們的后端開發(fā)語言。

golang在性能和開發(fā)效率上有很好的平衡,語法上很簡單,并發(fā)編程簡單高效,基礎(chǔ)庫健全。

調(diào)試工具強大

自帶一些pprof包可以profile當(dāng)前程序的CPU消耗、內(nèi)存占用、鎖狀態(tài)、channel阻塞等,非常便利我們定位問題。

有一些優(yōu)秀的微服務(wù)框架

我們選用go-micro作為開發(fā)框架,里面包含幾乎所有微服務(wù)組件,并且支持非常好的拓展性,通過接口的設(shè)計方式,讓我們可以拓展一些自己的組件,如服務(wù)發(fā)現(xiàn)、傳輸協(xié)議等。

golang在華爾街見聞已經(jīng)有過比較多的應(yīng)用,工程師使用golang開發(fā)幾乎0學(xué)習(xí)成本。

服務(wù)拆分

拆分的原則是通過服務(wù)功能劃分,盡量避免雙向依賴。我們拆分出了13個服務(wù),包括用戶、內(nèi)容、實時新聞、評論、搜索、商城、支付、三方代理等服務(wù)。

服務(wù)間通信

服務(wù)間使用protobuf協(xié)議對數(shù)據(jù)進行編碼,使用UDP作為傳輸協(xié)議。

服務(wù)發(fā)現(xiàn)

Etcd搭建多節(jié)點高可用的服務(wù)發(fā)現(xiàn)。

服務(wù)保護

我們選擇Hystrix作為服務(wù)保護以及服務(wù)降級的方案。

每個服務(wù)開發(fā)者,需要定義自己服務(wù)接口的并發(fā)量、超時時間以及fallback方法。

部署方案

我們選擇了Kubernetes。

* Docker Swarm

這是我們最先選擇的方案,因為Docker 1.12之后已經(jīng)將Swarm功能集成到Docker Engine,能以最少的配置啟動Docker集群。經(jīng)過簡化和設(shè)計的控制臺API,方便地管理集群、調(diào)整服務(wù)如控制服務(wù)的數(shù)量、CPU、內(nèi)存限制等。往集群內(nèi)加入機器非常簡單,只需要運行一條命令即可。使用manager-worker架構(gòu),manager作為調(diào)度節(jié)點,支持高可用。

但遇到了非常致命的問題,比如頻繁更新服務(wù)的時候會出現(xiàn)服務(wù)訪問不到,某服務(wù)的負(fù)載均衡后掛載的服務(wù)IP是其它服務(wù)的,服務(wù)之間的通信有幾率出現(xiàn)超時問題,歸根結(jié)底,還是社區(qū)正在不斷完善swarm,有很多不穩(wěn)定的地方,網(wǎng)絡(luò)方面沒有進行優(yōu)化。

* Kubernetes

這是谷歌主導(dǎo)的服務(wù)編排工具,它支持Docker,相比Docker Swarm來說,它的概念更多,分層更細(xì)。功能方面多于Docker Swarm,支持一些高級功能如秘鑰管理、配置管理、自動拓容等。在生產(chǎn)環(huán)境的應(yīng)用比較廣泛,穩(wěn)定性更高。

* 裸機部署

裸機部署是我們的一個備案,考慮到以上兩個方案在當(dāng)時沒有具體線上實施的經(jīng)驗,所以如果Docker Swarm和Kubernetes都沒有成功,我們直接裸機部署。

裸機部署的需要解決單機端口沖突,如果一個服務(wù)在一個服務(wù)器上最多只部署一個,那么可以通過寫腳本,并劃分服務(wù)器角色的方式進行部署,利用ansible可以定義user服務(wù)集群、content服務(wù)集群、comment服務(wù)集群等,通過分發(fā)二進制文件的方式讓服務(wù)啟動,這樣的方案要考慮到服務(wù)更新、服務(wù)重啟、服務(wù)刪除等邏輯,同一時間只有部分節(jié)點更新,在服務(wù)未更新成功的時候流量暫時不能打到正在更新的節(jié)點。

準(zhǔn)備工作

代碼托管

由于之前使用github開發(fā)人員的代碼提交在有翻墻工具的幫助下速度依然不是很理想,我們自建了Gitlab倉庫,自此開發(fā)過上了幸福的生活。

容器化

swarm和kubernetes是基于docker快速創(chuàng)建刪除服務(wù),通過增加容器為服務(wù)拓容,縮減容器為服務(wù)縮小規(guī)模,所以所有項目必須要構(gòu)建docker鏡像。按項目類型劃分,我們遇到3種鏡像打包情況。

后端項目

后端服務(wù)90%是golang項目,針對golang的鏡像,我們采取將golang項目編譯成可執(zhí)行文件,基于最小的alpine鏡像打包入docker,這里遇到過一個問題,就是alpine里缺少openssl的證書,無法支持https,我們自定義了新的基礎(chǔ)鏡像,不僅將證書文件打入鏡像,同時為了線上調(diào)試方便,增加了tcpdump、strace、bash等工具,在初期調(diào)試容器間通信問題時發(fā)揮重要的作用。

前端靜態(tài)文件

見聞的后臺以及m站基于Vue,編譯后生成的靜態(tài)文件打入鏡像,通過nginx訪問。 為了支持HTTP2,我們打入nginx鏡像缺少的證書。

服務(wù)端渲染

主站PC站基于nodejs、Vue實現(xiàn)服務(wù)端渲染,所以不僅需要依賴nodejs,而且需要利用pm2進行nodejs生命周期的管理。為了加速線上鏡像構(gòu)建的速度,我們利用taobao源https://registry.npm.taobao.org進行加速, 并且將一些常見的npm依賴打入了基礎(chǔ)鏡像,避免每次都需要重新下載,鏡像打包從開始的3分鐘縮減到1.5分鐘。

三類鏡像結(jié)構(gòu)

持續(xù)集成

我們利用Gitlab CI配置了測試、鏡像構(gòu)建、鏡像發(fā)布、自動部署等流程,后端服務(wù)從提交代碼到測試分支到測試環(huán)境自動部署完成花費1.5分鐘,前端服務(wù)平均為2.5分鐘。

CI任務(wù)中的test->build->docker->deploy流程

云平臺的選擇

最終,我們選擇了騰訊云的容器服務(wù),主要基于以下幾點考慮:

騰訊云的容器服務(wù)是在騰訊云的Iaas上為每個用戶構(gòu)建容器集群,騰訊云提供的微服務(wù)架構(gòu)和持續(xù)集成與交付的應(yīng)用場景基本滿足了我們的述求。

騰訊云的容器服務(wù)是基于Kubernetes實現(xiàn)的,支持完全的kubernetes能力。

騰訊云在Kubernetes上實現(xiàn)了他們的存儲、負(fù)載均衡等產(chǎn)品的插件、復(fù)用了騰訊云本身平臺的監(jiān)控、日志等能力。減少了我們接入和開發(fā)的成本。

服務(wù)在騰訊云的應(yīng)用

我們將我們的應(yīng)用重構(gòu)成微服務(wù)的架構(gòu),每個微服務(wù)部署成騰訊云容器服務(wù)上的一個服務(wù),前端接入通過一個負(fù)載均衡。后端服務(wù)間可互相訪問。

服務(wù)器安全方面,內(nèi)部服務(wù)器通過VPC進行網(wǎng)絡(luò)隔離,將網(wǎng)絡(luò)劃分為生產(chǎn)環(huán)境、測試環(huán)境,在生產(chǎn)環(huán)境中又劃分backend子網(wǎng)和data子網(wǎng),設(shè)定子網(wǎng)之間的訪問規(guī)則。

為了禁止內(nèi)部服務(wù)器的外網(wǎng)訪問,不給內(nèi)部服務(wù)器分配外網(wǎng)IP,僅通過跳板機訪問。

性能對比

利用locust模擬線上請求的比例,利用2臺16核的壓測機在內(nèi)網(wǎng)對10臺16C32G的機器上的服務(wù)進行壓測,達(dá)到1w/s QPS以上,并且服務(wù)的負(fù)載并沒達(dá)到極限,這已經(jīng)是之前PHP生產(chǎn)環(huán)境20+臺16C32G服務(wù)器能達(dá)到的QPS。

線上調(diào)用追蹤

通過追蹤API調(diào)用鏈的流向與耗時,我們可以找出性能的瓶頸。我們通過zipkin實際優(yōu)化了幾種情況:

服務(wù)調(diào)用冗余

當(dāng)拉取文章列表的時候,我們需要拉取文章對應(yīng)的作者信息,開始的時候我們使用拉取單個作者信息的方式,后來性能調(diào)優(yōu)階段,我們將其改為批量拉取作者列表,減少RPC的冗余。

服務(wù)耗時長

對于有些本身就比較耗時并且對即時性不是那么苛刻的計算服務(wù),我們?yōu)榱吮WC服務(wù)的響應(yīng)時間,會適量地加上緩存。

監(jiān)控與報警

由從外部系統(tǒng)表征到內(nèi)部日志,我們將監(jiān)控分為API健康,程序錯誤報警,以及服務(wù)器/容器負(fù)載。

排查問題的流程一般有兩種情況,一種是用戶發(fā)現(xiàn)問題,申報問題,開發(fā)人員跟進問題;一種是我們的監(jiān)控優(yōu)先發(fā)現(xiàn)問題,開發(fā)人員在用戶反饋前跟進并修復(fù)。在報警方面,我們通過為監(jiān)控系統(tǒng)謹(jǐn)慎設(shè)置報警閾值,當(dāng)觸發(fā)報警時,開發(fā)人員會收到郵件。

這里我們在報警的定義上有過思考,即什么樣的報警算是有意義的?我們遇到過每天10幾條重復(fù)的報警,通常開發(fā)人員開始時會對報警非常重視,當(dāng)重復(fù)的報警一再出現(xiàn),漸漸失去了對報警的關(guān)注。所以我們有解除一些不必要的報警,并且對剩余一些報警進行調(diào)查,甚至有些警報是因為監(jiān)控工具本身的不準(zhǔn)確引起的。

API健康

我們設(shè)置默認(rèn)的時間區(qū)間是5分鐘

統(tǒng)計API五分鐘內(nèi)平均QPS

API 98%以內(nèi)的延遲分布

QPS最高的前10的API

API的返回碼的分布

程序錯誤報警

后端程序內(nèi)接入Sentry日志報警系統(tǒng),golang程序捕獲panic日志以及error日志,并發(fā)送報警郵件。

服務(wù)器/容器負(fù)載

通過在服務(wù)器上運行telegraf daemon進程,收集服務(wù)器metrics并發(fā)送給influxdb,使用Grafana作為前端面板,對服務(wù)器負(fù)載以及容器的平均CPU、內(nèi)存占用率進行監(jiān)控。

結(jié)束語

本文介紹了華爾街見聞通過重構(gòu)和服務(wù)容器的重新部署,實踐微服務(wù)架構(gòu)的情況。經(jīng)過幾個月的開發(fā)測試,我們不僅完成了線上服務(wù)從PHP到Golang的轉(zhuǎn)型,更在服務(wù)的穩(wěn)定性上經(jīng)歷了考驗,支撐了幾次重大新聞的高流量。

在開發(fā)流程上,搭建了完善的自動化工具,減少了人工操作的重復(fù)性和誤操作概率。

在運維方面,由于監(jiān)控系統(tǒng)對系統(tǒng)完整的監(jiān)控,與Kubernetes健全的上線、下線、回滾、拓容功能配合,能以極快的速度處理線上問題。

舉報 0 收藏 0 打賞 0評論 0
 
 
更多>同類資訊
全站最新
熱門內(nèi)容
網(wǎng)站首頁  |  關(guān)于我們  |  聯(lián)系方式  |  版權(quán)聲明  |  網(wǎng)站留言  |  RSS訂閱  |  違規(guī)舉報  |  開放轉(zhuǎn)載  |  滾動資訊  |  English Version