短視頻go研發(fā)框架實(shí)踐
導(dǎo)讀:hulk是短視頻研發(fā)部研發(fā)的基于GDP2(Go Develop Platform?)的go服務(wù)開發(fā)框架。它是?款?向業(yè)務(wù)的Web開發(fā)框架,提供了諸多開箱即?的組件和功能,可以?來快速開發(fā)Web服務(wù)。同時(shí),依托于hulk框架并結(jié)合?內(nèi)/業(yè)界優(yōu)秀的開發(fā)實(shí)踐,初步構(gòu)建了?個(gè)符合業(yè)務(wù)應(yīng)?場景的go?態(tài)體系。
全文7330字,預(yù)計(jì)閱讀時(shí)間 12分鐘。
一、產(chǎn)生背景
hulk框架是在“好看視頻”服務(wù)端的go服務(wù)化架構(gòu)升級(jí)背景下產(chǎn)生的。
1.1 為什么要做架構(gòu)升級(jí)?當(dāng)前架構(gòu)面臨哪些問題?
好看視頻初期因業(yè)務(wù)需要快速、靈活的開發(fā)迭代,采?PHP作為開發(fā)語?實(shí)現(xiàn)后端服務(wù),前期取得了?較好的開發(fā)迭代效果。但隨著好看業(yè)務(wù)快速發(fā)展,服務(wù)端的項(xiàng)?(接?、代碼等)急速膨脹,類單體的PHP架構(gòu)在多個(gè)??遇到了瓶頸和問題,主要體現(xiàn)在以下?個(gè)??:
1.開發(fā)效率:對(duì)于主代碼庫,所有服務(wù)端同學(xué)都會(huì)在這同一個(gè)代碼空間開發(fā),此外還有依賴的第三方團(tuán)隊(duì)也會(huì)修改,頻繁的修改/合并降低了開發(fā)效率,同時(shí)也加大了代碼的維護(hù)成本和難度;
2.上線效率:多用戶開發(fā)同一代碼庫的另一個(gè)弊端就是上線等待,由于同一個(gè)時(shí)刻只能有一個(gè)分支上線(分級(jí)上線),導(dǎo)致相連的上線需求要排隊(duì)等待。這也導(dǎo)致我們的同學(xué)摸索出“搭車上線”的模式,雖然加快了上線效率,但也加大了上線的風(fēng)險(xiǎn),沒有從根本上解決問題;
3.運(yùn)行效率:PHP在開發(fā)效率和靈活度方面確實(shí)有一定優(yōu)勢(shì),但當(dāng)所支撐的業(yè)務(wù)達(dá)到幾千萬DAU及以上時(shí),我們必須要考慮服務(wù)的運(yùn)行效率和資源成本等問題。PHP語言在多線程/多協(xié)程的支持上,弱于Java、C/C 、Go等語言,基于物理機(jī)部署的類單體服務(wù)部署架構(gòu),在資源利用率和服務(wù)擴(kuò)縮容等方面也很難滿足需求;
4.SRE效率:在出現(xiàn)穩(wěn)定性問題時(shí),我們期望能夠做到快速感知、快速定位、快速止損。目前基于sia的監(jiān)控/報(bào)警,基于日志的問題定位方式距離理想目標(biāo)還有一定的距離:一是同學(xué)要奔波于各個(gè)平臺(tái)/系統(tǒng)獲取問題線索,二是獲取到的線索及信息維度很多時(shí)候也無法滿足快速、精確定位問題的需求;
這些問題需要通過“4化”,從總體業(yè)務(wù)架構(gòu)、部署架構(gòu)、基礎(chǔ)設(shè)施等多方面去解決:?
1.2 為什么不直接基于GDP2 ?
好看的go服務(wù)化升級(jí)工作開展時(shí),GDP2還未正式發(fā)布,這也是其中一個(gè)因素。
1.3 hulk與gdp2能?對(duì)照
下?從三個(gè)??與gdp2做?個(gè)簡單的對(duì)照,初步了解hulk的整體能?及與gdp2的?些差異。
1.3.1 web server能?
hulk?前主要服務(wù)于web應(yīng)?,?先了解?下hulk的web server能?。1.3.2?功能/組件
功能/組件的豐富度及?身能?,很?程度上影響了框架對(duì)業(yè)務(wù)服務(wù)的?持能?。備注:ral資源訪問層1.3.3 框架周邊及基礎(chǔ)設(shè)施
框架從來不是“單打獨(dú)?的”,它需要有周邊?具和基礎(chǔ)設(shè)施來?持。NOTE:1. 好看在做go化時(shí),也調(diào)研了開源社區(qū)??較優(yōu)秀的?些?具系統(tǒng)和?案并引?, hulk中默認(rèn)添加了對(duì)這些基礎(chǔ)設(shè)施的集成;
1.3.4 對(duì)照總結(jié)
本節(jié)主要站在hulk能力角度與GDP2做了一些方面的參考對(duì)照。以上對(duì)照,可以概括為4點(diǎn):1.很多基礎(chǔ)能?,hulk是復(fù)?gdp的,如:bns、net、codec等;2.?些通?/擴(kuò)展組件,hulk按照業(yè)務(wù)需求場景,進(jìn)??次封裝和增強(qiáng),如:httpserver、ral、redis、mysql等;3.對(duì)于gdp?前沒有?持的?些業(yè)務(wù)需求,進(jìn)?開發(fā)集成,如:定時(shí)任務(wù)、配置中?、服務(wù)治理等;4.參考業(yè)界開源實(shí)踐,引入了一些新的基礎(chǔ)設(shè)施:如prometheus grafana集群、sentry集群、故障定位系統(tǒng)等;
GDP2由幾十個(gè)模塊共同構(gòu)成,由于時(shí)間有限,可能個(gè)別功能點(diǎn)的對(duì)照有偏差。
二、了解hulk
2.1 設(shè)計(jì)思路
2.2 框架結(jié)構(gòu)
從功能上來看,hulk的整體能力可以劃分為四層:
2.2.1 基礎(chǔ)組件
提供了絕大部分項(xiàng)目都應(yīng)該需要的基礎(chǔ)能力,也是其他上層功能組件很可能依賴的組件。hulk框架通過這些基礎(chǔ)組件,使上層應(yīng)用可以無感的與基礎(chǔ)設(shè)施進(jìn)行集成:- 日志組件:默認(rèn)支持與PHP兼容的打印格式(用于配置sia監(jiān)控和報(bào)警),同時(shí)也兼容ftrace接入的格式(日志查詢和問題定位);
- 云原生監(jiān)控:默認(rèn)支持prometheus,對(duì)所有接口請(qǐng)求、redis、ral等遠(yuǎn)程調(diào)用進(jìn)行多維度的metrics采集,并通過grafana展示;
- 配置中心:通過配置中心,可以實(shí)時(shí)下發(fā)并生效配置。目前支持Apollo/iConf,支持功能包括-版本管理、熱發(fā)布、灰度發(fā)布、權(quán)限管理、審核與審計(jì)等;
- 事件追蹤/定位:借助sentry,對(duì)于一些故障,我們可以秒級(jí)感知。hulk在異常信息中保存了比較完整的現(xiàn)場信息-如調(diào)用棧、request、集群和實(shí)例信息等,通過這些信息,可以直接定位問題的原因;
2.2.2 通用組件
這一層的組件能力是通用的,提供了一些管理控制和切面能力:- ral組件:hulk的ral模塊封裝了GDP2的ral主體功能,同時(shí),對(duì)ral進(jìn)行了增強(qiáng)- a)?提供了通過字符串而非文件來進(jìn)行ral初始化和ral懶加載功能;b)?提供了多個(gè)hook能力,如prometheus的監(jiān)控信息采集,熔斷、降級(jí)等;
- 服務(wù)治理:框架的服務(wù)治理能力是基于Sentinel (阿里開源的高可用流量防護(hù)組件)和配置中心來構(gòu)建的,主要以流量為切入點(diǎn),從限流、流量整形、熔斷、降級(jí)等多個(gè)維度來協(xié)助保障微服務(wù)的穩(wěn)定性,并提供動(dòng)態(tài)控制能力;
- 協(xié)程池:a) 可以自動(dòng)調(diào)度海量協(xié)程,復(fù)用goroutines,減少gc,b)?可以優(yōu)雅處理 panic,防止程序崩潰 c)?提供了:任務(wù)提交、獲取運(yùn)行中的 goroutine 數(shù)量、封裝了WaitGroup支持協(xié)程任務(wù)編排等功能;
- 事件通知:框架與如流做了集成。用戶將robot token配置在項(xiàng)目里,就可以直接使用ruliu組件向指定的如流群發(fā)送報(bào)警/通告。如流組件結(jié)合sentry,可以讓我們第一時(shí)間知道程序出了問題并快速定位到問題;
2.2.3?擴(kuò)展組件
前兩層功能對(duì)直接的業(yè)務(wù)處理邏輯參與較少,這一層的組件其能力多是為了處理某一類特定業(yè)務(wù)邏輯和場景,如redis/mysql/定時(shí)任務(wù)等:1.redis組件:基于GDP2 redis模塊的封裝并作了功能增,提供了:a) metrics hook,對(duì)所有的redis請(qǐng)求進(jìn)行監(jiān)控(prometheus)打點(diǎn)(latency/p99/qps/錯(cuò)誤碼分布等);b) sentry hook,支持將redis錯(cuò)誤在記錯(cuò)誤日志同時(shí)發(fā)送到sentry;c) 降級(jí)hook,支持按集群/實(shí)例/百分比維度降級(jí)redis訪問;d) 熔斷hook,支持按集群/實(shí)例/錯(cuò)誤率/慢請(qǐng)求率對(duì)依賴的服務(wù)進(jìn)行熔斷設(shè)置;2.mysql組件:mysql組件是基于GDP2 mysql和 gorm_adapter的封裝,在已有能力之上,進(jìn)行了以下功能擴(kuò)展:a) 提供了metrics hook,對(duì)所有的mysql請(qǐng)求進(jìn)行監(jiān)控(prometheus)打點(diǎn)(latency/p99/qps/錯(cuò)誤碼分布等);b) 提供了sentry hook,支持將mysql錯(cuò)誤在記錯(cuò)誤日志的同時(shí)發(fā)送到sentry;
3.分布式鎖:hulk提供了基于redis的分布式鎖實(shí)現(xiàn)。其中redis連接是基于GDP2的redis模塊的改造,分布式鎖功能是封裝了開源項(xiàng)目redsync;
4.定時(shí)任務(wù):支持兩種定時(shí)任務(wù)模式;a) 帶分布式鎖的運(yùn)行方式:對(duì)于多實(shí)例部署的定時(shí)任務(wù),如果任務(wù)不是冪等的,則需要使用分布式鎖對(duì)任務(wù)的調(diào)度運(yùn)行進(jìn)行控制;b) 不帶分布式鎖的運(yùn)行方式:此模式下,如果部署了多實(shí)例,則所有實(shí)例上同一時(shí)刻的定時(shí)任務(wù),會(huì)同時(shí)執(zhí)行;
2.2.4 http server
hulk(目前只提供了http server能力)提供了很多通用且高效的http middleware,并對(duì)外暴露了一些管理控制接口,在一些特殊情況下,可以通過這些管理接口,在運(yùn)行時(shí)干預(yù)服務(wù)的運(yùn)行:- logger_middleware:用于記錄http的請(qǐng)求、響應(yīng)、耗時(shí)等信息,同時(shí)支持實(shí)時(shí)修改日志打印策略-如按idc/ip/百分比/uid/cuid等維度打??;
- timer_middleware:用于http請(qǐng)求的監(jiān)控埋點(diǎn),可以輸出可用性、tp99、流量、平響、錯(cuò)誤碼等metrics,維度包括服務(wù)級(jí)/idc/instance等;
- recover_middleware:用于捕獲http 請(qǐng)求鏈路中的painc事件,并可自定義panic handler邏輯,如通過結(jié)合sentry和如流,可以實(shí)時(shí)感知并定位panic事件;
- flow_control_middleware:接口限流組件,可以通過配置中心或管理接口,對(duì)接口按idc/instance維度進(jìn)行限流;
- timeout_middleware:通過該middleware或與配置中心結(jié)合使用,可以對(duì)接口按idc維度進(jìn)行超時(shí)控制;
- 其他middleware可以查看hulk文檔(如-internal_user_middleware、jager_opentracing_middleware、thirdparty_auth_middleware、b2logger_middleware等)
- 管理控制接口:如健康檢查接口,服務(wù)治理-熔斷、限流、降級(jí)接口,metrics接口,線上實(shí)例性能調(diào)試接口等;
2.3 框架生態(tài)
通過近一年的建設(shè),我們初步構(gòu)建了一個(gè)以hulk框架為中心的、符合好看業(yè)務(wù)場景的go生態(tài)體系,包括:
- 標(biāo)準(zhǔn)目錄規(guī)范:避免各個(gè)項(xiàng)目結(jié)構(gòu)不統(tǒng)一,減少項(xiàng)目維護(hù)難度和工作量;
- 代碼生成器:基于hulk框架、標(biāo)準(zhǔn)目錄規(guī)范、組件使用規(guī)范的代碼生成器,目的是減少通用模塊/組件使用不規(guī)范,解決通用流程編碼、處理不一致的問題;
- hklib:好看的通用lib庫,提供了一些的通用功能(也包含了很多PHP轉(zhuǎn)go過程中的一些orp通用/基礎(chǔ)的函數(shù)/功能),也提供了50 對(duì)中臺(tái)服務(wù)的調(diào)用client,減少重復(fù)代碼,提升研發(fā)效率,提升可維護(hù)性;
- 基礎(chǔ)設(shè)施:prometheus thanos集群、sentry服務(wù)、apollo集群、pyroscope性能分析平臺(tái)等;
- iconf:好看自研配置中心,能力在對(duì)齊開源的Apollo之外,還增加/增強(qiáng)了一些功能,如-key維度的發(fā)布、更安全的配置獲取、更簡潔的操作頁面、類分級(jí)發(fā)布等;
- artemis:服務(wù)可視化與故障智能定位系統(tǒng),可以在該系統(tǒng)中看到服務(wù)的部署架構(gòu)、服務(wù)內(nèi)部調(diào)用鏈、多維度細(xì)粒度的近實(shí)時(shí)監(jiān)控和關(guān)鍵日志。在發(fā)生可用性故障時(shí),一些故障問題可以秒級(jí)的定位到原因和具體代碼;
2.4 框架應(yīng)用情況
目前短視頻所有g(shù)o服務(wù)都是基于hulk構(gòu)建的,在資源、接口性能和可用性等方面都有一些階段性產(chǎn)出和收益。
hulk框架應(yīng)用現(xiàn)狀:資源和性能收益:
資源和性能收益,很大一部分要?dú)w屬于PHP->Go的技術(shù)棧切換;而框架為服務(wù)應(yīng)用相應(yīng)技術(shù)棧特性提供了便捷和高效的方式。
2.4?hulk服務(wù)架構(gòu)
下圖描述了一個(gè)微服務(wù)(基于hulk)的架構(gòu)全景圖:
- 框架中個(gè)各功能組件都是圍繞業(yè)務(wù)各個(gè)場景和需求的,在業(yè)務(wù)邏輯中能夠比較便捷的使用相關(guān)功能組件;
- 這些組件在啟用后,也會(huì)與相應(yīng)的基礎(chǔ)設(shè)施進(jìn)行交互融合,共同支撐服務(wù)的高效、可控和穩(wěn)定的運(yùn)行;
hulk組件初始化及與周邊基礎(chǔ)設(shè)施的集成,基本都可以通過環(huán)境變量/配置文件來完成。
三、框架能力與應(yīng)用
下面我們從日常開發(fā)遇到的一些痛點(diǎn),來介紹框架的能力,并配以示例來說明這些能力是如何減少或解決痛點(diǎn)的。
3.1 如何提升代碼質(zhì)量?
代碼質(zhì)量會(huì)直接或間接的產(chǎn)生以下影響:
- 代碼質(zhì)量會(huì)直接影響代碼維護(hù)成本;
- 代碼質(zhì)量會(huì)影響程序出bug的概率;
- 代碼質(zhì)量會(huì)影響程序運(yùn)行效率;
3.1.1?規(guī)范代碼組織結(jié)構(gòu)
降低項(xiàng)目維護(hù)成本,提升研發(fā)效率。
- 通過標(biāo)準(zhǔn)目錄規(guī)范,定義通用(http服務(wù))的項(xiàng)目layout,避免出現(xiàn)每人一種或多種layout,最終項(xiàng)目結(jié)構(gòu)“百花齊放”的現(xiàn)象;
- 通過代碼生成器,幫助開發(fā)者生成項(xiàng)目模板,對(duì)初始化流程,各目錄/文件的使用進(jìn)行潛在約定;
3.1.2 編碼規(guī)范和靜態(tài)檢查
提升代碼可讀性,減少低級(jí)代碼bug
- 遵循百度Go編碼規(guī)范 業(yè)務(wù)編碼補(bǔ)充規(guī)范;
- 使用GDP的代碼檢查工具:go_fmt、goc;
3.1.3 配套的壓測和性能分析平臺(tái)
確定服務(wù)的壓力邊界,發(fā)現(xiàn)潛在的性能問題。
- 壓測和性能測試平臺(tái)(測試環(huán)境):nGrinder
- 程序性能分析平臺(tái):pyroscope??梢酝ㄟ^hulk自集成的管理接口,實(shí)時(shí)打開或關(guān)閉線上實(shí)例的“continuous-prof”功能,定位線上性能問題:
3.2 如何提升開發(fā)迭代速度?
- 如何讓開發(fā)者專注于業(yè)務(wù)邏輯與實(shí)現(xiàn)?
- 如何讓開發(fā)者快速響應(yīng)并完成產(chǎn)品需求?
3.2.1?豐富的實(shí)用組件/功能
提升研發(fā)效率,避免試錯(cuò),減少出錯(cuò)。
- 程序增強(qiáng)組件:增強(qiáng)的redis/mysql功能,增強(qiáng)的ral調(diào)用等。例-下圖中的redis監(jiān)控,其監(jiān)控指標(biāo)是由hulk redis組件自動(dòng)采集計(jì)算的:
- 優(yōu)秀的開源組件:sentry、prometheus grafana、apollo、協(xié)程池等。例-prometheus grafana:hulk框架默認(rèn)支持prometheus,可以對(duì)服務(wù)的可用性、QPS、耗時(shí)、錯(cuò)誤碼等metrics自動(dòng)計(jì)算收集:
- 豐富的http middleware。
3.2.2 配置化、低代碼支持
減少代碼的修改和上線,提升需求的響應(yīng)和完成速度。
- hulk框架中大部分組件可以通過環(huán)境變量/配置文件來初始化;
- 業(yè)務(wù)邏輯中的可變數(shù)據(jù)與配置,可以通過apollo/iconf實(shí)時(shí)下發(fā)和生效,無需代碼修改和長流程上線。例-可以通過開箱即用的配置中心功能,實(shí)時(shí)下發(fā)并生效配置:
3.3 如何快速感知并定位問題?
- 開發(fā)者如何快速感知服務(wù)中的問題,嚴(yán)重問題如何實(shí)時(shí)感知?
- 開發(fā)者如何能從監(jiān)控、日志、報(bào)警中獲得詳細(xì)的問題信息,以快速定位問題?
3.3.1 完善的事件追蹤定位與通告能力
能夠?qū)崟r(shí)追蹤開發(fā)者自定義的錯(cuò)誤并通告
- 實(shí)時(shí)事件追蹤組件:sentry。hulk提供了開箱即用的sentry組件功能,可以像打印日志一樣使用,sentry中的信息包含代碼調(diào)用棧、上下文、自定義關(guān)鍵信息等:
- 通告組件:ruliu。一行token配置就可以開啟如流功能,可以將一些需要立即關(guān)注的信息實(shí)時(shí)打到如流群里,同時(shí)還可以和sentry結(jié)合,實(shí)現(xiàn)異常問題實(shí)時(shí)感知和定位:
3.3.2 prometheus sia監(jiān)控支持
通過prometheus與noah的互補(bǔ),支持多維度全方位監(jiān)控,能夠獲得更多的服務(wù)穩(wěn)定性相關(guān)信息
- prometheus為開發(fā)者提供靈活的多維度的業(yè)務(wù)監(jiān)控信息;
- sia可以為開發(fā)者提供基于日志的采集的服務(wù)穩(wěn)定指標(biāo)和容器、網(wǎng)絡(luò)等資源維度監(jiān)控信息;
3.3.3 ftrace日志查詢與分析功能
hulk默認(rèn)支持ftrace平臺(tái)的日志格式
- 通過ftrace,可以便捷高效的查詢用戶維度的日志信息;
- 通過pdo2命令,可以檢索查詢自定義規(guī)則的日志信息;
3.4 基于hulk的服務(wù)可視化和故障智能定位系統(tǒng)
artemis是我們基于hulk研發(fā)的一款服務(wù)可視化與故障智能定位追蹤系統(tǒng),它集服務(wù)部署架構(gòu)可視化、近實(shí)時(shí)多維度監(jiān)控、關(guān)鍵日志、服務(wù)調(diào)用鏈等多方面信息,可以快速、高效、精準(zhǔn)的發(fā)現(xiàn)和定位穩(wěn)定性問題。
該系統(tǒng)目前已接入好看/全民/度咔等多個(gè)后端服務(wù),極大加速了故障定位效率。在一些故障場景,可以秒級(jí)定位問題,給出問題的代碼行。
3.4.1 服務(wù)部署架構(gòu)
通過實(shí)例列表,可以獲取服務(wù)的idc列表、instance列表和詳情,并提供了便捷高效的調(diào)試入口和登錄指令:3.4.2 近實(shí)時(shí)多維度監(jiān)控
artemis提供的近實(shí)時(shí)監(jiān)控,能夠提供更多維度信息,這些維度是sia和prometheus無法提供的,如:- 某個(gè)URI下面的某個(gè)下游(或下游實(shí)例)RAL的QPS、耗時(shí)、可用性;
- 某個(gè)服務(wù)實(shí)例實(shí)例的URI或RAL的監(jiān)控信息;
3.4.3 關(guān)鍵日志
由于與hulk的深度集成,在業(yè)務(wù)代碼中打印warning級(jí)別以上的日志時(shí),artemis能拿到更多的日志信息,如-各維度信息、調(diào)用棧、上下文等:3.4.4 服務(wù)調(diào)用鏈
在hulk框架的協(xié)助下,artemis還可以獲取到URI及URI所依賴的RAL調(diào)用信息,由此可以構(gòu)建出請(qǐng)求調(diào)用鏈,并實(shí)時(shí)展示調(diào)用鏈上的相關(guān)metrics信息:不同顏色的鏈路代表不同的可用性:紅色-1個(gè)9及以下,黃色-2個(gè)9,藍(lán)色-3個(gè)9,灰色-4個(gè)9。通過服務(wù)調(diào)用鏈,可以非常直觀的看到服務(wù)里,哪個(gè)接口有問題,還可以看到哪些下游影響了這個(gè)接口的可用性。
3.4.5 使用案例
通過與報(bào)警系統(tǒng)的聯(lián)動(dòng),可以在發(fā)生報(bào)警的第一時(shí)間,在artemis系統(tǒng)中找到受影響的服務(wù)及URI,確定是否是下游引起,錯(cuò)誤是什么,哪一行代碼報(bào)了錯(cuò)等,以下是一個(gè)artemis的實(shí)際應(yīng)用示例。四、總結(jié)
hulk雖然是?個(gè)新的go語?web框架,但不是重復(fù)造輪,?是站在?內(nèi)和開源軟件的基礎(chǔ)上,結(jié)合業(yè)務(wù)實(shí)際開發(fā)、部 署、運(yùn)?、運(yùn)維環(huán)境,對(duì)這些開源框架和?具進(jìn)?取?補(bǔ)短、?次開發(fā),最終切合實(shí)際的業(yè)務(wù)使?場景。同時(shí),圍繞hulk初步構(gòu)建起的go生態(tài),為服務(wù)在開發(fā)、部署、運(yùn)行、運(yùn)維等各個(gè)階段都提供了有力支持。
最后,希望短視頻研發(fā)部在go服務(wù)化架構(gòu)升級(jí)/研發(fā)框架上的?些實(shí)踐、?案和經(jīng)驗(yàn),能夠給有相同架構(gòu)升級(jí)需求、 在go項(xiàng)?實(shí)踐中遇到問題的其他業(yè)務(wù)線同學(xué)?些幫助和參考。
五、附錄 (外網(wǎng)不可訪問)
1. 框架及使??檔:http://hulk-go.baidu-int.com/2. hulk底層是基于GDP2的,了解gdp也更有助于了解hulk:http://gdp.baidu-int.com/
會(huì)吹牛逼真的很重要
關(guān)于堆棧的講解(我見過的最經(jīng)典的)
寫出高效代碼的12條建議