Codis作者黃東旭細(xì)說分布式Redis架構(gòu)設(shè)計和踩過的那些坑們 - OPEN 開發(fā)經(jīng)驗庫 http://www.open-open.com/lib/view/open1436360508098.html
本次分享的內(nèi)容主要包括五個大部分:
Redis、RedisCluster和Codis;
我們更愛一致性;
Codis在生產(chǎn)環(huán)境中的使用的經(jīng)驗和坑們;
對于分布式數(shù)據(jù)庫和分布式架構(gòu)的一些看法;
Q & A環(huán)節(jié)。
Codis是一個分布式Redis解決方案,與官方的純P2P的模式不同,Codis采用的是Proxy-based的方案。今天我們介紹一下Codis及下一個大版本RebornDB的設(shè)計,同時會介紹一些Codis在實際應(yīng)用場景中的tips。最后拋磚引玉,會介紹一下我對分布式存儲的一些觀點和看法,望各位首席們雅正。
一、 Redis,RedisCluster和Codis
Redis:想必大家的架構(gòu)中,Redis已經(jīng)是一個必不可少的部件,豐富的數(shù)據(jù)結(jié)構(gòu)和超高的性能以及簡單的協(xié)議,讓Redis能夠很好的作為數(shù)據(jù)庫的上游緩存層。但是我們會比較擔(dān)心Redis的單點問題,單點Redis容量大小總受限于內(nèi)存,在業(yè)務(wù)對性能要求比較高的情況下,理想情況下我們希望所有的數(shù)據(jù)都能在內(nèi)存里面,不要打到數(shù)據(jù)庫上,所以很自然的就會尋求其他方案。 比如,SSD將內(nèi)存換成了磁盤,以換取更大的容量。更自然的想法是將Redis變成一個可以水平擴(kuò)展的分布式緩存服務(wù),在Codis之前,業(yè)界只有Twemproxy,但是Twemproxy本身是一個靜態(tài)的分布式Redis方案,進(jìn)行擴(kuò)容/縮容時候?qū)\(yùn)維要求非常高,而且很難做到平滑的擴(kuò)縮容。Codis的目標(biāo)其實就是盡量兼容Twemproxy的基礎(chǔ)上,加上數(shù)據(jù)遷移的功能以實現(xiàn)擴(kuò)容和縮容,最終替換Twemproxy。從豌豆莢最后上線的結(jié)果來看,最后完全替換了Twem,大概2T左右的內(nèi)存集群。
**Redis Cluster **:與Codis同期發(fā)布正式版的官方cluster,我認(rèn)為有優(yōu)點也有缺點,作為架構(gòu)師,我并不會在生產(chǎn)環(huán)境中使用,原因有兩個:
cluster的數(shù)據(jù)存儲模塊和分布式的邏輯模塊是耦合在一起的,這個帶來的好處是部署異常簡單,all-in-the-box,沒有像Codis那么多概念,組件和依賴。但是帶來的缺點是,你很難對業(yè)務(wù)進(jìn)行無痛的升級。比如哪天Redis cluster的分布式邏輯出現(xiàn)了比較嚴(yán)重的bug,你該如何升級?除了滾動重啟整個集群,沒什么好辦法。這個比較傷運(yùn)維。
對協(xié)議進(jìn)行了較大的修改,對客戶端不太友好,目前很多客戶端已經(jīng)成為事實標(biāo)準(zhǔn),而且很多程序已經(jīng)寫好了,讓業(yè)務(wù)方去更換Redisclient,是不太現(xiàn)實的,而且目前很難說有哪個Rediscluster客戶端經(jīng)過了大規(guī)模生產(chǎn)環(huán)境的驗證,從HunanTV開源的Rediscluster proxy上可以看得出這個影響還是蠻大的,否則就會支持使用cluster的client了。
Codis:和Redis cluster不同的是,Codis采用一層無狀態(tài)的proxy層,將分布式邏輯寫在proxy上,底層的存儲引擎還是Redis本身(盡管基于Redis2.8.13上做了一些小patch),數(shù)據(jù)的分布狀態(tài)存儲于zookeeper(etcd)中,底層的數(shù)據(jù)存儲變成了可插拔的部件。這個事情的好處其實不用多說,就是各個部件是可以動態(tài)水平擴(kuò)展的,尤其無狀態(tài)的proxy對于動態(tài)的負(fù)載均衡,還是意義很大的,而且還可以做一些有意思的事情,比如發(fā)現(xiàn)一些slot的數(shù)據(jù)比較冷,可以專門用一個支持持久化存儲的server group來負(fù)責(zé)這部分slot,以節(jié)省內(nèi)存,當(dāng)這部分?jǐn)?shù)據(jù)變熱起來時,可以再動態(tài)的遷移到內(nèi)存的server group上,一切對業(yè)務(wù)透明。比較有意思的是,在Twitter內(nèi)部棄用Twmeproxy后,t家自己開發(fā)了一個新的分布式Redis解決方案,仍然走的是proxy-based路線。不過沒有開源出來。可插拔存儲引擎這個事情也是Codis的下一代產(chǎn)品RebornDB在做的一件事情。btw,RebornDB和它的持久化引擎都是完全開源的,見https://github.com/reborndb/reborn和https://github.com/reborndb/qdb。當(dāng)然這樣的設(shè)計的壞處是,經(jīng)過了proxy,多了一次網(wǎng)絡(luò)交互,看上去性能下降了一些,但是記住,我們的proxy是可以動態(tài)擴(kuò)展的,整個服務(wù)的QPS并不由單個proxy的性能決定(所以生產(chǎn)環(huán)境中我建議使用LVS/HA Proxy或者Jodis),每個proxy其實都是一樣的。
二、我們更愛一致性
很多朋友問我,為什么不支持讀寫分離,其實這個事情的原因很簡單,因為我們當(dāng)時的業(yè)務(wù)場景不能容忍數(shù)據(jù)不一致,由于Redis本身的replication模型是主從異步復(fù)制,在master上寫成功后,在slave上是否能讀到這個數(shù)據(jù)是沒有保證的,而讓業(yè)務(wù)方處理一致性的問題還是蠻麻煩的。而且Redis單點的性能還是蠻高的,不像mysql之類的真正的數(shù)據(jù)庫,沒有必要為了提升一點點讀QPS而讓業(yè)務(wù)方困惑。這和數(shù)據(jù)庫的角色不太一樣。所以,你可能看出來了,其實Codis的HA,并不能保證數(shù)據(jù)完全不丟失,因為是異步復(fù)制,所以master掛掉后,如果有沒有同步到slave上的數(shù)據(jù),此時將slave提升成master后,剛剛寫入的還沒來得及同步的數(shù)據(jù)就會丟失。不過在RebornDB中我們會嘗試對持久化存儲引擎(qdb)可能會支持同步復(fù)制(syncreplication),讓一些對數(shù)據(jù)一致性和安全性有更強(qiáng)要求的服務(wù)可以使用。
說到一致性,這也是Codis支持的MGET/MSET無法保證原本單點時的原子語義的原因。 因為MSET所參與的key可能分不在不同的機(jī)器上,如果需要保證原來的語義,也就是要么一起成功,要么一起失敗,這樣就是一個分布式事務(wù)的問題,對于Redis來說,并沒有WAL或者回滾這么一說,所以即使是一個最簡單的二階段提交的策略都很難實現(xiàn),而且即使實現(xiàn)了,性能也沒有保證。所以在Codis中使用MSET/MGET其實和你本地開個多線程SET/GET效果一樣,只不過是由服務(wù)端打包返回罷了,我們加上這個命令的支持只是為了更好的支持以前用Twemproxy的業(yè)務(wù)。
在實際場景中,很多朋友使用了lua腳本以擴(kuò)展Redis的功能,其實Codis這邊是支持的,但記住,Codis在涉及這種場景的時候,僅僅是轉(zhuǎn)發(fā)而已,它并不保證你的腳本操作的數(shù)據(jù)是否在正確的節(jié)點上。比如,你的腳本里涉及操作多個key,Codis能做的就是將這個腳本分配到參數(shù)列表中的第一個key的機(jī)器上執(zhí)行。所以這種場景下,你需要自己保證你的腳本所用到的key分布在同一個機(jī)器上,這里可以采用hashtag的方式。
比如你有一個腳本是操作某個用戶的多個信息,如uid1age,uid1sex,uid1name形如此類的key,如果你不用hashtag的話,這些key可能會分散在不同的機(jī)器上,如果使用了hashtag(用花括號擴(kuò)住計算hash的區(qū)域):{uid1}age,{uid1}sex,{uid1}name,這樣就保證這些key分布在同一個機(jī)器上。這個是twemproxy引入的一個語法,我們這邊也支持了。
在開源Codis后,我們收到了很多社區(qū)的反饋,大多數(shù)的意見是集中在Zookeeper的依賴,Redis的修改,還有為啥需要Proxy上面,我們也在思考,這幾個東西是不是必須的。當(dāng)然這幾個部件帶來的好處毋庸置疑,上面也闡述過了,但是有沒有辦法能做得更漂亮。于是,我們在下一階段會再往前走一步,實現(xiàn)以下幾個設(shè)計:
使用proxy內(nèi)置的Raft來代替外部的Zookeeper,zk對于我們來說,其實只是一個強(qiáng)一致性存儲而已,我們其實可以使用Raft來做到同樣的事情。將raft嵌入proxy,來同步路由信息。達(dá)到減少依賴的效果。
抽象存儲引擎層,由proxy或者第三方的agent來負(fù)責(zé)啟動和管理存儲引擎的生命周期。具體來說,就是現(xiàn)在codis還需要手動的去部署底層的Redis或者qdb,自己配置主從關(guān)系什么的,但是未來我們會把這個事情交給一個自動化的agent或者甚至在proxy內(nèi)部集成存儲引擎。這樣的好處是我們可以最大程度上的減小Proxy轉(zhuǎn)發(fā)的損耗(比如proxy會在本地啟動Redis instance)和人工誤操作,提升了整個系統(tǒng)的自動化程度。
還有replication based migration。眾所周知,現(xiàn)在Codis的數(shù)據(jù)遷移方式是通過修改底層Redis,加入單key的原子遷移命令實現(xiàn)的。這樣的好處是實現(xiàn)簡單、遷移過程對業(yè)務(wù)無感知。但是壞處也是很明顯,首先就是速度比較慢,而且對Redis有侵入性,還有維護(hù)slot信息給Redis帶來額外的內(nèi)存開銷。大概對于小key-value為主業(yè)務(wù)和原生Redis是1:1.5的比例,所以還是比較費(fèi)內(nèi)存的。
在RebornDB中我們會嘗試提供基于復(fù)制的遷移方式,也就是開始遷移時,記錄某slot的操作,然后在后臺開始同步到slave,當(dāng)slave同步完后,開始將記錄的操作回放,回放差不多后,將master的寫入停止,追平后修改路由表,將需要遷移的slot切換成新的master,主從(半)同步復(fù)制,這個之前提到過。
三、Codis在生產(chǎn)環(huán)境中的使用的經(jīng)驗和坑們
來說一些 tips,作為開發(fā)工程師,一線的操作經(jīng)驗肯定沒有運(yùn)維的同學(xué)多,大家一會可以一起再深度討論。
關(guān)于多產(chǎn)品線部署:很多朋友問我們?nèi)绻卸鄠€項目時,codis如何部署比較好,我們當(dāng)時在豌豆莢的時候,一個產(chǎn)品線會部署一整套codis,但是zk共用一個,不同的codis集群擁有不同的product name來區(qū)分,codis本身的設(shè)計沒有命名空間那么一說,一個codis只能對應(yīng)一個product name。不同product name的codis集群在同一個zk上不會相互干擾。
關(guān)于zk:由于Codis是一個強(qiáng)依賴的zk的項目,而且在proxy和zk的連接發(fā)生抖動造成sessionexpired的時候,proxy是不能對外提供服務(wù)的,所以盡量保證proxy和zk部署在同一個機(jī)房。生產(chǎn)環(huán)境中zk一定要是>=3臺的奇數(shù)臺機(jī)器,建議5臺物理機(jī)。
關(guān)于HA:這里的HA分成兩部分,一個是proxy層的HA,還有底層Redis的HA。先說proxy層的HA。之前提到過proxy本身是無狀態(tài)的,所以proxy本身的HA是比較好做的,因為連接到任何一個活著的proxy上都是一樣的,在生產(chǎn)環(huán)境中,我們使用的是jodis,這個是我們開發(fā)的一個jedis連接池,很簡單,就是監(jiān)聽zk上面的存活proxy列表,挨個返回jedis對象,達(dá)到負(fù)載均衡和HA的效果。也有朋友在生產(chǎn)環(huán)境中使用LVS和HA Proxy來做負(fù)載均衡,這也是可以的。 Redis本身的HA,這里的Redis指的是codis底層的各個server group的master,在一開始的時候codis本來就沒有將這部分的HA設(shè)計進(jìn)去,因為Redis在掛掉后,如果直接將slave提升上來的話,可能會造成數(shù)據(jù)不一致的情況,因為有新的修改可能在master中還沒有同步到slave上,這種情況下需要管理員手動的操作修復(fù)數(shù)據(jù)。后來我們發(fā)現(xiàn)這個需求確實比較多的朋友反映,于是我們開發(fā)了一個簡單的ha工具:codis-ha,用于監(jiān)控各個server group的master的存活情況,如果某個master掛掉了,會直接提升該group的一個slave成為新的master。 項目的地址是:https://github.com/ngaut/codis-ha。
關(guān)于dashboard:dashboard在codis中是一個很重要的角色,所有的集群信息變更操作都是通過dashboard發(fā)起的(這個設(shè)計有點像docker),dashboard對外暴露了一系列RESTfulAPI接口,不管是web管理工具,還是命令行工具都是通過訪問這些httpapi來進(jìn)行操作的,所以請保證dashboard和其他各個組件的網(wǎng)絡(luò)連通性。比如,經(jīng)常發(fā)現(xiàn)有用戶的dashboard中集群的ops為0,就是因為dashboard無法連接到proxy的機(jī)器的緣故。
關(guān)于go環(huán)境:在生產(chǎn)環(huán)境中盡量使用go1.3.x的版本,go的1.4的性能很差,更像是一個中間版本,還沒有達(dá)到production ready的狀態(tài)就發(fā)布了。很多朋友對go的gc頗有微詞,這里我們不討論哲學(xué)問題,選擇go是多方面因素權(quán)衡后的結(jié)果,而且codis是一個中間件類型的產(chǎn)品,并不會有太多小對象常駐內(nèi)存,所以對于gc來說基本毫無壓力,所以不用考慮gc的問題。
關(guān)于隊列的設(shè)計:其實簡單來說,就是「不要把雞蛋放在一個籃子」的道理,盡量不要把數(shù)據(jù)都往一個key里放,因為codis是一個分布式的集群,如果你永遠(yuǎn)只操作一個key,就相當(dāng)于退化成單個Redis實例了。很多朋友將Redis用來做隊列,但是Codis并沒有提供BLPOP/BLPUSH的接口,這沒問題,可以將列表在邏輯上拆成多個LIST的key,在業(yè)務(wù)端通過定時輪詢來實現(xiàn)(除非你的隊列需要嚴(yán)格的時序要求),這樣就可以讓不同的Redis來分擔(dān)這個同一個列表的訪問壓力。而且單key過大可能會造成遷移時的阻塞,由于Redis是一個單線程的程序,所以遷移的時候會阻塞正常的訪問。
關(guān)于主從和bgsave:codis本身并不負(fù)責(zé)維護(hù)Redis的主從關(guān)系,在codis里面的master和slave只是概念上的:proxy會將請求打到「master」上,master掛了codis-ha會將某一個「slave」提升成master。而真正的主從復(fù)制,需要在啟動底層的Redis時手動的配置。在生產(chǎn)環(huán)境中,我建議master的機(jī)器不要開bgsave,也不要輕易的執(zhí)行save命令,數(shù)據(jù)的備份盡量放在slave上操作。
關(guān)于跨機(jī)房/多活:想都別想。。。codis沒有多副本的概念,而且codis多用于緩存的業(yè)務(wù)場景,業(yè)務(wù)的壓力是直接打到緩存上的,在這層做跨機(jī)房架構(gòu)的話,性能和一致性是很難得到保證的
關(guān)于proxy的部署:其實可以將proxy部署在client很近的地方,比如同一個物理機(jī)上,這樣有利于減少延遲,但是需要注意的是,目前jodis并不會根據(jù)proxy的位置來選擇位置最佳的實例,需要修改。
四、對于分布式數(shù)據(jù)庫和分布式架構(gòu)的一些看法(one more Thing)
Codis相關(guān)的內(nèi)容告一段落。接下來我想聊聊我對于分布式數(shù)據(jù)庫和分布式架構(gòu)的一些看法。 架構(gòu)師們是如此貪心,有單點就一定要變成分布式,同時還希望盡可能的透明:P。就MySQL來看,從最早的單點到主從讀寫分離,再到后來阿里的類似Cobar和TDDL,分布式和可擴(kuò)展性是達(dá)到了,但是犧牲了事務(wù)支持,于是有了后來的OceanBase。Redis從單點到Twemproxy,再到Codis,再到Reborn。到最后的存儲早已和最初的面目全非,但協(xié)議和接口永存,比如SQL和Redis Protocol。
NoSQL來了一茬又一茬,從HBase到Cassandra到MongoDB,解決的是數(shù)據(jù)的擴(kuò)展性問題,通過裁剪業(yè)務(wù)的存儲和查詢的模型來在CAP上平衡。但是幾乎還是都丟掉了跨行事務(wù)(插一句,小米上在HBase上加入了跨行事務(wù),不錯的工作)。
我認(rèn)為,拋開底層存儲的細(xì)節(jié),對于業(yè)務(wù)來說,KV,SQL查詢(關(guān)系型數(shù)據(jù)庫支持)和事務(wù),可以說是構(gòu)成業(yè)務(wù)系統(tǒng)的存儲原語。為什么memcached/Redis+mysql的組合如此的受歡迎,正是因為這個組合,幾個原語都能用上,對于業(yè)務(wù)來說,可以很方便的實現(xiàn)各種業(yè)務(wù)的存儲需求,能輕易的寫出「正確」的程序。但是,現(xiàn)在的問題是數(shù)據(jù)大到一定程度上時,從單機(jī)向分布式進(jìn)化的過程中,最難搞定的就是事務(wù),SQL支持什么的還可以通過各種mysqlproxy搞定,KV就不用說了,天生對分布式友好。
于是這樣,我們就默認(rèn)進(jìn)入了一個沒有(跨行)事務(wù)支持的世界里,很多業(yè)務(wù)場景我們只能犧牲業(yè)務(wù)的正確性來在實現(xiàn)的復(fù)雜度上平衡。比如一個很簡單的需求:微博關(guān)注數(shù)的變化,最直白,最正常的寫法應(yīng)該是,將被關(guān)注者的被關(guān)注數(shù)的修改和關(guān)注者的關(guān)注數(shù)修改放到同一個事務(wù)里,一起提交,要么一起成功,要么一起失敗。但是現(xiàn)在為了考慮性能,為了考慮實現(xiàn)復(fù)雜度,一般來說的做法可能是隊列輔助異步的修改,或者通過cache先暫存等等方式繞開事務(wù)。
但是在一些需要強(qiáng)事務(wù)支持的場景就沒有那么好繞過去了(目前我們只討論開源的架構(gòu)方案),比如支付/積分變更業(yè)務(wù),常見的搞法是關(guān)鍵路徑根據(jù)用戶特征sharding到單點MySQL,或者M(jìn)ySQLXA,但是性能下降得太厲害。
后來Google在他們的廣告業(yè)務(wù)中遇到這個問題,既需要高性能,又需要分布式事務(wù),還必須保證一致性:),Google在此之前是通過一個大規(guī)模的MySQL集群通過sharding苦苦支撐,這個架構(gòu)的可運(yùn)維/擴(kuò)展性實在太差。這要是在一般公司,估計也就忍了,但是Google可不是一般公司,用原子鐘搞定Spanner,然后再Spanner上構(gòu)建了SQL查詢層F1。我在第一次看到這個系統(tǒng)的時候,感覺簡直驚艷,應(yīng)該是第一個可以真正稱為NewSQL的公開設(shè)計的系統(tǒng)。所以,BigTable(KV)+F1(SQL)+Spanner(高性能分布式事務(wù)支持),同時Spanner還有一個非常重要的特性是跨數(shù)據(jù)中心的復(fù)制和一致性保證(通過Paxos實現(xiàn)),多數(shù)據(jù)中心,剛好補(bǔ)全了整個Google的基礎(chǔ)設(shè)施的數(shù)據(jù)庫棧,使得Google對于幾乎任何類型的業(yè)務(wù)系統(tǒng)開發(fā)都非常方便。我想,這就是未來的方向吧,一個可擴(kuò)展的KV數(shù)據(jù)庫(作為緩存和簡單對象存儲),一個高性能支持分布式事務(wù)和SQL查詢接口的分布式關(guān)系型數(shù)據(jù)庫,提供表支持。
五、Q & A
Q1:我沒看過Codis,您說Codis沒有多副本概念,請問是什么意思?
A1:Codis是一個分布式Redis解決方案,是通過presharding把數(shù)據(jù)在概念上分成1024個slot,然后通過proxy將不同的key的請求轉(zhuǎn)發(fā)到不同的機(jī)器上,數(shù)據(jù)的副本還是通過Redis本身保證
Q2:Codis的信息在一個zk里面存儲著,zk在Codis中還有別的作用嗎?主從切換為何不用sentinel
A2:Codis的特點是動態(tài)的擴(kuò)容縮容,對業(yè)務(wù)透明;zk除了存儲路由信息,同時還作為一個事件同步的媒介服務(wù),比如變更master或者數(shù)據(jù)遷移這樣的事情,需要所有的proxy通過監(jiān)聽特定zk事件來實現(xiàn) 可以說zk被我們當(dāng)做了一個可靠的rpc的信道來使用。因為只有集群變更的admin時候會往zk上發(fā)事件,proxy監(jiān)聽到以后,回復(fù)在zk上,admin收到各個proxy的回復(fù)后才繼續(xù)。本身集群變更的事情不會經(jīng)常發(fā)生,所以數(shù)據(jù)量不大。Redis的主從切換是通過codis-ha在zk上遍歷各個server group的master判斷存活情況,來決定是否發(fā)起提升新master的命令。
Q3:數(shù)據(jù)分片,是用的一致性hash嗎?請具體介紹下,謝謝。
A3:不是,是通過presharding,hash算法是crc32(key)%1024
Q4:怎么進(jìn)行權(quán)限管理?
A4:Codis中沒有鑒權(quán)相關(guān)的命令,在reborndb中加入了auth指令。
Q5:怎么禁止普通用戶鏈接Redis破壞數(shù)據(jù)?
A5:同上,目前Codis沒有auth,接下來的版本會加入。
Q6:Redis跨機(jī)房有什么方案?
A6:目前沒有好的辦法,我們的Codis定位是同一個機(jī)房內(nèi)部的緩存服務(wù),跨機(jī)房復(fù)制對于Redis這樣的服務(wù)來說,一是延遲較大,二是一致性難以保證,對于性能要求比較高的緩存服務(wù),我覺得跨機(jī)房不是好的選擇。
Q7:集群的主從怎么做(比如集群S是集群M的從,S和M的節(jié)點數(shù)可能不一樣,S和M可能不在一個機(jī)房)?
A7:Codis只是一個proxy-based的中間件,并不負(fù)責(zé)數(shù)據(jù)副本相關(guān)的工作。也就是數(shù)據(jù)只有一份,在Redis內(nèi)部。
Q8:根據(jù)你介紹了這么多,我可以下一個結(jié)論,你們沒有多租戶的概念,也沒有做到高可用。可以這么說吧?你們更多的是把Redis當(dāng)做一個cache來設(shè)計。
A8:對,其實我們內(nèi)部多租戶是通過多Codis集群解決的,Codis更多的是為了替換twemproxy的一個項目。高可用是通過第三方工具實現(xiàn)。Redis是cache,Codis主要解決的是Redis單點、水平擴(kuò)展的問題。把codis的介紹貼一下: Auto rebalance Extremely simple to use Support both Redis or rocksdb transparently. GUI dashboard & admin tools Supports most of Redis commands. Fully compatible with twemproxy(https://github.com/twitter/twemproxy). Native Redis clients are supported Safe and transparent data migration, Easily add or remove nodes on-demand.解決的問題是這些。業(yè)務(wù)不停的情況下,怎么動態(tài)的擴(kuò)展緩存層,這個是codis關(guān)注的。
Q9:對于Redis冷備的數(shù)據(jù)庫的遷移,您有啥經(jīng)驗沒有?對于Redis熱數(shù)據(jù),可以通過migrate命令實現(xiàn)兩個Redis進(jìn)程間的數(shù)據(jù)轉(zhuǎn)移,當(dāng)然如果對端有密碼,migrate就玩完了(這個我已經(jīng)給Redis官方提交了patch)。
A9:冷數(shù)據(jù)我們現(xiàn)在是實現(xiàn)了完整的Redissync協(xié)議,同時實現(xiàn)了一個基于rocksdb的磁盤存儲引擎,備機(jī)的冷數(shù)據(jù),全部是存在磁盤上的,直接作為一個從掛在master上的。實際使用時,3個group,keys數(shù)量一致,但其中一個的ops是另外兩個的兩倍,有可能是什么原因造成的?key的數(shù)量一致并不代表實際請求是均勻分布的,不如你可能某幾個key特別熱,它一定是會落在實際存儲這個key的機(jī)器上的。剛才說的rocksdb的存儲引擎:https://github.com/reborndb/qdb,其實啟動后就是個Redis-server,支持了PSYNC協(xié)議,所以可以直接當(dāng)成Redis從來用。是一個節(jié)省從庫內(nèi)存的好方法。
Q10:Redis實例內(nèi)存占比超過50%,此時執(zhí)行bgsave,開了虛擬內(nèi)存支持的會阻塞,不開虛擬內(nèi)存支持的會直接返回err,對嗎?
A10:不一定,這個要看寫數(shù)據(jù)(開啟bgsave后修改的數(shù)據(jù))的頻繁程度,在Redis內(nèi)部執(zhí)行bgsave,其實是通過操作系統(tǒng)COW機(jī)制來實現(xiàn)復(fù)制,如果你這段時間的把幾乎所有的數(shù)據(jù)都修改了,這樣操作系統(tǒng)只能全部完整的復(fù)制出來,這樣就爆了。
Q11:剛讀完,贊一個。可否介紹下codis的autorebalance實現(xiàn)。
A11:算法比較簡單,https://github.com/wandoulabs/codis/blob/master/cmd/cconfig/rebalancer.go#L104。代碼比較清楚,code talks:)。其實就是根據(jù)各個實例的內(nèi)存比例,分配slot好的。
Q12:主要想了解對降低數(shù)據(jù)遷移對線上服務(wù)的影響,有沒有什么經(jīng)驗介紹?
A12:其實現(xiàn)在codis數(shù)據(jù)遷移的方式已經(jīng)很溫和了,是一個個key的原子遷移,如果怕抖動甚至可以加上每個key的延遲時間。這個好處就是對業(yè)務(wù)基本沒感知,但是缺點就是慢。
來自:http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=208733458&idx=1&sn=691bfde670fb2dd649685723f7358fea