洪增林:網易遊戲統一資料流平臺架構與實踐

趙鈺瑩發表於2018-08-16

【IT168 專稿】本文根據洪增林老師在2018年5月12日【第九屆中國資料庫技術大會】現場演講內容整理而成。

講師簡介: 

洪增林,網易遊戲資深開發工程師,網易遊戲資料中心開發負責人,專注於統一資料流建設、大資料作業平臺設計開發和大資料元件優化等工作。

摘要:

1. 網易遊戲的資料業務特點和資料流的挑戰 2. 資料流採集架構和實踐 (1). 資料流平臺架構 (2). 伺服器日誌採集的設計與實現 (3). 客戶端資料提交入口設計 (4). 後續迭代計劃 3. 基於資料流支撐的業務介紹 (1). 遊戲資料整合 (2). 程式/運維類日誌歸集與應用 (3). 通用資料處理和轉換 4. 總結展望 技術點:日誌歸集、資料整合、資料流平臺、golang、高併發、效能優化 面向人群:大資料平臺設計和開發人員

分享大綱:

1、網易遊戲統一資料流背景

2、統一資料流架構

3、資料流業務實踐

4、想法與總結

正文:

一、網易遊戲統一資料流背景

首先,我簡單介紹一下網易遊戲開發部門,我們目前運營線上的遊戲有上百款。從2014年開始,公司從端遊市場轉向手遊,與端遊市場相比,手遊市場的研發週期大幅縮短,上線週期和迭代速度加快,對伺服器的需求量大增,以陰陽師為例,上線之前內部規劃採購幾十臺伺服器,上線之後預計砸了上千臺伺服器,基礎設施資料流波動非常大。此外,手遊生命週期相對較短,大部分遊戲半年之內熱度會明顯下降,如何有效回收利用資源成為一大難點。

總結來說,我們面臨的最大挑戰是應對突增資料(流量高峰)的能力,每天的新增資料大概在百TB級別,這些資料主要來自玩家運營資料、客戶端效能監控資料以及基礎架構資料。

  

    

以上是網易遊戲資料分析業務部分示意圖,我們團隊主要負責綠色模組以下的部分,我們在資料管道建設以及整個元件封裝上投入了很大精力,主要提供機器學習服務、實時計算、離線計算和OLAP能力。其中,OLAP部分主要使用Kylin和Presto實現。在此之上,我們不希望元件和計算儲存過多直接暴露給使用者,所以封裝了一些作業平臺以及SaaS服務。對於資料分析服務,下游通常會使用各種高大上的儲存和分析引擎以支援上游資料分析業務,所以我們需要一個穩健的資料流支撐。接下來,我主要想跟大家分享網易遊戲的資料流轉過程。 

 

如果你對日誌和資料流有所瞭解,那你對上圖一定不陌生。如果一家公司沒有統一的資料流,那麼資料生產方和使用方會非常混亂,這也是網易遊戲最開始的生存現狀。我們的資料大概有兩種來源,一是玩家客戶端;二是遊戲伺服器,但我們下游有非常多使用方,使用方之間相互呼叫混亂,我們希望最終可以出現統一的中間層(如下圖),目前我們也在用這種方式實踐整體架構。 

如果要做統一資料流層,我們就需要思考基本要求是什麼。在網易遊戲,我們做了如下幾點思考:一是資料歸集分發,我們希望將資料傳送到統一的中間層,因此需要對下游使用方進行統一分發;二是保證資料不重不丟;三是傳輸低延遲,因為下游有很多實時業務包括實時推薦,因此整體延時性不能太高;四是低成本,因為我們有很多海外節點,所以需要考慮節點之間傳輸不能佔用太多傳輸頻寬,需要把控整體成本不能過高。

二、統一資料流架構 

 

上圖為網易遊戲資料流平臺示意圖,我們的資料來源主要有三種途徑——伺服器日誌、客戶端日誌和資料庫,客戶端日誌存放了各種使用者行為日誌,比如玩家副本資訊等,資料庫可能會儲存一些業務資料,主要涉及MySQL資料庫、MongoDB等,三種來源的資料最終經過統一資料流平臺,將整個細節遮蔽最終放到Kafka叢集中。

下游,我們主要用到了一些元件,比如實時性相關的Storm、Spark Streaming和Flink;儲存、離線部分主要應用了HDFS、Hive、HBase三大元件。目前業務系統使用較多的是SQL元件,比如MySQL、MongoDB和Redis,這三者在我們內部基礎架構中有相應的SaaS服務。最後是Kafka叢集,我們的Kafka中涉及多個使用方,每個使用方的資料可能都是一個子集,因此我們需要進行額外分發,將某一個子集轉發到專門的Kafka topic中。

如果想把資料從客戶端和伺服器日誌流轉到資料中心,我個人認為大概需要兩個維度配合:客戶端和伺服器。我們希望可以將客戶端與伺服器統一放到伺服器日誌Agent層,也就是說,我們需要把客戶端玩家上傳的資料放到伺服器上。首先,我們需要一個外網資料API或者Proxy收集資料,之後統一用伺服器日誌Agent上傳。每個遊戲擁有自己的伺服器Agent,我們現在大概有幾萬臺遊戲伺服器,我們需要在每一臺重新部署Agent。 

 

日誌到達Agent之後,Agent負責統一定義要採集的資訊,然後動態掃描哪些檔案已經更新,讀取更新檔案的增量更新,傳遞到Kafka Proxy。整個過程中的大部分元件都是我們自研的,接下來我會具體介紹這些元件分別解決了哪些問題。

對於外網資料API,我認為最基本的兩個要求是高可用和高效能。如果做不到高可用,玩家上傳資料就可能會丟,即便客戶端可以重試,但重試也有上限。其餘兩個要求是全球主要Region和管理系統,因為網易遊戲是全球戰略,因此全球主要的Region,比如日本、北美、歐洲以及東南亞等均有發行,外網資料API也會發布到相應節點,底層直接使用AWS伺服器即可。至於管理系統,主要作用是降低整體成本。 

 

外網資料API主要通過web伺服器收集日誌請求並落盤,我們自研了高效能web端,可支援動態載入配置;日誌按照業務落盤,複用日誌Agent資料流;日誌rotate,監控metrics上報。一些開源元件也可實現上述操作,我們目前的整個流程如上圖所示。首先,客戶端通過https傳輸資料,這部分資料經過LB入口(海外走elb)到達伺服器後,我們會做三件事情,一是資料校驗,攔截非法請求和預期之外的資料提交;二是自定義資料轉換,我們會將全球所有資料放在一起分析,在前端根據域名直接將各區域的時區自動轉換好,三是持久化到檔案,第二步的資料轉換完成之後,我們就可以通過go channel將其持久化到檔案中,然後管理它的rotate。 

 

上圖為我們定義外網資料採集時自動生成的配置頁面,Web接收資料端會根據生成的配置監聽各域名提交資料的方法、磁碟位置以及rotate配置。這裡需要說明的一個問題是version,如果我們在中央區配置更新,這個版本號會自動重新整理,web端每隔一分鐘會進行一次輪詢,如果發現版本與記憶體版本不同就會觸發reload。我們通過這種方式解決配置自動載入問題,但並不是實時配置更新。當然,我們認為一分鐘時效是可以接受的。

在效能層面,我們內部使用的是32核、64G的伺服器,Goland 1.9.1,fasthttp,單機50w qps左右,整個資源佔用率較低,至少目前可以滿足我們的內部需求,並保有很大餘量。

通過自研web端,資料從玩家端上傳到伺服器,這時,我們要用日誌Agent接力上傳。日誌Agent需要保證日誌不重不丟,在執行過程中保持傳送狀態,這個狀態是事務更新的;降低配置成本,我們會做中央化管理,根據機器tag分配任務;支援多種業務同時傳輸,因為無論是系統日誌分析還是程式日誌檢索,入口都是Agent,因此我們要在一臺伺服器上支援多種業務同時傳輸,並可根據任務優先順序做出有效調整,最後是高效運維,具備完善的管控平臺。 

 

以上是我們自研的日誌Agent架構設計,基本原理與開源Flume等類似。首先,這裡會涉及一個Scanner的概念,Scanner的字面意思就是掃描,我首先需要弄清楚一臺遊戲伺服器上到底有多少檔案和目錄需要掃描上傳,我們會在配置中心定義這些東西,檔案掃描使用FileScanner,DB方面使用DBScanner,目前主要涉及MySQL和MongoDB。

Scanner掃描資料初始化時要載入offset記錄,增量掃描所監聽的檔案和目錄,如果獲取到更新訊息可使用batch讀的方式傳到Reader中,我們額外會有單獨的執行緒週期性發一個心跳,這是內部監控中用的。最後,所有資料會傳到 Queue中,這是一個資料緩衝區的大小,如果有網路IO或者磁碟IO的場景,你可能需要緩衝區來解耦生產者和消費者,不然吞吐量上不去。

之後,我們會把Queue封裝成一個優先佇列,高優先順序任務資料率先通過併發Sender讀取,Thrift RPC會將這些日誌傳送到kafka proxy中。為了保證資料可靠性,整個過程必須是同步的,如果傳送成功,就更新offset;如果傳送失敗,則進入等待重試佇列,如果重試了幾次均失敗,就報警給SRE的同學。

整個過程中需要配置的部分同樣在配置中心完成,配置中心同樣有版本號的概念,每隔一分鐘重新整理一次。主要的核心配置,比如資料來源配置、緩衝區大小、併發數等是為了調整傳送效率,資料路由會根據業務特性進行調整。

除了上述提到的掃描更新方式外,Scanner還有一種顯而易見的方式就是事件通知,可以通過系統方法啟動程式並監聽檔案,事件更新之後對外發出通知。當處於某些極端場景下時,這種方式的效能就會變得很差。假設我現在需要掃描的資料夾下有一萬個檔案,我們的做法是對檔案進行冷熱tag標記,如果這個檔案在一段時間內沒有被更新,我們就會把它標記為冷檔案,冷檔案的掃描週期比熱檔案長。當然,冷熱檔案列表一直處於交換更新狀態,通過這種方式可以達到更優的效能並避免實時監聽的效能損耗。

 

上圖為中央化任務釋出流程圖,SRE和業務方會基於機器tag定義任務,CMDB會管理整個tag列表,比如某臺機器要採集某路徑上的某個檔案,CMDB會對該類任務進行完整定義和管理,機器會在啟動或者輪詢時發起請求,我們將SRE與CMDB的請求打通,根據IP對映到具體tag列表,最終合併出機器任務列表返回日誌Agent。我們也會根據合併列表生成版本號與Agent進行比對,確定是否需要Reload。

在配置中,我們將後設資料稱為Meta,通過日誌Agent進行管理,這裡涉及兩個名詞需要解釋——Timestamp和offset,Timestamp並不是指日誌裡面的時間,因為日誌本身可能並沒有時間,Timestamp指Agent讀的時間,而offset是指Agent按照batch方式讀時,每行可能都有一個offset位置。如果你需要對日誌進行精準排序,Timestamp和offset組合索引可以還原日誌順序。當然,不同的應用場景可以不斷擴充套件meta。

傳送效率如何呢?在網易遊戲的場景下,主要有四大因素影響傳送效率:一是傳送併發數;二是資料緩衝區大小;三是batch讀取大小;四是冷檔案掃描週期。當Agent效能處於正常情況下時,batch讀取大小和冷檔案掃描週期不會過多影響傳送效率;當日志數量突然猛增,二者才會產生影響。雖然,我們可以提供多種組合配置,但我們內部並未對SRE和產品完全開放,目前提供的預設配置是35MB/S,高效能配置是70MB/S。這裡的前提是不對原始伺服器也就是使用者伺服器有過高資源佔用。

我之前一直在強調保證日誌不重不丟,所以日誌可靠性是我們非常關注的事情。對於日誌異常監控,我們主要做了三件事情:Heartbeat心跳;心跳錨點計算傳輸延遲;檔案傳輸延遲LAG。具體來說,如果Heartbeat停止並且持續一段時間沒有恢復,我們就認為Agent可能出現了問題,我們會立刻監督Agent的狀態。其次,心跳資訊不僅僅是一個心跳,還包括伺服器、主機名、負載以及觸發心跳的時間等資訊,我們在下游設定了統一實時Flink程式處理資訊,當Flink收到心跳觸發時間後,它會根據當前時間計算當前從遊戲伺服器到資料中心的實時延遲。如果延遲過大,我們會關注是否出現異常。

對於上文提到的日誌數突然猛增的情況,我們做的主要工作是通過後設資料記錄查詢並計算檔案傳輸延遲,同時也在嘗試使用自動化的方式解析每個日誌的時間。如果延遲過大,會觸發報警機制。 

 

上圖為資料傳送流程,資料通過Agent上報Kafka Proxy,我們內部會有多個Kafka叢集,我們希望在Proxy層隱藏上層細節,不希望Kafka叢集的訪問許可權或者埠開放給數萬臺遊戲伺服器,我們希望Kafka叢集繼續放在純內網環境中執行,與遊戲伺服器的外網連線隔離。 

經過近一年的努力,我們形成了統一的資料流,支撐了網易遊戲大概50+產品,有1萬多臺伺服器日誌上報;上線Docker平臺日誌採集;通用類日誌採集;支援Windows伺服器。

三、資料流業務實踐

以上是我們在資料採集、資料流轉、資料分發方面做的事情,我們的下游業務最主要還是與資料流緊密相關,也可以說是緊接著kafka內層做的事情。第一層就是實時日誌清洗與分發,這是我們技術團隊直接接管的,簡單來說,我們會管理下游日誌到達Kafka之後的去向和使用者等資訊。目前,我們的大部分任務還是通過Storm完成,最近部分切換成了Flink。

實時計算主要指業務方向的實時計算。業務方將實時計算邏輯打成包,放到託管平臺上執行。此外,我們基於Spark Streaming封裝了一套ETL框架,不需要寫程式碼,只需要進行一些配置就可以轉換讀取資料,包括開放自定義介面並將資料寫到不同的儲存中,比如Kafka、HDFS等。

最後是通用日誌檢索,我先簡單介紹一下程式日誌檢索的概念,狹隘來說,程式日誌檢索就是通過伺服器檢視日誌資訊。我以微服務場景為例講解一下整個概念,微服務的好處在於我們可以將伺服器拆分為不同元件,每個元件由不同的人開發,擁有獨立的技術棧、迭代週期和上線更新頻率。最大的問題在於請求呼叫鏈變得非常長,查詢使用者異常資訊的過程異常痛苦。我們最終的解決方案是在每個請求的入口注入trace ID或者在前端和proxy閘道器上做,所有請求都會有自己的ID,我們通過這個可以很容易得檢索一條請求鏈。

總結來看,大規模程式日誌檢索主要有三點要求:檢索效率高,低延遲和查詢時保證順序。目前的程式日誌檢索流程如下圖所示,我們會對資料流進行實時清洗切分,然後將結果放到ES之中,最後通過查詢Server實現查詢。 

四、想法與總結

以上是我今天分享的全部內容,通過整個過程,我自己對技術開發有如下三點感受:追求簡單、可靠、靈活的解決方案;解決方案需要針對具體的場景,沒有一種技術可以解決所有問題;架構設計和選型有很多的Trade offs。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2200166/,如需轉載,請註明出處,否則將追究法律責任。

相關文章