日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

魅族 C++ 微服务框架技术内幕揭秘

發(fā)布時間:2024/9/21 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 魅族 C++ 微服务框架技术内幕揭秘 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2019獨角獸企業(yè)重金招聘Python工程師標準>>>

分享嘉賓簡介:魅族科技平臺事業(yè)部于洋子,專注于高并發(fā)高性能服務(wù)端架構(gòu)設(shè)計與開發(fā),參與過flyme通訊、推送平臺、實時大數(shù)據(jù)統(tǒng)計等項目。

kiev,是魅族科技推送平臺目前使用的C++后臺開發(fā)框架。2012年,魅族的推送業(yè)務(wù)剛剛有一點從傳統(tǒng)架構(gòu)向微服務(wù)架構(gòu)轉(zhuǎn)型的意識萌芽,為了在拆分系統(tǒng)的同時提高開發(fā)效率,決定做一個C++開發(fā)框架,這就是最早期Kiev的由來。在不斷的演變中,框架也經(jīng)過了多次調(diào)整升級,在此一一進行講述和揭秘??蚣苁菫榧軜?gòu)在做服務(wù),所以整篇內(nèi)容會在架構(gòu)演進和框架演進兩條線之間交錯展開。

第一版:沒有開發(fā)框架

首個版本的架構(gòu)非常簡單粗暴,首先開一個WEB接口,接入PUSH,再開一個TCP長連接的接口,讓手機連上。這么做的目的就是為了能快速上線。不過快是快了,問題也很嚴重。這個版本沒有開發(fā)框架,完全從socket寫起,不僅難寫,而且不能水平擴展,承載能力也非常有限。

第二版:框架首次出現(xiàn)

隨著魅族用戶量級的快速提升,很快迭代了第二個版本。第二版首次出現(xiàn)了開發(fā)框架,命名為“Kiev”。這個版本對手機連接的部分進行了拆分,拆出接入層和路由層,業(yè)務(wù)層支持水平擴展,這樣重構(gòu)以后抗住了百萬級的用戶量。不過同樣存在不少問題,因為還是在用普通的HASH算法在做均衡負載,擴容非常不平滑,容易影響用戶體驗。而且隨著用戶量的增長,日志量變的非常多,甚至都要把磁盤刷爆。此外,由于使用的文本協(xié)議很臃腫,當某一天中午12點推送高峰期的時候,整個公司的機房帶寬都被吃完,其他業(yè)務(wù)受到了不同程度的干擾。

這個版本的框架如下,左上角是Kiev協(xié)議,左下角是使用到的一些開源的第三方庫?,包括谷歌開源的Protobuf、用于加解密的Openssl、 用于支持HTTP的Curl、優(yōu)化內(nèi)存分配的Tcmalloc等。右上角是Kiev框架的功能組件,包括提供HTTP接口的FastCGI、一些常用的算法和數(shù)據(jù)結(jié)構(gòu)、日志模塊、編碼常用的定時器以及一個自研的單鏈接能達到10W+QPS的Redis Client。

第三版:增加限速、業(yè)務(wù)流程優(yōu)化、日志切割和壓縮

考慮到前面說到的帶寬撐爆問題,第三版增加了限速模塊。此外還做了一個業(yè)務(wù)流程上的優(yōu)化,使用redis存儲離線消息,用戶上線時再推送出去。負載均衡上,改用一致性HASH算法,這樣做的好處是每次擴容受到影響的只有遷移的那一部分用戶,另一部分用戶則不會受任何影響,擴容變得平滑了很多。針對日志刷爆磁盤的問題,做了一個每天定時切割和壓縮日志的腳本。

看看這個版本在框架上做的一些修改,圖中深色部分為新增的東西:

第四版:全面重構(gòu)

為了徹底解決第二版的一些問題,花了半年多的時間對框架進行全面重構(gòu)。重構(gòu)主要針對以下幾點:

一是將限速、接入層、路由層、邏輯層等都做成了無狀態(tài)服務(wù),這樣的話在整個擴容的過程中可以做到完全平滑;

二是對協(xié)議進行優(yōu)化,將原本臃腫的文本協(xié)議改為二進制協(xié)議,協(xié)議頭從700字節(jié)降到6個字節(jié),大幅度降低了流量;

三是流程上的優(yōu)化,這個還是趨于流量的考量。大家都知道移動互聯(lián)網(wǎng)有個很顯著的特點,就是手機網(wǎng)絡(luò)特別不穩(wěn)定,可能這一秒在線,下一秒走進電梯就失去信號,這個時候如果直接進行消息推送的話,既浪費機房帶寬,又沒效果,而且還可能會出現(xiàn)重復推送的問題。所以針對這種情況,魅族的做法是每次先推一個很小的只有幾個字節(jié)的消息過去,如果手機端的網(wǎng)絡(luò)穩(wěn)定,它會回復一個同樣很小的消息,這時候再真正進行消息推送,這樣可以有效利用帶寬資源。而且給每一條消息打上唯一的序號,當手機端每次收到消息時,會將序號儲存起來,下次拉取消息的時候再帶上來,比如某用戶已收到1、2、3的消息,拉取的時候把3帶上來,服務(wù)端就知道1、2、3都已經(jīng)推過了,直接推送4之后的消息即可,避免消息重復。

這個版本的框架改進比較小,在上個版本的基礎(chǔ)上引入MongoDBClient,對序號進行索引。

業(yè)務(wù)越做越大,發(fā)現(xiàn)新問題1

隨著業(yè)務(wù)越做越大,業(yè)務(wù)流程也變得越來越復雜。舉個栗子,魅族有一個業(yè)務(wù)流程中,請求過來時,會先和Redis來回交互幾次,然后才訪問MongoDB,最后還要和Redis交互幾次才能返回結(jié)果。

這種時候如果按早期的異步模式去寫代碼,會很難看??梢钥吹秸麄€業(yè)務(wù)流程被切割的支離破碎,寫代碼的和看代碼的人都會覺得這種方式很不舒服,也容易出錯。

針對這種復雜的問題,魅族引入了“協(xié)程”,用仿造Golang的方式自己做了一套協(xié)程框架Libgo。重構(gòu)后的代碼變成如下圖左側(cè)的方式,整個業(yè)務(wù)流程是順序編寫的,不僅沒有損失運行的效率,同時還提高了開發(fā)的效率。

Libgo的簡介和開源地址如下:

  • 提供CSP模型的協(xié)程功能
  • Hook阻塞的系統(tǒng)調(diào)用,IO等待時自動切換協(xié)程
  • 無縫集成使用同步網(wǎng)絡(luò)模型的第三方庫 (mysqlclient/CURL)
  • 完善的功能體系:Channel / 協(xié)程鎖 / 定時器 / 線程池等等

開源地址:https://github.com/yyzybb537/libgo

業(yè)務(wù)越做越大,發(fā)現(xiàn)新問題2

在這個時期,在運營過程中有遇到一個問題,每天早上9點鐘,手機端會向服務(wù)端發(fā)一個小小的訂閱請求,這個請求一旦超時會再來一遍,不斷重試。當某天用戶量增長到1300萬左右的時候,服務(wù)器雪崩了!

雪崩的原因是因為過載產(chǎn)生的,通過分析發(fā)現(xiàn)過載是在流程中的兩個服務(wù)器間產(chǎn)生的。服務(wù)器A出現(xiàn)了大量的請求超時的log,服務(wù)器B出現(xiàn)接收隊列已滿的log,此時會將新請求進行丟棄。此時發(fā)現(xiàn),在服務(wù)器B的接收隊列中積壓了大量請求,而這些請求又都是已經(jīng)超時的請求,手機端已經(jīng)在重試第二次,所以當服務(wù)器拿起之前這些請求來處理,也是在做無用功,正因為服務(wù)器一直在做無用功,手機端就會一直重試,因此在外部看來整個服務(wù)是處于不可用狀態(tài),也就形成了雪崩效應(yīng)。

當時的緊急處理方式是先對接收隊列的容量進行縮小,提供有損服務(wù)。所謂的有損服務(wù)就是當服務(wù)器收到1000個請求但只能處理200個請求時,就會直接丟棄剩下的800個請求,而不是讓他們排隊等待,這樣就能避免大量超時請求的問題。

那緊急處理后,要怎么樣根治這個問題呢?首先對這個過載問題產(chǎn)生的過程進行分析,發(fā)現(xiàn)是在接收隊列堵塞,所以對接收點進行改造,從原來的單隊列變?yōu)槎嚓犃?#xff0c;按優(yōu)先級進行劃分。核心級業(yè)務(wù)會賦予最高級的優(yōu)先處理隊列,當高優(yōu)先級的請求處理完后才會處理低優(yōu)先級的請求。這樣做的就能保證核心業(yè)務(wù)不會因為過載問題而受到影響。

還有一點是使用固定數(shù)量的工作協(xié)程處理請求,這樣做的好處是可以控制整個系統(tǒng)的并發(fā)量,防止請求積壓過多,拖慢系統(tǒng)響應(yīng)速度。

業(yè)務(wù)越做越大,發(fā)現(xiàn)新問題3

在最早的時候,這一塊是沒有灰度發(fā)布機制的,所有發(fā)布都是直接發(fā)全網(wǎng),一直到機器量漲到上百臺時依然是用這種方式,如果沒問題當然皆大歡喜,有問題則所有一起死。這種方式肯定是無法長遠進行,需要灰度和分組。但由于服務(wù)是基于TCP長連接的,在業(yè)內(nèi)目前沒有成熟的解決方案,所以只能自己摸索。

當時的第一個想法是進行分組,分為組1和組2,所有的請求過來前都加上中間層。這樣做的好處是可以分流用戶,當某一組出現(xiàn)故障時,不會影響到全部,也可以導到另外一組去,而且在發(fā)布的時候也可以只發(fā)其中一組。

那中間層這一塊要怎么做呢?在參考了很多業(yè)界的成熟方案,但大多是基于HTTP協(xié)議的,很少有基于TCP長連接的方案,最終決定做一個反向代理。它的靈感是來源于Nginx反向代理,Nginx反向代理大家知道是針對HTTP協(xié)議,而這個是要針對框架的Kiev協(xié)議,恰好魅族在使用ProtoBuf在做協(xié)議解析,具有動態(tài)解析的功能,因此基于這樣一個功能做了Kiev反向代理的組件。這個組件在啟動時會向后端查詢提供哪些服務(wù)、每個服務(wù)有哪些接口、每個接口要什么樣的請求、回復什么樣的數(shù)據(jù)等等。將這些請求存儲在反向代理組件中,組成一張路由表。接收到前端的請求時,對請求的數(shù)據(jù)進行動態(tài)解析,在路由表中找到可以處理的后端服務(wù)并轉(zhuǎn)發(fā)過去。

第五版:針對問題,解決問題

有了上述這些規(guī)則后,第五版也就是目前使用的版本部署如下圖。對邏輯層進行了分組,分流用戶。在實際使用過程中精準調(diào)控用戶分流規(guī)則,慢慢進行遷移,一旦發(fā)現(xiàn)有問題,立即往回倒。此外,還精簡了存儲層,把性價比不高的MongoDB砍掉,降低了70%的存儲成本。

很多項目特別是互聯(lián)網(wǎng)項目,在剛剛上線的時候都有個美好的開始,美好之處在于最初所有服務(wù)的協(xié)議版本號都是一樣的。就比如說A服務(wù)、B服務(wù)、C服務(wù)剛開始的時候全都是1.0,完全不用去考慮兼容性問題。當有一天,你需要升級了,要把這三個服務(wù)都變成2.0的時候,如果想平滑的去升級就只能一個一個來。而在這個升級的過程中,會出現(xiàn)低版本調(diào)用高版本,也會出現(xiàn)高版本調(diào)用低版本的情況,特別蛋疼,這就要求選擇的通訊協(xié)議支持雙向兼容,這也是魅族使用Protobuf的原因。

最終,完整的框架生態(tài)如下。虛線框內(nèi)為后續(xù)將加入的服務(wù)。

魅族消息推送服務(wù)的現(xiàn)狀

該服務(wù)在過去的4年多來一直只是默默的為魅族的100多個項目提供,前段時間,正式向社區(qū)所有的開發(fā)者開放了這種推送能力,接入的交流群:QQ488591713。目前有3000萬的長連接用戶,為100多個項目提供服務(wù)。集群中有20多個微服務(wù)和數(shù)百個服務(wù)進程,有100多臺服務(wù)器,每天的推送量在2億左右。

(文章內(nèi)容由開源中國整理自2016年9月10日的【OSC源創(chuàng)會】珠海站,轉(zhuǎn)載請注明出處。)

轉(zhuǎn)載于:https://my.oschina.net/osccreate/blog/752986

總結(jié)

以上是生活随笔為你收集整理的魅族 C++ 微服务框架技术内幕揭秘的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。