最近項目裏打算做一個緩存全服玩家的基礎信息的功能,由於數據量表面看上去有點大,需要對數據量進行在內存中大小進行評估,同時也要對GC進行評測,才能確定是否批准把該方案落地。
- 緩存方案:服務器啓動時把全服玩家基礎數據讀取出來進行緩存,每個玩家測試字段數量爲:6個int, 2個字符串。按這個數據模板測試,得出的大概內存佔用數量統計爲:
數據量 | 垃圾(單位:M) |
---|---|
314750 | 108.73 |
可以從上面圖看出,對於30萬的玩家來說,內存數據大概108M,即使把字段翻一翻,也就216M,對於服務器的開發換來的是不需要異步讀取離線玩家數據,基礎數據統一管理的結果,這個內存是極具性價比的。
3. 由於數據常駐內存,對於GC來說可能存在回收時的效率問題。對於上述的例子,純基礎數據約30萬的table數據量,外加60萬的string數據量,這都是可確定的數據量。接下來的測試數據會比這個數據量大得多,爲了不僅僅是針對這個數據,是需要對於GC回收有個清楚的認識。
4. 爲了測試回收效率,測試的方向是從數據量和GC回收的時候每一個階段時間做統計。GC主要分了5個階段,每個階段還有細分不同情況的統計,目前分的階段有:markroot, 掃描標記, 掃描標記原子階段, 清理字符串, 清理Table及其它GCObject階段, 停止階段。統計方式爲:每個階段的時間使用clock()時間累加統計,clock的精度也足夠了。測試數據方面,string和table測試數量從100萬,200萬, …1000萬,數據量從200萬起。對於此次測試,測試目標是數量與時間關係,採用了連續調用單步回收的方式測試,測試統計結果如下:
總數量 | tabel數據量 | string數據量 | 垃圾內存大小 | markroot時間(單位:ms) | 掃描標記(單位:ms) | 掃描標記原子階段(單位:ms) | 掃描字符串(單位:ms) | 掃描Table及其它GCObject(單位:ms) | 回收階段(單位:ms) |
---|---|---|---|---|---|---|---|---|---|
test count | testtablecount | teststringcount | garbage | gcmarkroottime | gcpropagatetime | gcatomictime | gcsweepstringtime | gcsweeptime | gcfinalizetime |
2000000 | 1000000 | 1000000 | 187.51M | 1 | 94 | 0 | 462 | 330 | 0 |
4000000 | 2000000 | 2000000 | 248.92M | 0 | 90 | 0 | 973 | 635 | 0 |
6000000 | 3000000 | 3000000 | 302.32M | 0 | 92 | 0 | 1318 | 940 | 0 |
8000000 | 4000000 | 4000000 | 355.73M | 0 | 101 | 0 | 1817 | 1253 | 0 |
10000000 | 5000000 | 5000000 | 425.14M | 0 | 91 | 0 | 2269 | 1569 | 0 |
12000000 | 6000000 | 6000000 | 478.54M | 0 | 87 | 0 | 2661 | 1865 | 0 |
14000000 | 7000000 | 7000000 | 531.95M | 0 | 92 | 0 | 2983 | 2172 | 0 |
16000000 | 8000000 | 8000000 | 585.35M | 0 | 84 | 0 | 3397 | 2489 | 0 |
18000000 | 9000000 | 9000000 | 670.76M | 0 | 99 | 0 | 4096 | 2828 | 0 |
20000000 | 10000000 | 10000000 | 724.16M | 0 | 93 | 0 | 4448 | 3104 | 0 |
6. 分析
1. mark rook階段:操作不多,時間可以忽略不計,多次測試爲0。
2. 掃描標記階段: 這個階段的耗時比較穩定,從200萬到2000萬,時間都處於毫秒級
3. 掃描標記原子階段: 由於我們測試table沒有弱表,並且是連續阻塞調用,所以掃描標記原子階段是爲0的。即使使用默認方式調用,可以影響到原子階段的情況就是:在回收過程中被掃描過的table會被修改了,同時又再被掃描到,就需要放到指定的鏈表裏(grayagain)裏,等到原子階段再處理。對於這種情況,短時間內被修改的和操作表的頻率會對此情況造成影響,可預見的數量並不會多。這個對於項目來說,可以說不具什麼影響。
4. 掃描字符串: 時間與數量大概是成線性增加,每增加100萬數據量,大約耗時增加450ms。
5. 掃描Table及其它GCObject:時間與數量大概是成線性增加,每增加100萬數據量,大約耗時增加300ms。對比字符串時間計算,統計顯示清理字符串稍微會久一點。
6. 回收階段: 操作不多,時間可以忽略不計,測試耗時爲0。
7. 總耗時:對於總耗時來算,從800ms到7500ms,完全回收的時間並不算是預料中的多。對於項目實踐來說,採用定時回收策略的話,可以把這些時間分攤到每一步定時回收裏,大概回收過程能在2分鐘內(依賴參數設置,此處使用默認參數)可以完成。對於時間分佈,大部分時間耗在清理階段,而對於掃描階段的耗時相對還是要穩定和少。
測試統計代碼稍後整理存放在github上