基于NodeJS的高性能分布式游戲日志系統(tǒng)

大綱:

  • 前言
  • 日志系統(tǒng)架構(gòu)是怎樣的
  • 游戲分析有什么內(nèi)容
  • 為什么要自己架一個系統(tǒng)
  • FEN架構(gòu)
    • 架構(gòu)圖
    • Fluentd
    • ElasticSearch
    • NodeJS
    • pusher
    • logger
    • analyser
    • 用戶界面
  • 總結(jié)

前言

最近我司需要做一個統(tǒng)一的游戲日志系統(tǒng)脖祈,要求有一定的通用性,能應(yīng)對公司所有的游戲業(yè)務(wù)。接下來分享一下這次日志系統(tǒng)的項目經(jīng)驗蝎毡。

日志系統(tǒng)架構(gòu)是怎樣的

目前流行的日志系統(tǒng)為ELK笛钝,由Beats壶熏、Logstash容客、Elasticsearch派昧、Kibana等組件共同實現(xiàn)特笋,但萬變不離其宗剃浇,一個基本的日志系統(tǒng)架構(gòu)類似如下:

基本架構(gòu)

游戲分析有什么內(nèi)容

游戲分析,與其它服務(wù)系統(tǒng)不同的是猎物,游戲內(nèi)的系統(tǒng)可能是天馬行空的虎囚,數(shù)據(jù)類型是多樣的,甚至頻繁變化的蔫磨。我們要在變化中總結(jié)到不變的內(nèi)容淘讥,例如系統(tǒng)經(jīng)濟(jì)產(chǎn)出,玩家物品消耗堤如,商店購買等進(jìn)行分析蒲列。所以這次的游戲日志系統(tǒng)要滿足以下需求:

  • 記錄游戲日志窒朋,并隨時檢索日志;
  • 分析玩家行為:玩家留存相關(guān)蝗岖,玩家物品消耗侥猩,商店消耗等有一定復(fù)雜度的分析;
  • 能建立一個統(tǒng)一的日志系統(tǒng):一次性滿足未來游戲運營多樣性抵赢。

為什么要自己架一個系統(tǒng)

雖然ELK在安裝配置方面不算困難欺劳,插件眾多,例如Filebeat铅鲤,讀log文件划提,過濾格式,轉(zhuǎn)發(fā)邢享,但誰來生產(chǎn)這些log文件鹏往,沒有提及。實際上骇塘,業(yè)務(wù)具有多樣性伊履,只要有日志文件的地方,它就可以用绪爸。例如多數(shù)會使用Nginx進(jìn)行日志收集湾碎。我們也需要考慮到日志生產(chǎn)者的問題,責(zé)權(quán)分離奠货,需要單獨一臺機(jī)子進(jìn)行日志采集介褥。

游戲是一種技術(shù)與藝術(shù)結(jié)合的產(chǎn)品,數(shù)據(jù)龐雜递惋,形態(tài)各異柔滔,光日志埋點也花不少功夫復(fù)雜,但不能因此放棄治療萍虽。好的游戲日志睛廊,還可以幫我們還原玩家玩家畫像。游戲更新周期短杉编,數(shù)據(jù)變化大超全,需要提供更實時參照報表,為非技術(shù)人員更好友的查詢界面邓馒,才能更好的服務(wù)于游戲數(shù)據(jù)分析嘶朱。ELK 在這方面,基本解決了采集和儲存的問題光酣,但實現(xiàn)分析方面還不能滿足我們的需求疏遏。

經(jīng)過一翻思索,我們可以用現(xiàn)有工具,粘合多個套件财异,所以倘零,我們有了以下思路:

  • 日志采集器:
    利用Fluented作為日志文件采集器,生產(chǎn)者通過內(nèi)網(wǎng)HTTP發(fā)送到采集器上戳寸,那每個生產(chǎn)者同一內(nèi)網(wǎng)只要部署一個采集器即可呈驶,如果量特別大,可以多個庆揩,游戲的功能埋點可以統(tǒng)一俐东;
  • 轉(zhuǎn)發(fā)器:
    利用NodeJS進(jìn)行 HTTP 轉(zhuǎn)發(fā)即可,前提是能按順序和分段讀取日志文件订晌,結(jié)合Fluented間接實現(xiàn);
  • 接收器與實時分析:
    接收器可以用Koa實現(xiàn)蚌吸,Redis進(jìn)行緩存锈拨;同時用NodeJS另外一個進(jìn)程分析和日志入庫,分析行為羹唠,玩家畫像奕枢,得出報表,這些非日志源的數(shù)據(jù)佩微,可以放到MongoDB上缝彬,因為這些數(shù)據(jù)是修改性增長緩慢數(shù)據(jù),占用空間不大哺眯;
  • 儲存?zhèn)}庫:
    ElasticSearch是個很好的選擇谷浅,能集群,可熱增減節(jié)點奶卓,擴(kuò)容一疯,還可以全文檢索,分詞夺姑;
  • 用戶界面:
    Kibana針對 ElasticSearch提供良好的分析墩邀,結(jié)合原有的管理后臺系統(tǒng),我們自己實現(xiàn)了一套用戶界面盏浙。

FEN架構(gòu)

這個框架主要使用到了Fluentd眉睹,ElasticSearch,以及NodeJS废膘,我就稱它為 FEN 架構(gòu)吧竹海,如下圖。

架構(gòu)圖

FEN架構(gòu)

上圖看出殖卑,這樣的日志架構(gòu)和第一個圖基本沒什么不同站削,只是多了后面的分析與分批入庫處理,并且大量使用了NodeJS孵稽。

注:在這里不會介紹各組件的詳細(xì)的安裝配置方法许起,網(wǎng)上有太多了十偶,怎樣使用好每一個組件才是關(guān)鍵。

先介紹我們用到的工具:

Fluentd

Fluentd是一個完全開源免費的log信息收集軟件园细,支持超過125個系統(tǒng)的log信息收集惦积。Fluentd在收集源日志方面非常方便而且高性能,通過HTTP GET就可以猛频,這類似于Nginx的日志記錄行為狮崩。它的優(yōu)點是,日志文件可以高度定制化鹿寻,例如我們這里每5秒生成一個文件睦柴,這樣每分鐘有12個文件,每個文件體積非常小毡熏。為什么要這樣做坦敌?下面會介紹。Fluentd還有非常多的插件痢法,例如直接存入MongoDB狱窘,亞馬遜云等,要是熟悉Ruby财搁,也可以自己寫插件蘸炸。

ElasticSearch

有人使用MongoDB進(jìn)行日志收集,是非常不明智的尖奔,只有幾千萬條還可以搭儒,如果半個月生產(chǎn)10億條日志呢?日志文件需要保存一個月甚至更長越锈,那么集群和硬盤維護(hù)就非常重要仗嗦。使用便利性也很重要,例如分詞檢索甘凭,在客服回溯玩家日志稀拐,分析游戲 BUG 的時候非常有用。下文的 ES 也是該組件的簡稱丹弱。

NodeJS

NodeJS不適合做 CPU 密集型任務(wù)德撬,但在網(wǎng)絡(luò)應(yīng)用方面還不錯,并且是我們正好熟悉的躲胳。日志系統(tǒng)并不對實時性要求并不高蜓洪,延時半小時以內(nèi)都是允許的,事實上坯苹,正常情況延時也就10來秒隆檀。下面的讀與轉(zhuǎn)發(fā)日志的Pusher,收集日志的logger,分析日志并數(shù)據(jù)落袋為安的的analyser恐仑,都是由NodeJS實現(xiàn)的泉坐。

下面繼續(xù)介紹用 NodeJS實現(xiàn)的每一個部分:

轉(zhuǎn)發(fā)器Pusher

上面說到,為什么Fluentd使用分割成多個小文件的方式裳仆,因為NodeJS在大文件處理方面并不友好腕让,并且要考慮到通過網(wǎng)絡(luò)發(fā)送到另一臺機(jī),轉(zhuǎn)發(fā)速度比讀慢太多了歧斟,所以必須實現(xiàn)續(xù)傳與斷點記錄功能纯丸。想想,如果讀幾百 M 的文件静袖,出現(xiàn)中斷后觉鼻,需要永久記錄上次位置,下次再從此處讀起队橙,這就增加了程序復(fù)雜度滑凉。NodeJS雖然有readline模塊,但測過發(fā)現(xiàn)并不如文件流那樣可控喘帚,訪模塊用于交互界面尚可。相反咒钟,如果日志分割成多個小文件吹由,則讀的速度非常高效,并且每5秒一個文件朱嘴,哪怕有上萬條記錄倾鲫,文件也大不到哪里去,內(nèi)存也不會占用太多萍嬉,在斷點續(xù)傳與出錯重試方面都能自如應(yīng)對乌昔。如果游戲日志增多,可以增加節(jié)點來緩解文件過大的壓力壤追。

為什么不直接讓日志生產(chǎn)者直接發(fā)到Koa上磕道?因為效率與帶寬。NodeJS的適合做網(wǎng)站行冰,但比專業(yè)的HTTP服務(wù)器要弱太多溺蕉,4核心主機(jī)面對3000QPS就吃力,更多的關(guān)于NodeJS的性能問題悼做,可以參考網(wǎng)絡(luò)文章疯特。在高并發(fā)量下,帶寬是個很大的問題肛走,尤其是需要做統(tǒng)一服務(wù)漓雅,面對的情況是日志機(jī)器與游戲并不在同一內(nèi)網(wǎng)中。在10萬日活下,帶寬超過了50M邻吞,非常嚇人组题,帶寬可是很貴的,過高的帶寬費用在這里性價比太低了吃衅。

Pusher的注意點:
  • 批量轉(zhuǎn)發(fā):不要一條條日志發(fā)往踢,采用批量發(fā)送。根據(jù)單條日志文件大小徘层,如果是 JSON 數(shù)據(jù)峻呕,有10多個字段,那么每次請求發(fā)送50~100條發(fā)送都是沒問題的趣效,也就幾十 KB瘦癌;
  • 串行序順發(fā)送:從時間小的文件,從文件關(guān)開始發(fā)跷敬,等待上一次發(fā)送請求完成再執(zhí)行下一次讯私;
  • 發(fā)送失敗保存重試:如果某一次請求失敗,則保存到另外一個文件目錄西傀,以時間戳作為文件名斤寇,下次重試,盡可能保證數(shù)據(jù)完整性拥褂;
  • 每100毫秒讀一次文件列表娘锁,檢查有沒有新的日志文件。雖然是每5秒產(chǎn)生一次日志文件饺鹃,但有可能出現(xiàn)效率下降導(dǎo)致發(fā)送速度跟不上而產(chǎn)生文件積壓莫秆,即使是空讀也是允許的,這不基本不占什么CPU悔详。第100毫秒的間隔不要使用setInterval镊屎,應(yīng)該在上一次文件發(fā)送完畢再setTimeout來執(zhí)行;
  • 發(fā)送速度提供可變性茄螃,如果下面的logger效率低下缝驳,上面的100毫秒可以適當(dāng)放緩一些。

日志收集器logger

這里我們使用Koa作為日志采集器责蝠。使用Koa党巾,無論在性能還是開發(fā)效率上,都比expressJS高效霜医。我們還用到了Redis作為緩存齿拂,而不是直接在這里做分析任務(wù),是為了盡量提高與Pusher的對接效率肴敛,畢竟日志的生產(chǎn)速度是很快的署海,但網(wǎng)絡(luò)傳送是相對低效的吗购。

logger的注意點:
  • 使用緩存緩存數(shù)據(jù),如Redis砸狞;
  • 關(guān)注內(nèi)存:logger與pusher是兩臺機(jī)子捻勉,當(dāng)logger的緩存提升太快,也就是后面的分析與入庫速度跟不上了刀森,需要返回消息告知pusher放慢發(fā)送速度踱启;
  • 安全驗證:簡單的方式是pusher發(fā)送時可以進(jìn)行md5驗證,logger驗簽研底;
  • 如果使用Redis埠偿,在Redis 4.0以下,使用list記錄每條日志 ID榜晦,日志使用hash節(jié)省內(nèi)存冠蒋。在Redis 3.x不要使用Scan,它有BUG乾胶,就是Scan出的數(shù)量是無法確定的抖剿,就算明確指定了條數(shù),但有可能出現(xiàn)一次讀數(shù)萬條识窿,也有可能一次讀幾十條斩郎,這對后面的分析器非常不利;
  • Redis記得開啟 RDB喻频,以及maxmemory設(shè)置孽拷,前者可以在出問題時還原狀態(tài),后者可以防止出現(xiàn)災(zāi)難時資源暴掉半抱,搞崩其它服務(wù);
  • 無論是不是使用Redis膜宋,應(yīng)該使用支持管道窿侈,或者批量的方法,如redisio秋茫,根據(jù)機(jī)器效率史简,如每次滿500條就入緩存,不滿就100毫秒入一次肛著,減少緩存操作次數(shù)可以提高效率圆兵;
  • logger可以用pm2的集群模式,提高效率枢贿。

注:pm2 3.2.2的集群可能出現(xiàn)集群內(nèi)端口沖突的吊詭問題殉农,建議用3.0.3

分析器analyser:

分析器讀取Redis的內(nèi)容,這里就是單進(jìn)程的隊列操作局荚。到這一步超凳,日志怎么分析愈污,就可以很自由了。

分析器analyser的注意點:

  • 單線程可以確保每個玩家的日志時間序列轮傍;
  • Redis的讀取使用管道暂雹,一次讀取數(shù)千條進(jìn)行分析。參考值:目前每次讀3000條進(jìn)行處理创夜,在4核心中低配置云主機(jī)下單線程占用僅為35%左右杭跪;
  • 日志存ES:源日志文件可以進(jìn)行進(jìn)一步分析或者格式優(yōu)化,處理后的放ES驰吓,ES 就是為集群而生涧尿,通過加入子節(jié)點可以熱擴(kuò)容,硬盤便宜棚瘟,所以先做3個節(jié)點的集群吧现斋;
  • 配置好ES的索引(mapping),仔細(xì)考慮各字段類型偎蘸,凡是要與搜索條件有關(guān)的庄蹋,例如要查元寶大于多少的,那么元寶字段必須有索引迷雪,否則將無法根據(jù)該字段查找日志限书。還有,想要分詞的必須使用text類型章咧。日志一般不會進(jìn)行匯總倦西,因為我們已經(jīng)統(tǒng)計大部分內(nèi)容了,所以可以適當(dāng)減少doc_value赁严,壓縮率等扰柠,否則一千萬條日志半小時內(nèi)就吃掉1G硬盤。這需要你好好研究 ES 的索引配置了疼约,后面還得研究 ES 的搜索卤档,因為它比MongoDB的復(fù)雜得多,但這很值得程剥;
  • ES和MongoDB的入庫劝枣,使用批量處理,根據(jù)機(jī)器性能和系統(tǒng)資源找到合適的批處理數(shù)量织鲸。參考值舔腾,4核下 ES 批量入庫1000條效率300ms 左右;
  • ES 配置好內(nèi)存搂擦,默認(rèn)是1G JVM內(nèi)存稳诚,經(jīng)常不夠用就會崩潰。在配置文件同目錄下有個jvm option文件瀑踢,可以加大JVM采桃,建議至少分配一半以上內(nèi)存懒熙;
  • ES 的寫入效率:不要以為 ES 的輸入速度很快,默認(rèn)它是寫一條更新一條索引普办,也就是必須等把數(shù)據(jù)更新到索引才會返回工扎,無論使用批量處理還是單個,日志量大的時候衔蹲,批處理僅100條也會超過500ms肢娘。設(shè)置durability為async,不要馬上更新到索引舆驶;
  • ES使用別名索引橱健,好處是當(dāng)你需要重建索引時,可以通過另外重新指向到新的索引沙廉,因為 ES 不能修改索引拘荡,只能重建;
  • 在分析的時候撬陵,先還原玩家畫像珊皿,對其它數(shù)據(jù)報表,組織好你的數(shù)據(jù)結(jié)構(gòu)巨税,數(shù)據(jù)量小蟋定、簡單的可以同時放內(nèi)存中進(jìn)行計數(shù),并定期條件清理草添,大的如玩家畫像放redis中驶兜,定期更新入庫。這些數(shù)據(jù)的緩存方式可以使用完整版本远寸,簡化問題抄淑,減少出現(xiàn)臟數(shù)據(jù)的可能;同時分析也要注意效率的問題驰后,例如有Mongodb數(shù)據(jù)的讀寫蝇狼,要務(wù)必配置到index,否則將引起災(zāi)難性效率下降倡怎。

用戶界面

因為我們本身有后臺管理系統(tǒng),所以我們很方便的把用戶畫像與其它分析點接了入去贱枣,在查詢玩家行為時监署,我們搜索ES,在查詢分析報表時纽哥,我們查詢MongoDB中的數(shù)據(jù)钠乏。當(dāng)然我們也使用了Kibana來滿足可能的需求。

總結(jié)

目前該日志系統(tǒng)運行1個半月春塌,由純MongoDB到結(jié)合 ES晓避,走了不少彎路簇捍,還好現(xiàn)在終于穩(wěn)定下來。目前在性能方面俏拱,logger 與 analyser都在同一臺機(jī)暑塑,平均 CPU 為23%左右,高峰47%左右锅必,說明還有更大的機(jī)器壓榨空間事格。

內(nèi)存方面,在高峰期5G 以內(nèi)搞隐,總體非常平穩(wěn)沒多大波動驹愚,其中redis內(nèi)存使用為800MB以內(nèi),但機(jī)器是16G劣纲,還有很大余量保障逢捺。

NodeJS 的腳本中,logger的CPU占用更小癞季,3條進(jìn)程劫瞳,每條才3%,每條內(nèi)存占用不到100MB余佛。analyser 的 CPU 與內(nèi)存占用多一點柠新,這一點可以通過腳本內(nèi)的參數(shù)調(diào)整,例如內(nèi)存計數(shù)的內(nèi)容清理得更快辉巡,使用pm2的話設(shè)置max_memory_restart : '4G' 都可以提高穩(wěn)定性恨憎。

以上是我在游戲日志系統(tǒng)中的經(jīng)驗總結(jié)。

參考文獻(xiàn):

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郊楣,一起剝皮案震驚了整個濱河市憔恳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌净蚤,老刑警劉巖钥组,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異今瀑,居然都是意外死亡程梦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門橘荠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屿附,“玉大人,你說我怎么就攤上這事哥童⊥Ψ荩” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵贮懈,是天一觀的道長匀泊。 經(jīng)常有香客問我优训,道長,這世上最難降的妖魔是什么各聘? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任揣非,我火速辦了婚禮,結(jié)果婚禮上伦吠,老公的妹妹穿的比我還像新娘妆兑。我一直安慰自己,他們只是感情好毛仪,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布搁嗓。 她就那樣靜靜地躺著,像睡著了一般箱靴。 火紅的嫁衣襯著肌膚如雪腺逛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天衡怀,我揣著相機(jī)與錄音棍矛,去河邊找鬼。 笑死抛杨,一個胖子當(dāng)著我的面吹牛够委,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怖现,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茁帽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屈嗤?” 一聲冷哼從身側(cè)響起潘拨,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎饶号,沒想到半個月后铁追,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡茫船,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年琅束,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片算谈。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡涩禀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出濒生,到底是詐尸還是另有隱情,我是刑警寧澤幔欧,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布罪治,位于F島的核電站丽声,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏觉义。R本人自食惡果不足惜雁社,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晒骇。 院中可真熱鬧霉撵,春花似錦、人聲如沸洪囤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘤缩。三九已至喇完,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剥啤,已是汗流浹背锦溪。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留府怯,地道東北人刻诊。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像牺丙,于是被迫代替她去往敵國和親则涯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容