一. 應(yīng)用場(chǎng)景
redis 作為數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)引擎,有著很多優(yōu)點(diǎn)
- 高性能
單機(jī)引擎可以達(dá)到5-10W qps - 數(shù)據(jù)結(jié)構(gòu)全面,支持快速開發(fā)業(yè)務(wù)
string,list,set,sorted set, hashes
問題:
- 存儲(chǔ)容量受限單機(jī)最大容量即為單機(jī)內(nèi)存最大容量
- 單機(jī)數(shù)據(jù)的持久化依賴aof和rdb機(jī)制,如果機(jī)器整個(gè)down掉,服務(wù)不可用
二. redis集群選型
正是由于單機(jī)redis引擎有著這樣的問題,所以,基本每個(gè)互聯(lián)網(wǎng)公司都有自己的redis集群化方案。
- 在redis客戶端lib中實(shí)現(xiàn)數(shù)據(jù)的分片并主從部署redis實(shí)例
優(yōu)點(diǎn):簡(jiǎn)單,性能損耗小
缺點(diǎn):擴(kuò)容方案復(fù)雜 - 集群化候選方案
1、NetFlix對(duì)Dynamo的開源通用實(shí)現(xiàn)Dynomite
Dynomite是NetFlix對(duì)亞馬遜分布式存儲(chǔ)引擎Dynamo的一個(gè)開源通用實(shí)現(xiàn),使用C/C++語言編寫、以代理的方式實(shí)現(xiàn)的Redis緩存集群方案。Dynomite不僅能夠?qū)⒒趦?nèi)存的Redis和Memcached打造成分布式數(shù)據(jù)庫(kù),還支持持久化的MySQL、BerkeleyDB、LevelDB等數(shù)據(jù)庫(kù),并具有簡(jiǎn)單、高效、支持跨數(shù)據(jù)中心的數(shù)據(jù)復(fù)制等優(yōu)點(diǎn)。Dynomite的最終目標(biāo)是提供數(shù)據(jù)庫(kù)存儲(chǔ)引擎不能提供的簡(jiǎn)單、高效、跨數(shù)據(jù)中心的數(shù)據(jù)復(fù)制功能。Dynomite遵循Apache License 2.0開源協(xié)議發(fā)布,更多關(guān)于Dynomite的信息請(qǐng)查看NetFlix技術(shù)博客對(duì)Dynomite的介紹。
2、Twitter的Redis/Memcached代理服務(wù)Twemproxy
Twemproxy是一個(gè)使用C語言編寫、以代理的方式實(shí)現(xiàn)的、輕量級(jí)的Redis代理服務(wù)器,它通過引入一個(gè)代理層,將應(yīng)用程序后端的多臺(tái)Redis實(shí)例進(jìn)行統(tǒng)一管理,使應(yīng)用程序只需要在Twemproxy上進(jìn)行操作,而不用關(guān)心后面具體有多少個(gè)真實(shí)的Redis或Memcached實(shí)例,從而實(shí)現(xiàn)了基于Redis和Memcached的集群服務(wù)。當(dāng)某個(gè)節(jié)點(diǎn)宕掉時(shí),Twemproxy可以自動(dòng)將它從集群中剔除,而當(dāng)它恢復(fù)服務(wù)時(shí),Twemproxy也會(huì)自動(dòng)連接。由于是代理,所以Twemproxy會(huì)有微小的性能損失。根據(jù) Redis作者的測(cè)試結(jié)果,在大多數(shù)情況下,Twemproxy的性能相當(dāng)不錯(cuò),同直接操作Redis相比,最多只有20%的性能損失。Twemproxy遵循Apache License 2.0開源協(xié)議發(fā)布,更多關(guān)于Twemproxy的信息請(qǐng)登錄其在GitHub的主頁查看。
3、豌豆莢的 Redis 集群解決方案Codis
Codis是豌豆莢使用Go和C語言開發(fā)、以代理的方式實(shí)現(xiàn)的一個(gè)Redis分布式集群解決方案,且完全兼容Twemproxy。Twemproxy對(duì)于上一層的應(yīng)用來說, 連接Codis Proxy(Redis代理服務(wù))和連接原生的Redis服務(wù)器沒有明顯的區(qū)別,上一層應(yīng)用能夠像使用單機(jī)的 Redis一樣對(duì)待。Codis底層會(huì)處理請(qǐng)求的轉(zhuǎn)發(fā)、不停機(jī)的數(shù)據(jù)遷移等工作, 所有底層的一切處理, 對(duì)于客戶端來說是透明的??傊梢院?jiǎn)單的認(rèn)為后臺(tái)連接的是一個(gè)內(nèi)存無限大的Redis服務(wù)。Codis遵循MIT開源協(xié)議發(fā)布,更多關(guān)于Codis的信息請(qǐng)登錄其在GitHub的主頁查看。
另外,還有一些未開源的解決方案,比如新浪、百度、淘寶、騰訊等的Redis集群方案。在Redis官方正式推出可用于生產(chǎn)環(huán)境的集群方案前,以上三種方案是非常值得考慮在生產(chǎn)環(huán)境使用的方案。
三. 豌豆莢Codis
優(yōu)點(diǎn):
- codis-proxy基于GO和C語言,并發(fā)處理能力強(qiáng)勁
- 后端基于slot概念支持靈活,對(duì)用戶透明的擴(kuò)容和縮容操作,甚至一鍵式auto rebalance
- 基于zookeeper提供了高可用的codis-proxy代理服務(wù)
- 集群管理工具豐富:頁面和命令行工具集,如:redis-port可以將老集群(redis單機(jī)或twemproxy集群)中數(shù)據(jù)方便的遷移導(dǎo)入至Codis
整體架構(gòu)

Codis 由四部分組成:
- Codis Proxy (codis-proxy)
codis-proxy 是客戶端連接的 Redis 代理服務(wù), codis-proxy 本身實(shí)現(xiàn)了 Redis 協(xié)議, 表現(xiàn)得和一個(gè)原生的 Redis 沒什么區(qū)別 (就像 Twemproxy), 對(duì)于一個(gè)業(yè)務(wù)來說, 可以部署多個(gè) codis-proxy, codis-proxy 本身是無狀態(tài)的. - Codis Manager (codis-config)
codis-config 是 Codis 的管理工具, 支持包括, 添加/刪除 Redis 節(jié)點(diǎn), 添加/刪除 Proxy 節(jié)點(diǎn), 發(fā)起數(shù)據(jù)遷移等操作. codis-config 本身還自帶了一個(gè) http server, 會(huì)啟動(dòng)一個(gè) dashboard, 用戶可以直接在瀏覽器上觀察 Codis 集群的運(yùn)行狀態(tài). - Codis Redis (codis-server)
codis-server 是 Codis 項(xiàng)目維護(hù)的一個(gè) Redis 分支, 基于 2.8.13 開發(fā), 加入了 slot 的支持和原子的數(shù)據(jù)遷移指令. Codis 上層的 codis-proxy 和 codis-config 只能和這個(gè)版本的 Redis 交互才能正常運(yùn)行. - ZooKeeper
Codis 依賴 ZooKeeper 來存放數(shù)據(jù)路由表和 codis-proxy 節(jié)點(diǎn)的元信息, codis-config 發(fā)起的命令都會(huì)通過 ZooKeeper 同步到各個(gè)存活的 codis-proxy.
如果希望有更簡(jiǎn)單的訪問方式和更高的穩(wěn)定性:可以使用搭建HAProxy,但是會(huì)進(jìn)一步增加延遲。
安裝&管理集群
注意按照如下順序部署啟動(dòng)集群
- 啟動(dòng) dashboard *, 執(zhí)行 ../bin/codis-config dashboard, 該命令會(huì)啟動(dòng) dashboard *
- 初始化 slots , 執(zhí)行 ../bin/codis-config slot init,該命令會(huì)在zookeeper上創(chuàng)建slot相關(guān)信息
- 啟動(dòng) Codis Redis , 和官方的Redis Server參數(shù)一樣
- 添加 Redis Server Group , 每一個(gè) Server Group 作為一個(gè) Redis 服務(wù)器組存在, 只允許有一個(gè) master, 可以有多個(gè) slave, group id 僅支持大于等于1的整數(shù)
$ ../bin/codis-config server -h usage:
codis-config server list
codis-config server add <group_id> <redis_addr> <role>
codis-config server remove <group_id> <redis_addr>
codis-config server promote <group_id> <redis_addr>
codis-config server add-group <group_id>
codis-config server remove-group <group_id>
如: 添加兩個(gè) server group, 每個(gè) group 有兩個(gè) redis 實(shí)例,group的id分別為1和2, redis實(shí)例為一主一從。
添加一個(gè)group,group的id為1, 并添加一個(gè)redis master到該group
$ ../bin/codis-config server add 1 localhost:6379 master
添加一個(gè)redis slave到該group
$ ../bin/codis-config server add 1 localhost:6380 slave
類似的,再添加group,group的id為2
$ ../bin/codis-config server add 2 localhost:6479 master
$ ../bin/codis-config server add 2 localhost:6479 slave- 設(shè)置 server group 服務(wù)的 slot 范圍 Codis 采用 Pre-sharding 的技術(shù)來實(shí)現(xiàn)數(shù)據(jù)的分片, 默認(rèn)分成 1024 個(gè) slots (0-1023), 對(duì)于每個(gè)key來說, 通過以下公式確定所屬的 Slot Id : SlotId = crc32(key) % 1024 每一個(gè) slot 都會(huì)有一個(gè)特定的 server group id 來表示這個(gè) slot 的數(shù)據(jù)由哪個(gè) server group 來提供.
$ ../bin/codis-config slot -h
usage:
codis-config slot init
codis-config slot info <slot_id>
codis-config slot set <slot_id> <group_id> <status>
codis-config slot range-set <slot_from> <slot_to> <group_id> <status>
codis-config slot migrate <slot_from> <slot_to> <group_id> [--delay=<delay_time_in_ms>]
如:
設(shè)置編號(hào)為[0, 511]的 slot 由 server group 1 提供服務(wù), 編號(hào) [512, 1023] 的 slot 由 server group 2 提供服務(wù)
$ ../bin/codis-config slot range-set 0 511 1 online
$ ../bin/codis-config slot range-set 512 1023 2 online- 啟動(dòng) codis-proxy
../bin/codis-proxy -c config.ini -L ./log/proxy.log --cpu=8 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000
剛啟動(dòng)的 codis-proxy 默認(rèn)是處于 offline狀態(tài)的, 然后設(shè)置 proxy 為 online 狀態(tài), 只有處于 online 狀態(tài)的 proxy 才會(huì)對(duì)外提供服務(wù)
../bin/codis-config -c config.ini proxy online <proxy_name> <---- proxy的id, 如 proxy_1- 打開瀏覽器 http://localhost:18087/admin
現(xiàn)在可以在瀏覽器里面完成各種操作了, 玩得開心
性能
8 core Xeon 2.10GHz, 多線程的 benchmark, 單 proxy 的 ops 是 12w. 而且 proxy 是可以動(dòng)態(tài)水平擴(kuò)展的, 理論上的性能瓶頸應(yīng)該是百萬級(jí)別的