從應(yīng)用角度談新浪微博Redis服務(wù)平臺
可以簡單公布一下Redis平臺實(shí)際情況
2200+億 commands/day 5000億Read/day 500億Write/day
18TB+ Memory
500+ Servers in 6 IDC 2000+instances
應(yīng)該是國內(nèi)外比較大的Redis使用平臺,今天主要從應(yīng)用角度談?wù)凴edis服務(wù)平臺。
Redis使用場景
1.Counting(計(jì)數(shù))
計(jì)數(shù)的應(yīng)用在另外一篇文章里較詳細(xì)的描述,計(jì)數(shù)場景的優(yōu)化 http://www.xdata.me/?p=262 這里就不坳述了。
可以預(yù)見的是,有很多同學(xué)認(rèn)為把計(jì)數(shù)全部存在內(nèi)存中成本非常高,我在這里用個(gè)圖表來表示下我的觀點(diǎn):
很多情況大家都會設(shè)想純使用內(nèi)存的方案會很有很高成本,但實(shí)際情況往往會有一些不一樣:
1.COST,對于有一定吞吐需求的應(yīng)用來說,肯定會單獨(dú)申請DB、Cache資源,很多擔(dān)心DB寫入性能的同學(xué)還會主動將DB更新記入異步隊(duì)列,而這三塊的資源的利用率一般都不會太高。資源算下來,你驚異的發(fā)現(xiàn):反而純內(nèi)存的方案會更精簡!
2.KISS原則,這對于開發(fā)是非常友好的,我只需要建立一套連接池,不用擔(dān)心數(shù)據(jù)一致性的維護(hù),不用維護(hù)異步隊(duì)列。
3.Cache穿透風(fēng)險(xiǎn),如果后端使用DB,肯定不會提供很高的吞吐能力,cache宕機(jī)如果沒有妥善處理,那就悲劇了。
4.大多數(shù)的起始存儲需求,容量較小。
2.Reverse cache(反向cache)
面對微博常常出現(xiàn)的熱點(diǎn),如最近出現(xiàn)了較為火爆的短鏈,短時(shí)間有數(shù)以萬記的人點(diǎn)擊、跳轉(zhuǎn),而這里會常常涌現(xiàn)一些需求,比如我們向快速在跳轉(zhuǎn)時(shí)判定用戶等級,是否有一些賬號綁定,性別愛好什么的,已給其展示不同的內(nèi)容或者信息。
普通采用Memcache+Mysql的解決方案,當(dāng)調(diào)用id合法的情況下,可支撐較大的吞吐。但當(dāng)調(diào)用id不可控,有較多垃圾用戶調(diào)用時(shí),由于memcache未有命中,會大量的穿透至Mysql服務(wù)器,瞬間造成連接數(shù)瘋長,整體吞吐量降低,響應(yīng)時(shí)間變慢。
這里我們可以用redis記錄全量的用戶判定信息,如string key:uid int:type,做一次反向的cache,當(dāng)用戶在redis快速獲取自己等級等信息后,再去Mc+Mysql層去獲取全量信息。如圖:
當(dāng)然這也不是最優(yōu)化的場景,如用Redis做bloomfilter,可能更加省用內(nèi)存。
3.Top 10 list
產(chǎn)品運(yùn)營總會讓你展示最近、最熱、點(diǎn)擊率最高、活躍度最高等等條件的top list。很多更新較頻繁的列表如果使用MC+MySQL維護(hù)的話緩存失效的可能性會比較大,鑒于占用內(nèi)存較小的情況,使用Redis做存儲也是相當(dāng)不錯(cuò)的。
4.Last Index
用戶最近訪問記錄也是redis list的很好應(yīng)用場景,lpush lpop自動過期老的登陸記錄,對于開發(fā)來說還是非常友好的。
5.Relation List/Message Queue
這里把兩個(gè)功能放在最后,因?yàn)檫@兩個(gè)功能在現(xiàn)實(shí)問題當(dāng)中遇到了一些困難,但在一定階段也確實(shí)解決了我們很多的問題,故在這里只做說明。
Pinterest使用Redis存儲社交graph信息:
http://blog.gopivotal.com/case-studies-2/using-redis-at-pinterest-for-billions-of-relationships
Message Queue就是通過list的lpop及l(fā)push接口進(jìn)行隊(duì)列的寫入和消費(fèi),由于本身性能較好也能解決大部分問題。
6.Fast transaction with Lua
Redis 的Lua的功能擴(kuò)展實(shí)際給Redis帶來了更多的應(yīng)用場景,你可以編寫若干command組合作為一個(gè)小型的非阻塞事務(wù)或者更新邏輯,如:在收到message推送時(shí),同時(shí)1.給自己的增加一個(gè)未讀的對話 2.給自己的私信增加一個(gè)未讀消息 3.最后給發(fā)送人回執(zhí)一個(gè)完成推送消息,這一層邏輯完全可以在Redis Server端實(shí)現(xiàn)。
但是,需要注意的是Redis會將lua script的全部內(nèi)容記錄在aof和傳送給slave,這也將是對磁盤,網(wǎng)卡一個(gè)不小的開銷。
7.Instead of Memcache
很多測試和應(yīng)用均已證明,
1.在性能方面Redis并沒有落后Memcache多少,而單線程的模型給Redis反而帶來了很強(qiáng)的擴(kuò)展性。
2.在很多場景下,Redis對同一份數(shù)據(jù)的內(nèi)存開銷是小于Memcache的slab分配的。
3.Redis提供的數(shù)據(jù)同步功能,其實(shí)是對cache的一個(gè)強(qiáng)有力功能擴(kuò)展。
#p#
Redis使用的重要點(diǎn)
1.rdb/aof Backup!
我們線上的Redis 95%以上是承擔(dān)后端存儲功能的,我們不僅用作cache,而更為一種k-v存儲,他完全替代了后端的存儲服務(wù)(MySQL),故其數(shù)據(jù)是非常重要的,如果出現(xiàn)數(shù)據(jù)污染和丟失,誤操作等情況,將是難以恢復(fù)的。所以備份是非常必要的!為此,我們有共享的hdfs資源作為我們的備份池,希望能隨時(shí)可以還原業(yè)務(wù)所需數(shù)據(jù)。
2.Small item & Small instance!
由于Redis單線程(嚴(yán)格意義上不是單線程,但認(rèn)為對request的處理是單線程的)的模型,大的數(shù)據(jù)結(jié)構(gòu)list,sorted set,hash set的批量處理就意為著其他請求的等待,故使用Redis的復(fù)雜數(shù)據(jù)結(jié)構(gòu)一定要控制其單key-struct的大小。
另外,Redis單實(shí)例的內(nèi)存容量也應(yīng)該有嚴(yán)格的限制。單實(shí)例內(nèi)存容量較大后,直接帶來的問題就是故障恢復(fù)或者Rebuild從庫的時(shí)候時(shí)間較長,而更糟糕的是,Redis rewrite aof和save rdb時(shí),將會帶來非常大且長的系統(tǒng)壓力,并占用額外內(nèi)存,很可能導(dǎo)致系統(tǒng)內(nèi)存不足等嚴(yán)重影響性能的線上故障。我們線上96G/128G內(nèi)存服務(wù)器不建議單實(shí)例容量大于20/30G。
3.Been Available!
業(yè)界資料和使用比較多的是Redis sentinel(哨兵)
http://www.huangz.me/en/latest/storage/redis_code_analysis/sentinel.html
http://qiita.com/wellflat/items/8935016fdee25d4866d9
2000行C實(shí)現(xiàn)了服務(wù)器狀態(tài)檢測,自動故障轉(zhuǎn)移等功能。
但由于自身實(shí)際架構(gòu)往往會復(fù)雜,或者考慮的角度比較多,為此@許琦eryk 和我一同做了hypnos項(xiàng)目。
hypnos是神話中的睡神,字面意思也是希望我們工程師無需在休息時(shí)間處理任何故障。:-)
其工作原理示意如下:
Talk is cheap, show me your code! 稍后將單獨(dú)寫篇博客細(xì)致講下Hypnos的實(shí)現(xiàn)。
4.In Memory or not?
發(fā)現(xiàn)一種情況,開發(fā)在溝通后端資源設(shè)計(jì)的時(shí)候,常常因?yàn)榱?xí)慣使用和錯(cuò)誤了解產(chǎn)品定位等原因,而忽視了對真實(shí)使用用戶的評估。也許這是一份歷史數(shù)據(jù),只有最近一天的數(shù)據(jù)才有人進(jìn)行訪問,而把歷史數(shù)據(jù)的容量和最近一天請求量都拋給內(nèi)存類的存儲現(xiàn)實(shí)是非常不合理的。
所以當(dāng)你在究竟使用什么樣的數(shù)據(jù)結(jié)構(gòu)存儲的時(shí)候,請務(wù)必先進(jìn)行成本衡量,有多少數(shù)據(jù)是需要存儲在內(nèi)存中的?有多少數(shù)據(jù)是對用戶真正有意義的。因?yàn)檫@其實(shí)對后端資源的設(shè)計(jì)是至關(guān)重要的,1G的數(shù)據(jù)容量和1T的數(shù)據(jù)容量對于設(shè)計(jì)思路是完全不一樣的
Plans in future?
1.slave sync改造
全部改造線上master-slave數(shù)據(jù)同步機(jī)制,這一點(diǎn)我們借鑒了MySQL Replication的思路,使用rdb+aof+pos作為數(shù)據(jù)同步的依據(jù),這里簡要說明為什么官方提供的psync沒有很好的滿足我們的需求:
假設(shè)A有兩個(gè)從庫B及C,及 A `— B&C,這時(shí)我們發(fā)現(xiàn)master A服務(wù)器有宕機(jī)隱患需要重啟或者A節(jié)點(diǎn)直接宕機(jī),需要切換B為新的主庫,如果A、B、C不共享rdb及aof信息,C在作為B的從庫時(shí),仍會清除自身數(shù)據(jù),因?yàn)镃節(jié)點(diǎn)只記錄了和A節(jié)點(diǎn)的同步狀況。
故我們需要有一種將A`–B&C 結(jié)構(gòu)切換切換為A`–B`–C結(jié)構(gòu)的同步機(jī)制,psync雖然支持?jǐn)帱c(diǎn)續(xù)傳,但仍無法支持master故障的平滑切換。
實(shí)際上 我們已經(jīng)在我們定制的Redis計(jì)數(shù)服務(wù)上使用了如上功能的同步,效果非常好,解決了運(yùn)維負(fù)擔(dān),但仍需向所有Redis服務(wù)推廣,如果可能我們也會向官方Redis提出相關(guān)sync slave的改進(jìn)。
2.更適合redis的name-system Or proxy
細(xì)心的同學(xué)發(fā)現(xiàn)我們除了使用DNS作為命名系統(tǒng),也在zookeeper中有一份記錄,為什么不讓用戶直接訪問一個(gè)系統(tǒng),zk或者DNS選擇其一呢?
其實(shí)還是很簡單,命名系統(tǒng)是個(gè)非常重要的組件,而dns是一套比較完善的命名系統(tǒng),我們?yōu)榇俗隽撕芏喔倪M(jìn)和試錯(cuò),zk的實(shí)現(xiàn)還是相對復(fù)雜,我們還沒有較強(qiáng)的把控粒度。我們也在思考用什么做命名系統(tǒng)更符合我們需求。
3.后端數(shù)據(jù)存儲
大內(nèi)存的使用肯定是一個(gè)重要的成本優(yōu)化方向,flash盤及分布式的存儲也在我們未來計(jì)劃之中。
原文鏈接:http://www.xdata.me/?p=301
【編輯推薦】