Go語言構建千萬級線上的高並發訊息推送系統實踐(來自360公司)-推送開發/專項技術區

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

1、前言


Go語言的滲透率越來越高,同時大家對Go語言實戰經驗的關注度也越來越高。Go語言在高並發、通訊互動複雜、重商務邏輯的分布式系統中非常適用,具有開發體驗好、一定量級下服務穩定、效能滿足需要等優勢。

本文內容整理自奇虎360公司的周洋在 Gopher China 2015 大會上的分享(演講PPT下載:《Go語言構建高並發訊息推送系統實踐PPT(來自奇虎360)[附件下載] 》),該次分享以360海量線上的訊息推送系統為例,來探討使用Go語言構建高並發訊息推送系統時所遇到的問題以及總結出的各種實踐技巧。

2、Go語言在基礎服務開發領域的優勢


Go語言在高並發、通訊互動複雜、重商務邏輯的分布式系統中非常適用,具有開發體驗好、一定量級下服務穩定、效能滿足需要等優勢。以360訊息推送系統為例,目前360訊息推送系統服務於50+內部產品,萬款開發平台App,即時長串連數億量級,日獨數十億量級,1分鐘內可以實現億量級廣播,日下發峰值百億量級,400台物理機,3000多個執行個體分布在9個獨立叢集中,每個叢集跨國內外近10個IDC。

經過兩年的迭代,該系統功能上需要做一些擴充,支援聊天情境業務,穩定支援多款聊天業務App,單通道多App複用,長串連支援上行,支援不同力度的回調,對智能硬體產品,提供定製化訊息推送與轉寄服務。

機器效能方面,該系統的單機在測試環境下,如果只掛長串連(系統參數調優之後),資料往往取決於掉線率。在串連穩定的情況下發出廣播,心跳時間不受影響,內部QPS在一個可接受的狀態達到300W長串連的壓測。線上單機實際使用最高160W長串連,分兩個執行個體。QPS的線上情境跟出口頻寬、協議輕重程度、接入端網路狀況及商務邏輯有關,但只要關閉影響I/O的因素,不通過加密的協議純效能去抓資料,QPS可達2~5萬,但如果加密較多,QPS會下降。

11.png (88.23 KB, 下載次數: 20)

下載附件 儲存到相簿

6 個月前 上傳



另外,該訊息推送系統重邏輯,整個系統由圖片互動完成整個推送功能。接入端流程主要由用戶端提供的各SDK接入Dispatcher伺服器,在用戶端進行選入時,會對Dispatcher伺服器上傳一些資料,根據傳入的相關狀況進行選入服務,將Room Service的IP或者網域名稱傳送給相關用戶端,用戶端基於當前網路情況對IP做策略的緩衝,再通過對緩衝IP與當前的Room Service做一個長串連。

Room Service在未做業務和架構拆解之前邏輯非常重,基本要與後面所有的服務進行遞進,而它本身還要承載上百萬的長串連業務。這種Service的邏輯主要重在內部通訊、外部通訊及對外串連的互動上。

首先,使用者接入長串連,長串連Room Service需要對使用者的身份進行驗證,還要支援公司各種產品、安全相關、回調相關業務的認證接入;其次,身份接受認證之後,要做後端的串連者Service,即記憶體儲存做一個通訊,將使用者與他所在的Room和Room身份綁定(註冊操作),單串連涉及到解除綁定、多次綁定、綁定多個使用者等互動邏輯。

使用者接入時可能會出現閃斷,要對閃斷(由於網路切換造成服務端未及時發現斷線的情況)之前的訊息進行遷移,各種操作都在這個邏輯裡進行。作為一個Room Service,要與後端的Coordinator服務進行互動,由於資料的上下行,使用者聯絡時可能會上傳各種資料(比如音頻或者簡單的資料流),通過Coordinator伺服器回調回來,相關的接入方拿到用戶端的上行資料,Room Service便要做安全性原則、白名單、IP限制策略,然後與自己寫的ZooKeeper/Keeper進行通訊。後端的另一個邏輯,比如使用者進入時要載入一些訊息,這時可能要用儲存訪問層(Saver Service)進行,所以Saver Service也要進行載入、儲存訊息等業務。該訊息系統本身也有商務邏輯,比如按產品、協議來定載入訊息的策略,包括全球廣播時對廣播的資訊做臨時緩衝。

總之,Room是整個Service最重要的一點,如果用C語言重構,儘管架構拆解很好,但因為這些邏輯始終要存在,所以會增加一些通訊的開銷。Go在開發這種重邏輯時,所有的邏輯都集中在最前端,而且是在互動通訊最頻繁的地方,所以,Go語言對這種重邏輯非常適用。

API接入層會有一個Center Service負責所有的App接入方,它們將通過Center Service做一些簡單的認證,然後將訊息發到叢集內部。比如發一條單播給一個使用者,先請求Register擷取這個使用者,Center擷取到這個使用者之後再與Router Service進行通訊,擷取註冊的串連通道標識、伺服器,然後與它進行通訊再下發給長串連。Center Service比較重的工作如全國廣播,需要把所有的任務分解成一系列的子任務,然後在所有的子任務裡調用串連的Service、Saver Service擷取線上和離線的相關使用者,再集體推到Room Service,所以整個叢集在那一瞬間壓力很大。可見,整個系統通訊較複雜,架構拆解之後也有很重的邏輯。

22.png (105.87 KB, 下載次數: 20)

下載附件 儲存到相簿

6 個月前 上傳



雖然它邏輯重,但程式基本是線性。從可以看出,基本任務相當於對每個使用者開協程。所有邏輯都是在兩個迴圈內完成(如註冊操作)。用戶端要顯示,該阻塞就阻塞。通常情況下,心跳響應要及時,心跳的主迴圈中要省心跳,這時要用非阻塞I/O,通過通道的方式集中控制、管理、操作,然後通過非同步方式再回來,整個迴圈的關鍵是要及時響應ping包的服務。因此,邏輯再好,基本上集中在兩個協程之內,而且無論什麼時侯讀代碼,它都是線性。

3、Go與C開發體會的對比


33.png (171.85 KB, 下載次數: 17)

下載附件 儲存到相簿

6 個月前 上傳



當遇到瓶頸又不知道能用Go提高多少效率時,他們寫了C語言的開發。用C語言要用Oneloop per thread原則,根據業務資料處理需求開一定量線程,由於每個線程的I/O不能阻塞,所以要採用非同步I/O的方式,每個線程有一個eventloop。一個線程為幾萬使用者服務會產生一個問題,要記錄一個使用者當前所在的狀態(註冊、載入訊息、與Coordinator通訊)並做維護,這時,寫程式是在做狀態的排列組合,如果程式是別人寫的,就需要考慮新加的邏輯是否會影響之前排列組合的運行,是否能讓之前正常啟動並執行程式繼續運行。所以,寧可使用Go語言通過最佳化之後效能降低一點,拆解架構讓機制減少,也不能為了用C語言而寫特別重的邏輯。

4、實踐中遇到的挑戰


遭遇的挑戰:

44.png (102.52 KB, 下載次數: 15)

下載附件 儲存到相簿

6 個月前 上傳



遇到的問題:
所有的機器記憶體都在50~60G,最高時為69G,機器時間最終達到GC3-6s。該系統的第一個版本單機一百萬的串連是五個月的,對內的通訊和對外刷資料的時侯頻率非常低,只有一些單波訊息,大概每天只有200多條,所以QPS每秒只有幾個,而廣播訊息一個月只有2~3條。該系統的業務採用Go,用Push下發一些非資訊類的內容,這些指令造成整個系統的負載長期維持在一個較高的QPS。

遇到的瓶頸:
  • 散落在協程裡的I/O,Buffer和對象不複用;
  • 奔放的協程使用,網路環境不好引起激增;
  • 機器時間2~3秒,如果機器時間長會影響接入方的QPS,在2~3分鐘的時間會卡住一條請求,如果內部通訊多,每個組件都支援響應,使用者就有可能會被業務方認為逾時進行重試,這樣對系統造成更多的壓力,系統會步入惡性迴圈;
  • 記憶體暴漲,I/O阻塞,協程激增。

5、可行的應對方式


1經驗一


Go語言程式開發需要找到一種平衡,既利用協程帶來的便利性又做適當集中化處理。當每一次請求都變成一個協程,那在每個協程之內是否有必要再去開一些協程解耦邏輯,這時使用任務池集中合并請求、串連池+Pipeline利用全雙工系統特性提高QPS。

55.png (43.94 KB, 下載次數: 8)

下載附件 儲存到相簿

6 個月前 上傳



首先要改造通訊庫,在程式裡直接調用一個I/O操作註冊執行,不能用短串連。因為對系統績效參數做過最佳化,正常通訊的時候約10萬個連接埠可用。雖然短串連通訊本身沒問題,但短串連會建立很多個物件(編碼Buffer、解碼Buffer、服務端的編碼Buffer、 Request對象、Response對象、服務端的Request對象、Response對象)。短串連還用了開源的RPC,用各種Buffer都會出現問題。

通訊庫做一版的迭代,第二版則用了一些值,相當於表面上阻塞的調用了I/O,但實際從串連池拿出一個請求Request,供服務端享用,然後拿到Response再把串連放回去。這樣做很多資源(包括Buffer、Request、Response,Sever端、Client端)串連池可以複用。對所有對象做記憶體複用,但它實際是線上的,所以拿出一個串連往裡面寫資料等服務端響應,響應後再讀取,這時服務端回應時間決定串連的佔用時間。第三版要寫一個Pipeline操作,Pipeline會帶來一些額外的開銷,這裡的Pipeline指串連是全雙工系統複用的,任何人都可以隨時往裡寫,請求之後阻塞在相關通道上面,由底層去分配一個串連,最後這個串連釋放留給其它人去寫。整個可以用TCP的全雙工系統特性把QPS跑滿,經過集中化處理,RPC庫會達到較好的效應,創業公司可以選擇GRPC。對於像360訊息推送的系統,如果不能控制每個環節就會出問題。如果代碼不自己寫,別人的代碼再簡單用起來也會非常困難,如用RPC判斷錯誤類型、調整錯誤類型這種最簡單的情況,返回的Error是個字串,因此要分析到底是編碼問題、網路問題,還是對波返回一個錯誤資訊需要處理,這時商務邏輯層要對RPC做一個字串的判斷。

QPS在RPC上達到較高效能,其實還可以最佳化,在網路連接上,編解碼的難度取決於對業務的需求。整個RPC庫能夠提高的效率達到瓶頸後,剩下就是怎樣減少RPC調用。RPC上的資料是寫滿的,在不停地運行,對RPC調用時,要把整塊的資料都寫到RPC串連上,寫完串連馬上就釋放給別人用,如果期望減少調用次數,每次盡量寫入多個資料。

串連池上要根據業務做一個任務池,換成任務池後(對不同的介面放不同的任務池),在任務池裡接收通道的一些資料,再在任務池裡面打包請求,最後對多條資料做一次RPC調用。這樣,RPC串連上的瞬間也降低了次數,減少了串列機率。批量調用屬於業務層級的最佳化,RPC介面支援批量的處理,但批量調用後,如果QPS的請求量少,構出的協程就少。開的協程少不會提高效率。在網路不好、阻塞的情況下,每接收一次請,協程暴漲會導致阻塞,如果裡面有流控,協程就會把記憶體崩上去,這也是有些機器隔幾天就會記憶體暴漲還降不下去的原因。通過這種方式減少了協程調用次數,系統效能沒有特別大的提高,但在任務池可以做流控,當隊列超過一定長度可以做策略,重要的介面要重試,不重要的丟掉。流控可以在RPC底下做,但RPC不識別介面,它沒法決定在出現流控策略時是選擇丟掉還是定義的介面操作。任務池+Pipeline的串連池可以把整個系統的輸送量達到最高(不是QPS)。

2經驗二


Go語言開發追求開銷最佳化的極限,謹慎引入其他語言領域高效能服務的通用方案。

主要關注記憶體池、對象池適用於代碼可讀性與整體效率的權衡。這種程式一定情況下會增加串列度。用記憶體一定要加鎖,不加鎖用原理操作有額外的開銷,程式的可讀性會越來越像C語言,每次要malloc,各地方用完後要free,free之前要reset,各種操作做完之後會發現問題。這裡的最佳化策略是仿達達做的資料架構,然後做了一個仿Memorycache形式的記憶體池。

66.png (64.77 KB, 下載次數: 15)

下載附件 儲存到相簿

6 個月前 上傳



左邊的數組實際上是一個列表,這個列表按大小將記憶體分塊。在協議解期時不知道長度,需要動態計算長度,所以申請適配的大小不夠,就把這塊還回去再申請一個Bucket。加入記憶體池之後減少了一些機器的開銷,但是程式的可讀性嚴重降低。

對象池策略本身有一個Sync庫的API,在申請對象的時候要做清理操作,包括通道的清理,防止有障資料,增加開銷。其實CPU大部分時間是閒置,只有在廣播的時候比較高,加上這兩個策略之後,程式的串列度提高,記憶體的機器時間加長,但QPS不一定上升。

6、具有Go特色的營運


依託Go語言做一些常規的營運工作需要一些常識。線上處理就是看一下協程在F上是否有協程疏漏、高阻塞。因為有時看不到,所以他們對線上的執行個體監控做了一個統一的管理和可視化操作。Go語言提供配套的組合工具做一些更方便開發調試的機制。第一點是Profiling可視化,可以從中發現記錄,出現問題時的峰值、協程數,可以比較兩次上線完之後進程到了什麼樣的狀態。比如營運的時候做一個分析群,然後把一部分的產品分到一個單獨叢集上,發現這個叢集總比另一個叢集多4到5個記憶體(程式是同一個),直接開啟圖就非常明了地顯示。在一個Buffer中,這個叢集明顯較大的原因是兩年前做了一個策略防止重新拷貝。當時寫的邏輯針對每個產品開Buffer,開了一百萬。這個叢集就是一個開源平台,上面有上萬個App,數值提供的時候明顯不是同一個圖,它的Buffer更大。各種問題都可以通過對Go語言提供的Profiling、協程、本機機器時間、相關數量進行監控。

另外,通訊可視化,長串連調用基本是RPC調用,RPC庫、Redis的庫、MySQL庫給力,整個系統就可控。所以要對RPC庫、Redis的庫做各種代碼內嵌,要統計它的QPS、網路頻寬佔用、各種出錯情況。然後再通過各種壓測手段,發現要做的最佳化對效能是否有影響。如果一個系統不可評估就無法最佳化,而如果可評估就會發現一些潛在的問題。通訊可視化是在RPC庫和Redis庫植入自己的代碼。其實選擇RPC庫並不重要,重要的是能夠對它改造、監控。

可視化還可以做壓測。由於壓測不能出即時的資料,可選一百台機器,對一台進行壓測,通過後台看各種績效參數,然後通過RPC庫的結構判斷各資料。壓測完後,每一個壓測的進程要匯總統計資料,業務的QPS數量、協議版本、串連建立成功的時間和每秒鐘建立串連數量,這些細節的績效參數決定系統的潛在問題,因此,壓測平台最好要做統計資料的功能。360的團隊做了一個簡單的壓測後台,可以選定一些機器進行壓測。一台機器壓測由於網路問題和機器本身的CPU線路無法測出問題。因此,壓測時最好選十幾台機器,每台機器開10段串連做壓測。

77.png (97.86 KB, 下載次數: 15)

下載附件 儲存到相簿

6 個月前 上傳



營運對線上進行拆分,可以減少機器時間,但營運壓力變大。通過開協程的方式解決相當於把這台機器轉嫁到各個進程上,雖然機器時間短,但頻繁次數多,所以問題並未得到解決。開多進程可以節省時間,但卡頓時間和體量變成漸進性。系統根據使用的各種資源不同可做一個橫向拆分,按業務拆分(助手、衛士、瀏覽器)、功能拆分(push、聊天、嵌入式產品)和IDC拆分(zwt、bjsc、bjdt、bjcc、shgt、shjc、shhm、Amazon Singapore),拆解後帶來管理成本,引入(ZooKeeper+deployd)/(Keeper+Agent)對各節點進行管理。

正常情況下,營運都採用ZooKeeper管理各個進程的動態設定檔。第二部分相當於Profiling資料,用後台去各個進程中請求,即時監控各個介面,通訊錄的資料也通過後台進行請求,這時Keeper的節點要配置,後台也要配置。這種功能可以抽象一下,理論上期望用戶端有個SDK,中心節點有個Keeper,然後可以對設定檔進行管理,對Profiling、自己寫的各種庫的資訊進行收集,再匯總,放到本機資料或者檔案夾,通過介面對後台提供服務。服務通過網路進行啟動,管理層集中在Keeper上而不是在後台和Keeper上,所以Keeper的同步會考慮用一些開源的東西。360團隊寫了一些工具把正常的設定檔用Key-Value的形式支援一些Map結構,反序相當於寫了一個Convert工具。剩下的用Profiling,相當於跟Keeper和節點進行通訊,所以Profiling會很高。Keeper的啟動相當於用一個Agent啟動進程,然後指定Keeper中心節點連接埠把資訊傳過去,當Keeper正好配了這個節點就能把配置發過去,如果沒有配就丟失。

7、演講PPT下載


本文內容根據360公司的周洋在Gopher China大會上的技術分享整理而成,希望對大家有所協助。該次演講的PPT稿講下載請至:《Go語言構建高並發訊息推送系統實踐PPT(來自奇虎360)[附件下載]》。

8、更多有關推送技術的文章


《iOS的推送服務APNs詳解:設計思路、技術原理及缺陷等》
《Android端訊息推送總結:實現原理、心跳保活、遇到的問題等》
《掃盲貼:認識MQTT通訊協定》
《一個基於MQTT通訊協定的完整Android推送Demo》
《IBM技術經理訪談:MQTT協議的制定曆程、發展現狀等》
《求教android訊息推送:GCM、XMPP、MQTT三種方案的優劣》
《移動端即時訊息推送技術淺析》
《掃盲貼:淺談iOS和Android後台即時訊息推送的原理和區別》
《絕對乾貨:基於Netty實現海量接入的推送服務技術要點》
《移動端IM實踐:Google訊息推送服務(GCM)研究(來自)》
《為何、QQ這樣的IM工具不使用GCM服務推送訊息?》
《極光推送系統大規模高並發架構的技術實踐分享》
《從HTTP到MQTT:一個基於位置服務的APP資料通訊實踐概述》
《魅族2500萬長串連的即時訊息推送架構的技術實踐分享》
《專訪魅族架構師:海量長串連的即時訊息推送系統的心得體會》
《深入的聊聊Android訊息推送這件小事》
《基於WebSocket實現Hybrid行動裝置 App的訊息推送實踐(含程式碼範例)》
《一個基於長串連的安全可擴充的訂閱/推送服務實現思路》
《實踐分享:如何構建一套高可用的移動端訊息推送系統?》
《Go語言構建高並發訊息推送系統實踐(來自360公司)》
>> 更多同類文章 ……

(原文連結:點此進入)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.