引言:
如今redis憑借其高性能的優(yōu)勢, 以及豐富的數(shù)據(jù)結(jié)構(gòu)作為cache已越來越流行, 逐步取代了memcached等cache產(chǎn)品, 在Twitter,新浪微博中廣泛使用,阿里巴巴同樣如此. redis已經(jīng)占據(jù)了其不可動搖的地位, 然而在實際的生產(chǎn)環(huán)境中, redis也暴露出一些其他問題.如性能瓶頸, 內(nèi)存冗余, 運維部署復(fù)雜等. 本文目的就是分析redis現(xiàn)有的問題, 以及介紹阿里巴巴技術(shù)保障團(tuán)隊對redis的改造工作, 使其在生產(chǎn)環(huán)境中發(fā)揮更大的價值.
原生redis的瓶頸:
1. 單進(jìn)程單線程, 無法充分發(fā)揮服務(wù)器多核cpu的性能.
2. 大流量下造成IO阻塞. 同樣是由于單進(jìn)程單線程, cpu在處理業(yè)務(wù)邏輯的時候,網(wǎng)絡(luò)IO被阻塞住, 造成無法處理更多的請求.
3. 維護(hù)成本高, 如果想要充分發(fā)揮服務(wù)器的所有資源包括cpu, 網(wǎng)絡(luò)io等, 就必須建立多個instance, 但此時不可避免會增加維護(hù)成本. 拿24核服務(wù)器舉例來講, 如果部署24個單機(jī)版的instance,理論上可以實現(xiàn)10w*24core= 240wQPS的總體性能.但是每個 instance 有各自獨立的數(shù)據(jù),占用資源如內(nèi)存也會同比上升,反過來制約一臺服務(wù)器又未必能支持這么多的 instance. 如果部署24個Instance來構(gòu)成單機(jī)集群, 雖然可以共享數(shù)據(jù),但是因為節(jié)點增加, redis的狀態(tài)通訊更加頻繁和費時,性能也下會降很多. 并且兩種方式都意味著要維護(hù)24個Instance,運維成本都會成倍增加.
4. 持久化. redis提供了兩種save方式 1)save觸發(fā). 2)bgsave. 當(dāng)然也可以使用3)aof來實現(xiàn)持久化, 但是這3點都有弊端.
1)save: 由于是單進(jìn)程單線程, redis會阻塞住所有請求, 來遍歷所有redisDB, 把key-val寫入dump.rdb. 如果內(nèi)存數(shù)據(jù)量過大, 會造成短時間幾秒到幾十秒甚至更長的時間停止服務(wù), 這種方案對于twitter, taobao等大流量的網(wǎng)站, 顯然是不可取的.
2)bgsave: 在觸發(fā)bgsave時, redis會fork自身, child進(jìn)程會進(jìn)入1)的處理方式,這意味著服務(wù)器內(nèi)存要有一半的冗余才可以, 如今內(nèi)存已變得越來越廉價, 但是對于存儲海量數(shù)據(jù)的情況,內(nèi)存以及服務(wù)器的成本還是不容忽視的.
3)aof: 說到持久化, redis提供的aof算是最完美的方案了, 但是有得必有失, 嚴(yán)重影響性能! 因為redis每接收到一條請求, 就要把命令內(nèi)容完整的寫到磁盤文件, 且不說頻繁讀寫會影響磁盤壽命,寫磁盤的時間足以拖垮redis整體性能 . 當(dāng)然熟悉redis的開發(fā)者會想到用appendfsync等參數(shù)來調(diào)整, 但都不是完美.即使使用 SSD,性能也只是略有提升,并且性價比不高。
針對以上幾種情況, 阿里技術(shù)保障團(tuán)隊做了如下優(yōu)化手段, 其實這不僅僅只是優(yōu)化, 而更是一種對redis的改造.
1. 多線程master + N*work 工作模式.master線程負(fù)責(zé)監(jiān)聽網(wǎng)絡(luò)事件, 在接收到一個新的連接后, master會把新的fd注冊到worker的epoll事件中, 交由worker處理這個fd的所有讀寫事件, 這樣master線程就可以完全被釋放出來接收更多的連接, 同時又不妨礙worker處理業(yè)務(wù)邏輯和IO讀寫.
采用這種master + N*worker的網(wǎng)絡(luò)層事件模型,可以實現(xiàn)redis性能的平行擴(kuò)展. 真正的讓redis在面臨高并發(fā)請求時可以叢容面對.
2. 拋棄save, bgsave, aof等三種模式.采用redisDB lock模式. AliRedis在數(shù)據(jù)存儲層把多DB存儲模式轉(zhuǎn)換成HashDb存儲, 將key hash到所有RedisDB上, 這樣做有一個弊端就是拋棄了select命令, 但與此同時會帶來一個更大的好處, 可以逐個DB持久化而不會影響整個系統(tǒng), 在做持久化的時候AliRedis只需lock住1/N個redisDb, 占用1/m個線程. 在不需要內(nèi)存冗余的情況下進(jìn)行持久化, 相比之前提到的弊端, 這種方式可以帶來更大的收益, 更豐厚的回報.
3. 重構(gòu)hiredis客戶端, 支持redis-cluster工作模式, 目前hiredis并不支持redis-cluster模式, 阿里技術(shù)保障團(tuán)隊對hiredis進(jìn)行重構(gòu),使之支持redis-cluster.
4. 優(yōu)化jemalloc, 采用大內(nèi)存頁. Redis在使用內(nèi)存方面可謂苛刻至極, 壓縮, string轉(zhuǎn)number等, 能省就省, 但是在實際生產(chǎn)環(huán)境中, 為了追求性能, 對于內(nèi)存的使用可以適度(不至于如bgsave般浪費)通融處理, 因此AliRedis對jemalloc做了微調(diào), 通過調(diào)整pagesize來讓一次je_malloc分配更多run空間來儲備更多的用戶態(tài)可用內(nèi)存, 同時可以減輕換頁表的負(fù)載, 降低user sys的切換頻率, 來提高申請內(nèi)存的性能, 對jemalloc有興趣的開發(fā)者可以參考jemalloc源碼中的bin, run, chunk數(shù)據(jù)結(jié)構(gòu)進(jìn)行分析.
通過如上改造 , redis 可以充分發(fā)揮服務(wù)器多核的優(yōu)勢 , 以及網(wǎng)絡(luò) IO 復(fù)用 , 特別是節(jié)省運維成本 , 每臺服務(wù)器只需維護(hù)一個 AliRedis 實例 .
測試環(huán)境
CPU: Intel Xeon E5-2630 2.3GHz, *2
KERNEL: 3.2.0
GCC: 4.4.6
Jemalloc: 3.2.0
NIC: Intel 82599EB
測試數(shù)據(jù)
AliRedis單機(jī)版性能數(shù)據(jù)
thread: 1 2 4 8 12 16 20 24
set/get=1:1 83182 162214 301552 605817 876656 1173748 1551113 1800878
AliRedis集群
8個節(jié)點, 20臺客戶端, 配置相同, cpu全部打滿.
set/get=1:1 qps: 10,344,877
結(jié)論
單機(jī)版AliRedis可以實現(xiàn)24核跑滿180wQPS性能.
集群版可以實現(xiàn)8臺服務(wù)器支撐1000wQPS的數(shù)據(jù)請求.
阿里巴巴技術(shù)保障團(tuán)隊肩負(fù)著支撐阿里技術(shù), 保障系統(tǒng)穩(wěn)定運行的艱巨使命.不管是雙11, 還是雙12, 或者其他大促活動, 每個阿里人都在努力且拼命的工作, 拿自己的勞動來捍衛(wèi)著阿里集團(tuán)的榮譽.
阿里技術(shù)-保障奇跡.
阿里技術(shù)保障部-系統(tǒng)運營-網(wǎng)絡(luò)部-子逍
來自:http://blog.sina.com.cn/s/blog_e59371cc0101br74.html