[轉至雲風的部落格]談談陌陌爭霸在資料庫方面踩過的坑( Redis 篇)

來源:互聯網
上載者:User

標籤:

« 談談陌陌爭霸在資料庫方面踩過的坑(芒果篇) | 返回首頁 | linode 廣告時間 »

談談陌陌爭霸在資料庫方面踩過的坑( Redis 篇)

註:陌陌爭霸的資料庫部分我沒有參與具體設計,只是參與了一些討論和提出一些意見。在出現問題的時候,也都是由肥龍、曉靖、Aply 同學判斷研究解決的。所以我對 Redis 的判斷大多也從他們的討論中聽來,加上自己的一些猜測,並沒有去仔細閱讀 Redis 文檔和閱讀 Redis 代碼。雖然我們最終都解決了問題,但本文中說描述的技術細節還是很有可能與事實相悖,請閱讀的同學自行甄別。

在陌陌爭霸之前,我們並沒有大規模使用過 Redis 。只是直覺上感覺 Redis 很適合我們的架構:我們這個遊戲不依賴資料庫幫我們處理任何資料,總的資料量雖然較大,但增長速度有限。由於單台服務機處理能力有限,而遊戲又不能分服,玩家在任何時間地點登陸,都只會看到一個世界。所以我們需要有一個資料中心獨立於遊戲系統。而這個資料中心只負責資料中轉和資料落地就可以了。Redis 看起來就是最佳選擇,遊戲系統對它只有按玩家 ID 索引出玩家的資料這一個需求。

我們將資料中心分為 32 個庫,按玩家 ID 分開。不同的玩家之間資料是完全獨立的。在設計時,我堅決反對了從一個單點訪問資料中心的做法,堅持每個遊戲伺服器節點都要多每個資料倉儲直接連接。因為在這裡製造一個單點毫無必要。

根據我們事前對遊戲資料量的估算,前期我們只需要把 32 個資料倉儲部署到 4 台物理機上即可,每台機器上啟動 8 個 Redis 進程。一開始我們使用 64G 記憶體的機器,後來增加到了 96G 記憶體。實測每個 Redis 服務會佔到 4~5 G 記憶體,看起來是綽綽有餘的。

由於我們僅僅是從文檔上瞭解的 Redis 資料落地機制,不清楚會踏上什麼坑,為了保險起見,還配備了 4 台物理機做為從機,對主機進行資料同步備份。

Redis 支援兩種 BGSAVE 的策略,一種是快照方式,在發起落地指令時,fork 出一個進程把整個記憶體 dump 到硬碟上;另一種喚作 AOF 方式,把所有對資料庫的寫操作記錄下來。我們的遊戲不適合用 AOF 方式,因為我們的寫入操作實在的太頻繁了,且資料量巨大。

第一次事故出在 2 月 3 日,新年假期還沒有過去。由於整個假期都相安無事,營運也相對懈怠。

中午的時候,有一台資料服務主機無法被遊戲伺服器訪問到,影響了部分使用者登陸。線上嘗試修複串連無果,只好開始了長達 2 個小時的停機維護。

在維護期間,初步確定了問題。是由於上午一台從機的記憶體耗盡,導致了從機的資料庫服務重啟。在從機重新對主機串連,8 個 Redis 同時發送 SYNC 的衝擊下,把主機擊毀了。

這裡存在兩個問題,我們需要分別討論:

問題一:從機的硬體設定和主機是相同的,為什麼從機會先出現記憶體不足。

問題二:為何重新進行 SYNC 操作會導致主機過載。

問題一當時我們沒有深究,因為我們沒有估算準確過年期間使用者增長的速度,而正確部署資料庫。資料庫的記憶體需求增加到了一個臨界點,所以感覺記憶體不足的意外發生在主機還是從機都是很有可能的。從機先掛掉或許只是碰巧而已(現在反思恐怕不是這樣, 冷備指令碼很可能是罪魁禍首)。早期我們是定時輪流 BGSAVE 的,當資料量增長時,應該適當調大 BGSAVE 間隔,避免同一台物理機上的 redis 服務同時做 BGSAVE ,而導致 fork 多個進程需要消耗太多記憶體。由於過年期間都回家過年去了,這件事情也被忽略了。

問題二是因為我們對主從同步的機制瞭解不足:

仔細想想,如果你來實現同步會怎麼做?由於達到同步狀態需要一定的時間。同步最好不要幹涉正常服務,那麼保證同步的一致性用鎖肯定是不好的。所以 Redis 在同步時也觸發了 fork 來保證從機連上來發出 SYNC 後,能夠順利到達一個正確的同步點。當我們的從機重啟後,8 個 slave redis 同時開啟同步,等於瞬間在主機上 fork 出 8 個 redis 進程,這使得主機 redis 進程進入交換分區的機率大大提高了。

在這次事故後,我們取消了 slave 機。因為這使系統部署更複雜了,增加了許多不穩定因素,且未必提高了資料安全性。同時,我們改進了 bgsave 的機制,不再用定時器觸發,而是由一個指令碼去保證同一台物理機上的多個 redis 的 bgsave 可以輪流進行。另外,以前在從機上做冷備的機制也移到了主機上。好在我們可以用指令碼控製冷備的時間,以及錯開 BGSAVE 的 IO 高峰期。

第二次事故最出現在最近( 2 月 27 日)。

我們已經多次調整了 Redis 資料庫的部署,保證資料服務器有足夠的記憶體。但還是出了次事故。事故最終的發生還是因為記憶體不足而導致某個 Redis 進程使用了交換分區而處理能力大大下降。在大量資料擁入的情況下,發生了雪崩效應:曉靖在原來控制 BGSAVE 的指令碼中加了行保底規則,如果 30 分鐘沒有收到 BGSAVE 指令,就強制執行一次保障資料最終可以落地(對這條規則我個人是有異議的)。結果資料服務器在對外部失去響應之後的半小時,多個 redis 服務同時進入 BGSAVE 狀態,吃光了記憶體。

花了一天時間追查事故的元兇。我們發現是冷備機制惹的禍。我們會定期把 redis 資料庫檔案複製一份打包備份。而作業系統在拷貝檔案時,似乎利用了大量的記憶體做檔案 cache 而沒有及時釋放。這導致在一次 BGSAVE 發生的時候,系統記憶體使用量量大大超過了我們原先預期的上限。

這次我們調整了作業系統的核心參數,關掉了 cache ,暫時解決了問題。

經過這次事故之後,我反思了資料落地策略。我覺得定期做 BGSAVE 似乎並不是好的方案。至少它是浪費的。因為每次 BGSAVE 都會把所有的資料存檔,而實際上,記憶體資料庫中大量的資料是沒有變更過的。一目前 10 到 20 分鐘的儲存周期,資料變更的只有這個時間段內上線的玩家以及他們攻擊過的玩家(每 20 分鐘大約發生 1 到 2 次攻擊),這個數字遠遠少於全部玩家數量。

我希望可以只備份變更的資料,但又不希望用內建的 AOF 機制,因為 AOF 會不斷追加同一份資料,導致硬碟空間太快增長。

我們也不希望給遊戲服務和資料庫服務之間增加一個中介層,這白白犧牲了讀效能,而讀效能是整個系統中至關重要的。僅僅對寫指令做轉寄也是不可靠的。因為失去和讀指令的時序,有可能使資料版本錯亂。

如果在遊戲伺服器要寫資料時同時向 Redis 和另一個資料落地服務同時各發一份資料怎樣?首先,我們需要增加版本機制,保證能識別出不同位置收到的寫操作的先後(我記得在狂刃中,就發生過資料版本錯亂的 Bug );其次,這會使遊戲伺服器和資料服務器間的寫頻寬加倍。

最後我想了一個簡單的方法:在資料服務器的物理機上啟動一個監護服務。當遊戲伺服器向資料服務推送資料並確認成功後,再把這組資料的 ID 同時發送給這個監護服務。它再從 Redis 中把資料讀回來,並儲存在本地。

因為這個監護服務和 Redis 1 比 1 配置在同一台機器上,而硬碟寫速度是大於網路頻寬的,它一定不會過載。至於 Redis ,就成了一個純粹的記憶體資料庫,不再運行 BGSAVE 。

這個監護進程同時也做資料落地。對於資料落地,我選擇的是 unqlite ,幾行代碼就可以做好它的 Lua 封裝。它的資料庫檔案只有一個,更方便做冷備。當然 levelDB 也是個不錯的選擇,如果它是用 C 而不是 C++ 實現的話,我會考慮後者的。

和遊戲伺服器的對接,我在資料庫機器上啟動了一個獨立的 skynet 進程,監聽同步 ID 的請求。因為它只需要處理很簡單幾個 Redis 操作,我特地手寫了 Redis 指令。最終這個服務 只有一個 lua 指令碼 ,其實它是由三個 skynet 服務構成的,一個監聽外部連接埠,一個處理串連上的 Redis 同步指令,一個單點寫入資料到 unqlite 。為了使得資料恢複高效,我特地在儲存玩家資料的時候,把恢複用的 Redis 指令拼好。這樣一旦需要恢複,只用從 unqlite 中讀出玩家資料,直接發送給 Redis 即可。

有了這個東西,就一併把 Redis 中的冷熱資料解決了。長期不登陸的玩家,我們可以定期從 Redis 中清掉,萬一這個玩家登陸回來,只需要讓它幫忙恢複。

曉靖不喜歡我依賴 skynet 的實現。他一開始想用 python 實現一個同樣的東西,後來他又對 Go 語言產生了興趣,想借這個需求玩一下 Go 語言。所以到今天,我們還沒有把這套新機制部署到生產環境。

[轉至雲風的部落格]談談陌陌爭霸在資料庫方面踩過的坑( Redis 篇)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.