成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

談談陌陌爭霸在數(shù)據(jù)庫方面踩過的坑(排行榜篇)

移動開發(fā) Android
陌陌爭霸中用于排名的分數(shù)區(qū)間不大,也就是 0 分到 5000 分。而參與排名的人數(shù)眾多,數(shù)以百萬計。對百萬用戶做插入排序,每個插入即使是 O(N) 的也不可接受。可事實是大量玩家的分數(shù)相同,都是并列排名的。所以我們只需要做 5000 個桶,每個桶里僅記錄這個分數(shù)有多少個人就可以了。

為什么大部分網(wǎng)絡服務都需要一個數(shù)據(jù)庫在后臺支撐整個系統(tǒng)?

這通常是因為大部分系統(tǒng)的一個運行周期都很短,對于傳統(tǒng)的網(wǎng)站服務來說,從收到一個 HTTP 請求開始,到終端用戶收到這個請求的結果為止,就是一個運行周期。

而其間可能處理的數(shù)據(jù)集是很大的,通常沒有時間(甚至沒有空間)把所有數(shù)據(jù)都加載到內 存,處理其中涉及的一小部分,然后保存在磁盤上再退出。

當數(shù)據(jù)量巨大時,任何對數(shù)據(jù)的操作的算法和數(shù)據(jù)結構都需要精心設計,這不是隨便一個程序員就可以輕松完成的任務。尤其是數(shù)據(jù)量大到超過內存容量時, 很多算法和數(shù)據(jù)結構對大部分非此領域的程序員來說都是陌生的。本著專業(yè)的事情交給專業(yè)的人來做的原則,一般系統(tǒng)都會把這部分工作交給獨立的數(shù)據(jù)庫來完成。

對數(shù)據(jù)的操作只有抽象的足夠簡單,系統(tǒng)才能健壯,這便有了 SQL 語言做一層抽象,讓數(shù)據(jù)管理的工作可以獨立出來。甚至于你想犧牲一部分的特性來提高性能,還可以選用近年來流行的各種 NOSQL 數(shù)據(jù)庫。

可在 MMO 游戲服務器領域,事情發(fā)生了一點點變化。

數(shù)據(jù)和業(yè)務邏輯是密切相關的,改變非常頻繁。MMO 服務器需要持續(xù)快速的響應用戶的請求。我們幾乎不可能把一切數(shù)據(jù)都放在獨立的數(shù)據(jù)庫中,比如玩家在虛擬世界中的位置,以及他所影響的其他玩家的列表;玩家 戰(zhàn)斗時的各種屬性變化,還有和玩家互動的那些 NPC 的狀態(tài)改變……

最大的矛盾是:MMO 游戲中數(shù)據(jù)集的改變不再是簡單的 SQL 可以表達的東西,不可能交給數(shù)據(jù)庫服務期內部完成。無論什么類型的數(shù)據(jù)庫,都不是為這種應用設計的。如果你硬要套用其它領域的應用模式的話,游戲服務器只 能頻繁的把各種數(shù)據(jù)從數(shù)據(jù)庫中讀出來,按游戲邏輯做出改變,再寫回去。數(shù)據(jù)庫變成了一個很低效的數(shù)據(jù)中轉中心,無論你是否使用內存數(shù)據(jù)庫,都改變不了這個 低效的本質。

我聽過無數(shù)從別的領域轉行到游戲領域做開發(fā)的程序員設計出來的糟糕系統(tǒng)。他們最終僅僅把數(shù)據(jù)庫當成一個可靠的數(shù)據(jù)儲存點和中轉點,認為把所謂重要的 數(shù)據(jù)寫進數(shù)據(jù)庫就萬事大吉,然后再別扭的從另一個位置把數(shù)據(jù)從數(shù)據(jù)庫讀出來使用。系統(tǒng)中充滿了對數(shù)據(jù)庫的奇怪異步回調用來改善系統(tǒng)的反應速度,而系統(tǒng)卻始 終步履闌珊。能做對已經(jīng)是極限了,更何況游戲系統(tǒng)不僅僅是輸入輸出正確就是正確,如果超過了應用的響應時間,一切都是不正確的。

為了讓系統(tǒng)健壯,構架師在構架系統(tǒng)時,一定會把系統(tǒng)隔離成不同的模塊,并盡量簡化模塊間的溝通規(guī)則。這樣你可以單獨校驗每個模塊的質量,必要的時候可以更換。幾乎沒有人會因為效率或開發(fā)方便等原因而把應用代碼寫到 OS 內核中去跑就是這個道理。

每個模塊只對輸入它的數(shù)據(jù)負責,保證輸出的正確。通常測試也只對這個正確性負責。同學們最容易忽略的一點是,每個模塊都對它輸入數(shù)據(jù)的處理速度有一個上限,也就是它的吞吐量。

一旦輸入速度大于處理速度,模塊實現(xiàn)的再正確也是白搭。因為永遠都不會有輸出了。

對于大部分模塊,只要內存管夠,這都不是問題。實際運作的系統(tǒng)中很少有持續(xù)大數(shù)據(jù)量的輸入的,從一個較長的時間看,總的數(shù)據(jù)輸入是小于處理能力的,暫時沒能處理的數(shù)據(jù)堆積在內存就行了。

凡事都有例外。一個健壯的系統(tǒng)都需要對例外做處理。一個工作在 server 模式的數(shù)據(jù)庫是這樣解決這個例外的:它會支持查詢連接的并發(fā),并發(fā)的查詢相互間對計算資源的占用是公平的,相互不影響(至少是設計上的理想)。而操作系統(tǒng) 或數(shù)據(jù)庫本身會限制并發(fā)的連接數(shù),一旦達到最高連接數(shù),系統(tǒng)會拒絕服務;這樣就把超過處理能力的輸入擋在了模塊外面。按這種設計,就不會有輸入(只要能抵 達)永遠沒有回應了。

可惜,這樣做的代價是,你必須在模塊間加入請求失敗的處理。一個設計不謹慎的系統(tǒng)最容易在錯誤處理上栽跟頭。他們總是期望任何一個模塊都能正確處理上級的請求。

btw, 為什么 12306 的訂票系統(tǒng)在高負載的情況下完全不可用?就是這點沒處理好。我指的是,一個實現(xiàn)正確的系統(tǒng),一定不會連網(wǎng)頁的刷不出來,不給用戶正確的提示,哪怕只是錯誤 提示;也不應該在高負載下,有效處理能力急劇下降。我指的是,一旦用戶能進入正常流程,就應該順利把至少一個環(huán)節(jié)順利完成,而不是突然就卡在那里沒有任何 回應。

快跑題了。我談到這點,其實是想表達,說的容易,做起來是很難的。下一篇我會寫到我們在過年前出的一個事故和這個就有一些關系。

八卦時間:

陌陌勁舞團是陌陌游戲平臺上線的第 2 款游戲。我們的陌陌爭霸還在開發(fā)的時候,這款游戲就打算上線了。我對這個產(chǎn)品有限的了解都是道聽途說,所以如果有更清楚內情的同學發(fā)現(xiàn)說的不對,也請諒解。對于技術問題,我想八卦的真相就并不那么重要了,有則改之,無則嘉勉。

勁舞團這個品牌原本是屬于韓國人的,但這款游戲在國內曾經(jīng)異常火爆,在國內代理它的久游也就買下來 IP ,自己制作手機版。據(jù)我所知,陌陌勁舞團完全是在上海開發(fā)的,沒韓國人什么事。

這是個比較簡單的游戲,至少服務器部分很簡單,也就是統(tǒng)計下分數(shù),查查排名,以及解決一下收費問題而已。刨掉這些部分,它就是個單機游戲,根本不需要服務器。

因為勁舞團的品牌名氣,以及陌陌巨大的用戶群,游戲一上線就在 ios 免費榜飚上去了。如果不是企鵝公司看不順眼,立刻上線了節(jié)奏大師,估計還會在榜單上更火一些。事后證明節(jié)奏大師的上線也很倉促,完全是為了打擊競爭對手搶 著上的,因為后者的服務器也不穩(wěn)定,很快就掛掉了,完全不像一個大公司應有的質量。

陌陌勁舞團順利拉來了用戶后,第一天服務器就出了狀況,重啟了幾次后完全不解決問題。所以決定停服休整。一停就是三天。當時我就納悶了,哪有修個小 bug 預計要三天的?這肯定是有結構性問題了。當時我們的項目按計劃也就最后半個月的時間了,本來陌陌的人督的我們很緊的,一下子人全飛去了上海。

一周后陌陌勁舞團才重新上線,遠超過當初預計的 3 天。事情一解決,陌陌的技術班底,從 CTO 到下面大多數(shù)人,全部飛到廣州和我們開會,讓我們重視服務器穩(wěn)定性問題。會議內容主要是強調陌陌平臺初期導入用戶瞬間爆發(fā)量巨大,以及了解一下我們的設計 細節(jié)確保沒有大的問題。我所了解到的八卦就是在這段時間聽來的。

陌陌勁舞團使用的是 MongoDB 。似乎這玩意很受游戲開發(fā)者喜愛。我想主要是因為用起來簡單直接吧。游戲從業(yè)者如果之前沒有別的領域的開發(fā)經(jīng)驗,對數(shù)據(jù)庫這東西一知半解的人居多。尤其是 從客戶端開發(fā)過來的人,他們通常的習慣就是看 API 文檔,了解怎么用看起來正確就夠了。然后上線測試一下,好像也對,工作似乎就結束了。就算有壓力測試,也很難做到和生產(chǎn)環(huán)境一致。

上線前,據(jù)說雙方溝通過。陌陌方想確認系統(tǒng)能不能橫向擴展,得到的答復是可以:加硬件即可。我想陌陌勁舞團開發(fā)方的思路是這樣的:我們的服務器系統(tǒng) 很簡單,不都是過一下數(shù)據(jù)庫么?MongoDB 是被很多人驗證過的,不會在這么簡單的業(yè)務中出問題吧。至于負載,不是還有 mongos 么?放心啦,沒事的。

最終的直接問題出在排行榜上。當有兩萬人在線時(沒錯,才兩萬人而已),大量用戶的排行榜查詢阻塞了數(shù)據(jù)庫。導致不僅僅是排行榜刷不出來,連沖值業(yè)務也受到了影響。土豪們充不進去錢,談什么玩游戲啊。最終產(chǎn)生了雪崩,整個數(shù)據(jù)庫都不正常使得游戲系統(tǒng)工作不起來。

為啥用了這么長時間才修好這個 bug ?

負責陌陌勁舞團的服務器開發(fā)的人在項目做完就離職了。想想一個設計有問題的系統(tǒng)交給非設計者維護有多糟糕吧?任何清醒的程序員都知道,這個時候即使是重寫也比改問題簡單。陌陌的同學做了個正確的決定,直接派自己的人駐留在上海,把服務器重新寫了一遍。

陌陌的技術背景是 Redis 的,他們的系統(tǒng)用 redis 構建,所以重寫就用了 redis 取代 mongodb 。寫到這里,我完全沒有 redis 和 mongodb 誰好誰差的意思。關鍵在人,你對什么熟悉就用什么,哪種數(shù)據(jù)庫都能對付這點小業(yè)務,關鍵看你能不能用對。

Redis 里正好有一個有序集(Sorted Set) 的數(shù)據(jù)結構,你用 ZADD 插入完數(shù)據(jù)后,它就天然有序了。這個插入是 O( M * log(N)) 的時間復雜度,基本可以滿足需求。而用 ZRANGE 查詢榜單僅需 O(log(N)+M) 的時間復雜度。

那么使用 Redis ,利用 sorted set 做排行榜系統(tǒng)是我們的唯一選擇么?絕對不是。我們也不可能為了這個特性必須選擇 redis 做數(shù)據(jù)庫。但這個例子可以說明:如果數(shù)據(jù)庫提供內在的特性可以對數(shù)據(jù)集做一些操作,我們就直接用,但需要了解這種操作的性能。它需要和整個系統(tǒng)對它的性能 期望匹配。

陌陌勁舞團使用 mongodb 內置的排序功能去做排行榜本也不是大問題。或許僅僅只是實現(xiàn)的人對 mongo 不熟悉造成的性能低下。這些隨著系統(tǒng)重建已經(jīng)無法深究了。但核心問題是,僅僅一個排行榜系統(tǒng)的錯誤實現(xiàn)為何會影響整個系統(tǒng)的穩(wěn)定性?

下面就是我的猜測了:

許多程序員為了提高數(shù)據(jù)庫的吞吐量,并不是一個事務就給數(shù)據(jù)庫建一個連接,用完就關掉的。因為新建 TCP 連接是個開銷較大的操作。維持太多連接對系統(tǒng)也是一個開銷。同學們喜歡做一個叫做連接池的東西,在系統(tǒng)其它部分和數(shù)據(jù)庫對接的地方走這個連接池。只要一個 舊有連接沒有斷開,就一直把對數(shù)據(jù)庫的請求通過固定連接發(fā)給數(shù)據(jù)庫,等待返回。

在數(shù)據(jù)庫的吞吐量滿足系統(tǒng)需求的時候,這個模塊很容易實現(xiàn)正確。但一旦超出需求,連接池上的數(shù)據(jù)就會越積越多,數(shù)據(jù)庫查詢越來越慢。而調用數(shù)據(jù)庫的模塊卻不覺得這是問題。

正確的行為應該是讓連接池快速反饋,斷開并扔掉不可能處理完的請求,讓請求方把這個不能處理的錯誤反饋到上個環(huán)節(jié),直到流量被限制在合理的范圍內。整個系統(tǒng)才能不至于崩潰。當錯誤被迫反饋到玩家那里時,他頂多看到的是查詢失敗,而不太會影響到別的功能。

陌陌爭霸怎樣做排行榜的?

在上一篇里就有同學問道,如果你們不用數(shù)據(jù)庫,怎么做排行榜呢? 其實我在上一篇正文里就有解答:

“服務器只是在不斷的創(chuàng)造新數(shù)據(jù)并讓這些數(shù)據(jù)在內存中流通而已,它沒有任何需要從外部讀取數(shù)據(jù)。如果內存無限大,且服務器永遠不會當機,數(shù)據(jù)庫這個設施沒有存在的必要。”

排行榜單也是數(shù)據(jù)之一,游戲服務器開服一刻起,沒有任何玩家有排名信息。隨著玩家名次更替,榜單才逐步形成。我們只需要在玩家分數(shù)變化的時候同步榜單的變化即可。而玩家查詢僅僅是取走有序的榜單而已。

你看,這個過程和數(shù)據(jù)庫無關不是?需要設計的是調整榜單的算法,和榜單的數(shù)據(jù)結構以保證維持榜單的性能足夠強就好了。因為玩家名詞更替的頻率遠小于玩家網(wǎng)絡包的頻率,那么這個模塊的處理能力所需要的下限很容易滿足。我們不用考慮處理不過來的情況。

針對陌陌爭霸我們是這樣做的:

陌陌爭霸中用于排名的分數(shù)區(qū)間不大,也就是 0 分到 5000 分。而參與排名的人數(shù)眾多,數(shù)以百萬計。對百萬用戶做插入排序,每個插入即使是 O(N) 的也不可接受。可事實是大量玩家的分數(shù)相同,都是并列排名的。所以我們只需要做 5000 個桶,每個桶里僅記錄這個分數(shù)有多少個人就可以了。

當玩家分數(shù)變遷,把原來的桶減一,新的桶加一。這個操作就是 O(1) 的。

而排行榜的查詢僅需要把當前分數(shù)靠前的桶累加,就能獲知查詢者的名次。對于上百萬玩家,看到哪些人和你并列的人的名字是沒有意義的。這個查詢雖然是 O(n) 復雜度,但 n 只有區(qū)區(qū) 5000 ,還可以做 cache 以應對查詢頻率遠高于更新頻率的情況。

真正需要精確知道人名的是榜單的前 200 個人,而對前 200 個人做插入排序也很快,所以并不會造成性能問題。

我們在系統(tǒng)的單點做排行榜的維持,完全沒有外部數(shù)據(jù)庫操作,它只是一小段操作普通內存結構的 c 代碼。而這個單點遠遠成為不了整個系統(tǒng)的熱點。

我們在系統(tǒng)臨時退出時,把已經(jīng)排好的榜單落地,下次啟動的時候恢復。但也不必完全信任落地的數(shù)據(jù),可以用離線腳本檢索整個數(shù)據(jù)庫重新生成一份正確的榜單。所以數(shù)據(jù)庫中的榜單只是被 cache 起來而已,系統(tǒng)運行期間是不需要寫入數(shù)據(jù)庫的,也不用擔心數(shù)據(jù)丟失。

好吧,還是沒談到我們自己踩的坑,就又到了吃飯時間 :( 。

明天我將寫寫陌陌爭霸在運營期間遇到的第一起數(shù)據(jù)庫事故,它和 mongos 有關。同時也會談談我們在代理狂刃期間幫狂刃填的一些和 mongodb 有關的坑。

原文地址。51CTO獲作者授權轉載。

責任編輯:徐川 來源: blog
相關推薦

2014-03-09 23:29:12

2014-03-09 23:22:26

手游開發(fā)數(shù)據(jù)庫

2014-03-05 09:31:54

陌陌爭霸數(shù)據(jù)庫

2015-03-31 18:26:43

陌陌社交

2012-08-31 14:36:19

陌陌林志霖社交應用

2012-08-27 09:39:23

陌陌社交APP

2014-07-25 15:41:12

陌陌WOT2014GoRedis

2022-09-02 09:06:17

數(shù)據(jù)庫Oracle

2021-12-06 16:35:33

QQ微博社交軟件

2013-08-23 09:41:19

2021-07-09 14:18:15

數(shù)據(jù)庫DB-EnginesOracle

2014-08-15 17:51:39

聽云

2015-05-12 14:34:09

陌陌

2015-05-27 11:05:46

阿里云陌陌CDN

2015-12-11 16:07:03

光合資本

2021-08-05 10:46:21

數(shù)據(jù)庫SQL ServerDB-Engines

2021-04-02 12:51:03

數(shù)據(jù)庫DB-EnginesMongoDB

2022-08-03 08:26:03

數(shù)據(jù)庫OracleMySQL

2015-11-11 15:17:16

雙十一單身陌陌

2012-08-21 15:52:48

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: h小视频| 国产精品高潮呻吟久久 | 天天操天天干天天透 | 国产一区成人 | 日韩精品一区二区三区视频播放 | 日韩国产中文字幕 | 国产小u女发育末成年 | 正在播放一区二区 | 成人av色 | aaa级片 | 亚洲视频不卡 | 草樱av | 中文字幕在线欧美 | a级在线免费观看 | 91在线一区 | 亚洲成人一区二区 | 在线视频一区二区 | 亚洲视频在线免费观看 | 国产一级毛片视频 | 欧美一区二区网站 | 国产亚洲精品精品国产亚洲综合 | 在线观看免费毛片 | 日日欧美| 成人毛片一区二区三区 | 亚洲成人av在线播放 | 国产欧美一区二区三区另类精品 | 日韩三级电影一区二区 | 亚洲网站在线播放 | 久草网址 | 欧区一欧区二欧区三免费 | 伊人艹| 人成精品 | 韩国理论电影在线 | 欧美日产国产成人免费图片 | www.99精品| 日韩a在线 | 日韩av一二三区 | 99久久婷婷 | 精品国产伦一区二区三区观看体验 | 先锋影音资源网站 | 人人玩人人添人人澡欧美 |