紀(jì)國(guó)賢
摘 要 Redis 是一個(gè)開(kāi)源的內(nèi)存數(shù)據(jù)庫(kù),具有速度快,類型全,支持多種語(yǔ)言操作,可以把內(nèi)存中的數(shù)據(jù)同步存儲(chǔ)到硬盤(pán)上保存等優(yōu)點(diǎn),被廣泛應(yīng)用于網(wǎng)站大數(shù)據(jù)搜索,游戲服務(wù)器等領(lǐng)域。
關(guān)鍵詞 Redis 網(wǎng)絡(luò)游戲 Key-Value
中圖分類號(hào):TP3 文獻(xiàn)標(biāo)識(shí)碼:A
Redis是一個(gè)開(kāi)源的,先進(jìn)的key-value持久化產(chǎn)品。它通常被稱為數(shù)據(jù)結(jié)構(gòu)服務(wù)器,它的值可以是字符串(String)、哈希(Map)、列表(List)、集合(Sets)和有序集合(Sorted sets)等類型??梢栽谶@些類型上面做一些原子操作,如:字符串追加、增加Hash里面的值、添加元素到列表、計(jì)算集合的交集,并集和差集;或者區(qū)有序集合中排名最高的成員。為了取得好的性能,Redis是一個(gè)內(nèi)存型數(shù)據(jù)庫(kù)。不限于此,看你怎么用了,也可以把數(shù)據(jù)保存到磁盤(pán)中,或者把數(shù)據(jù)操作指令追加了一個(gè)日志文件,把它用于持久化。也可以用Redis容易的搭建master-slave架構(gòu)用于數(shù)據(jù)復(fù)制。Redis可以用大部分程序語(yǔ)言來(lái)操作:C、C++、C#、Java、Node.js、php、ruby等等。
Redis主要用于解決傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)存儲(chǔ)和查詢等操作速度緩慢的問(wèn)題,比如Mysql,Mssql。傳統(tǒng)網(wǎng)絡(luò)游戲中要把關(guān)系型數(shù)據(jù)庫(kù)的數(shù)據(jù)加載到內(nèi)存中運(yùn)算才能滿足游戲?qū)?shù)據(jù)的處理速度的需求。而從內(nèi)存到數(shù)據(jù)庫(kù)保存數(shù)據(jù)是每隔一段時(shí)間保存的,如果服務(wù)器出現(xiàn)bug,那么內(nèi)存里面的數(shù)據(jù)將會(huì)全部丟失。這就意味著玩家會(huì)丟失游戲數(shù)據(jù),比如丟了裝備,丟了進(jìn)度,只能被迫回檔,這顯然對(duì)游戲的運(yùn)營(yíng)造成了很大的困擾。因?yàn)镽edis數(shù)據(jù)庫(kù)是運(yùn)行在內(nèi)存中的,相對(duì)于基于磁盤(pán)存儲(chǔ)的傳統(tǒng)數(shù)據(jù)庫(kù),速度快了許多倍,游戲可以同步的把數(shù)據(jù)保存在redis數(shù)據(jù)庫(kù)里面,這樣即使服務(wù)器程序突然關(guān)閉也不會(huì)丟失用戶數(shù)據(jù)。
市場(chǎng)上還有Mongodb,Memcached等key-value型內(nèi)存數(shù)據(jù)庫(kù)提供了和Redis類似的功能。Mongodb是非關(guān)系型數(shù)據(jù)庫(kù),數(shù)據(jù)保存在磁盤(pán)上并且提供比較高的性能。Memcached是配合Mysql這種傳統(tǒng)數(shù)據(jù)庫(kù)的非關(guān)系型內(nèi)存數(shù)據(jù)庫(kù),也可以看成是一個(gè)數(shù)據(jù)緩存,但是他不提供數(shù)據(jù)持久化的功能,只能通過(guò)其他傳統(tǒng)數(shù)據(jù)庫(kù)保存數(shù)據(jù)。Redis數(shù)據(jù)庫(kù)比他們優(yōu)秀一個(gè)方面是他既是內(nèi)存數(shù)據(jù)庫(kù),又可以把數(shù)據(jù)保存到硬盤(pán)上。Redis有兩種硬盤(pán)存儲(chǔ)模式支持(snapshot和aof),另外Redis可以將key-value中的部分調(diào)用較少的value存儲(chǔ)在硬盤(pán)中,即VM(虛擬內(nèi)存)。Redis顯然比較適合于游戲中的應(yīng)用。
游戲服務(wù)器中涉及到很多排行信息,比如玩家等級(jí)排名、金錢(qián)排名、戰(zhàn)斗力排名等。一般情況下僅需要取排名的前N名就可以了,這時(shí)可以利用數(shù)據(jù)庫(kù)的排序功能,或者自己維護(hù)一個(gè)元素?cái)?shù)量有限的top集合。但是有時(shí)候我們需要每一個(gè)玩家的排名,玩家的數(shù)量太多,不能利用數(shù)據(jù)庫(kù)(全表排序壓力太大),自己維護(hù)也會(huì)比較麻煩。使用Redis可以很好的解決這個(gè)問(wèn)題。它提供的有序Set,支持每個(gè)鍵值(比如玩家id)擁有一個(gè)分?jǐn)?shù)(score),每次往這個(gè)set里添加元素,Redis會(huì)對(duì)其進(jìn)行排序,修改某一元素的score后,也會(huì)更新排序,在獲取數(shù)據(jù)時(shí),可以指定排序范圍。更重要的是,這個(gè)排序結(jié)果會(huì)被保存起來(lái),不用在服務(wù)器啟動(dòng)時(shí)重新計(jì)算。通過(guò)它,排行榜的實(shí)時(shí)刷新、全服排行都不再成為麻煩事。
Redis提供了較為豐富數(shù)據(jù)類型,使我們可以更為容易地將數(shù)據(jù)對(duì)象緩存起來(lái)(序列化、protobuffer)。當(dāng)需要請(qǐng)求某一數(shù)據(jù)時(shí),先從Redis中查找,如果沒(méi)有再查數(shù)據(jù)庫(kù),同時(shí)交給Redis緩存起來(lái)。當(dāng)對(duì)數(shù)據(jù)進(jìn)行修改時(shí),則先將修改后的數(shù)據(jù)保存到Redis,然后保存至數(shù)據(jù)庫(kù)??梢杂辛硗獾乃悸罚篈不實(shí)時(shí)保存到數(shù)據(jù)庫(kù),而是交由另外的線程(甚至是專門(mén)的程序)去保存,以提高邏輯層的響應(yīng)速度。B部分?jǐn)?shù)據(jù)交給Redis保存(Reids自身有持久化功能),像玩家已經(jīng)完成過(guò)的任務(wù)ID集合,利用Redis的Set類型保存更為合適。C玩家瞬時(shí)變化的數(shù)據(jù)不見(jiàn)得每次修改都需要保存(比如金錢(qián)、經(jīng)驗(yàn)),但如果游戲服務(wù)器自己維護(hù)在內(nèi)存中,出現(xiàn)宕機(jī)就會(huì)導(dǎo)致回檔。Redis是獨(dú)立于游戲服務(wù)器的,交由它來(lái)保存,可以防止宕機(jī)回檔的問(wèn)題,也可以減少游戲服務(wù)器自己維護(hù)數(shù)據(jù)所占用的內(nèi)存。
為了更好的擴(kuò)展數(shù)據(jù)庫(kù),把Redis設(shè)置成集群模式是相當(dāng)簡(jiǎn)單的事情:在Slave啟動(dòng)并連接到Master之后,它將主動(dòng)發(fā)送一個(gè)SYNC命令。此后Master將啟動(dòng)后臺(tái)存盤(pán)進(jìn)程,同時(shí)收集所有接收到的用于修改數(shù)據(jù)集的命令,在后臺(tái)進(jìn)程執(zhí)行完畢后,Master將傳送整個(gè)數(shù)據(jù)庫(kù)文件到Slave,以完成一次完全同步。而Slave服務(wù)器在接收到數(shù)據(jù)庫(kù)文件數(shù)據(jù)之后將其存盤(pán)并加載到內(nèi)存中。此后,Master繼續(xù)將所有已經(jīng)收集到的修改命令,和新的修改命令依次傳送給Slaves,Slave將在本次執(zhí)行這些數(shù)據(jù)修改命令,從而達(dá)到最終的數(shù)據(jù)同步。如果Master和Slave之間的鏈接出現(xiàn)斷連現(xiàn)象,Slave可以自動(dòng)重連Master,但是在連接成功之后,一次完全同步將被自動(dòng)執(zhí)行。
Redis數(shù)據(jù)庫(kù)優(yōu)異的性能和完善的數(shù)據(jù)處理方式,非常適合在網(wǎng)絡(luò)游戲服務(wù)器中使用,高速,穩(wěn)定,支持多種類型是它最大的優(yōu)點(diǎn)。