用Codis實現Redis分散式叢集
一、Redis叢集概述
Redis官方近期推出的Redis Cluster,Redis叢集有三種實現機制,分別介紹如下,(1)客戶端分片,(2)代理分片,(3)Redis Cluster
1.1 客戶端分片
這種方案將分片工作放在業務程式端,程式程式碼根據預先設定的路由規則,直接對多個Redis例項進行分散式訪問。這樣的好處是,不依賴於第三方分散式中介軟體,實現方法和程式碼都自己掌控,可隨時調整,不用擔心踩到坑。
這實際上是一種靜態分片技術。Redis例項的增減,都得手工調整分片程式。基於此分片機制的開源產品,現在仍不多見。
這種分片機制的效能比代理式更好(少了一箇中間分發環節)。但缺點是升級麻煩,對研發人員的個人依賴性強——需要有較強的程式開發能力做後盾。如果主力程式設計師離職,可能新的負責人,會選擇重寫一遍。
所以,這種方式下,可運維性較差。出現故障,定位和解決都得研發和運維配合著解決,故障時間變長。
1.2 代理分片
這種方案,將分片工作交給專門的代理程式來做。代理程式接收到來自業務程式的資料請求,根據路由規則,將這些請求分發給正確的Redis例項並返回給業務程式。
這種機制下,一般會選用第三方代理程式(而不是自己研發),因為後端有多個Redis例項,所以這類程式又稱為分散式中介軟體。
這樣的好處是,業務程式不用關心後端Redis例項,運維起來也方便。雖然會因此帶來些效能損耗,但對於Redis這種記憶體讀寫型應用,相對而言是能容忍的。
這是我們推薦的叢集實現方案。像基於該機制的開源產品Twemproxy,便是其中代表之一,應用非常廣泛。
1.3 Redis Cluster
在這種機制下,沒有中心節點(和代理模式的重要不同之處)。所以,一切開心和不開心的事情,都將基於此而展開。
Redis
Cluster將所有Key對映到16384個Slot中,叢集中每個Redis例項負責一部分,業務程式通過整合的Redis
Cluster客戶端進行操作。客戶端可以向任一例項發出請求,如果所需資料不在該例項中,則該例項引導客戶端自動去對應例項讀寫資料。
Redis Cluster的成員管理(節點名稱、IP、埠、狀態、角色)等,都通過節點之間兩兩通訊,定期交換並更新。
由此可見,這是一種非常“重”的方案。已經不是Redis單例項的“簡單、可依賴”了。可能這也是延期多年之後,才近期釋出的原因之一。
這令人想起一段歷史。因為Memcache不支援持久化,所以有人寫了一個Membase,後來改名叫Couchbase,說是支援Auto Rebalance,好幾年了,至今都沒多少家公司在使用。
這是個令人 憂心忡忡 的方案。為解決仲裁等叢集管理的問題,Oracle RAC還會使用儲存裝置的一塊空間。而Redis Cluster,是一種完全的去中心化……
二、 Twemproxy代理
Twemproxy是一種代理分片機制,由Twitter開源。Twemproxy作為代理,可接受來自多個程式的訪問,按照路由規則,轉發給後臺的各個Redis伺服器,再原路返回。
這個方案 順理成章 地解決了單個Redis例項承載能力的問題。當然,Twemproxy本身也是單點,需要用Keepalived做高可用方案。
我想很多人都應該感謝Twemproxy,這麼些年來,應用範圍最廣、穩定性最高、最 久經考驗 的分散式中介軟體,應該就是它了。只是,他還有諸多不方便之處。
Twemproxy最大的痛點在於,無法平滑地擴容/縮容。
這樣導致運維同學非常痛苦:業務量突增,需增加Redis伺服器;業務量萎縮,需要減少Redis伺服器。但對Twemproxy而言,基本上都很難操作(那是一種錐心的、糾結的痛……)。
或者說,Twemproxy更加像伺服器端靜態sharding。有時為了規避業務量突增導致的擴容需求,甚至被迫新開一個基於Twemproxy的Redis叢集。
Twemproxy另一個痛點是,運維不友好,甚至沒有控制面板。
三、Codis
Codis由豌豆莢於2014年11月開源,基於Go和C開發,是近期湧現的、國人開發的優秀開源軟體之一。
https://github.com/CodisLabs/codis
一、概要
Codis 是一個分散式 Redis 解決方案, 對於上層的應用來說, 連線到 Codis Proxy 和連線原生的 Redis Server 沒有明顯的區別 (有一些命令不支援), 上層應用可以像使用單機的 Redis 一樣使用, Codis 底層會處理請求的轉發, 不停機的資料遷移等工作, 所有後邊的一切事情, 對於前面的客戶端來說是透明的, 可以簡單的認為後邊連線的是一個記憶體無限大的 Redis 服務,當然,前段時間redis官方的3.0出了穩定版,3.0支援叢集功能,codis的實現原理和3.0的叢集功能差不多。
二、架構

三、角色分批
zookeeper叢集:
10.10.0.47 10.10.0.48 10.10.1.76
codis-config、codis-ha:
10.10.32.10:18087
codis-proxy:
10.10.32.10:19000 10.10.32.49:19000
codis-server:
10.10.32.42:6379、10.10.32.43:6380(主、從) 10.10.32.43:6379、10.10.32.44:6380(主、從) 10.10.32.44:6379、10.10.32.42:6380(主、從)
四、部署
1、安裝zookeeper
1yum -y installzookeeper jdk ##安裝服務
vim /etc/hosts##新增host
10.10.0.47 ZooKeeper-node1
10.10.0.48 ZooKeeper-node2
10.10.1.76 ZooKeeper-node3
vim /etc/zookeeper/conf/zoo.cfg ##撰寫zk的配置檔案
maxClientCnxns=50
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/
clientPort=2181
server.1=ZooKeeper-node1:2888:3888
server.2=ZooKeeper-node2:2888:3888
server.3=ZooKeeper-node3:2888:3888
mkdir/data/zookeeper/##建立zk的datadir目錄
echo"2">/data/zookeeper/myid##生成ID,這裡需要注意, myid對應的zoo.cfg的server.ID,比如ZooKeeper-node2對應的myid應該是2
/usr/lib/zookeeper/bin/zkServer.sh start ## 服務啟動
2、go安裝(codis是go語言寫的,所以那些機器需要安裝你懂得)
wget https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gz
tar-zxvf go1.4.1.linux-amd64.tar.gz
mvgo /usr/local/
cd/usr/local/go/src/
bashall.bash
cat>> ~/.bashrc << _bashrc_export
exportGOROOT=/usr/local/go
exportPATH=\$PATH:\$GOROOT/bin
exportGOARCH=amd64
exportGOOS=linux
_bashrc_export
source~/.bashrc
3、下載並編譯codis(codis-config、codis-proxy、codis-server所在的機器)
mkdir/data/go
exportGOPATH=/data/go
/usr/local/go/bin/goget github.com/wandoulabs/codis
cd/data/go/src/github.com/wandoulabs/codis/
./bootstrap.sh
makegotest
五、服務啟動及初始化叢集
1、啟動 dashboard(codis-config上操作)
cat/etc/codis/config_10.ini ##撰寫配置檔案
zk=10.10.0.47:2181,10.10.0.48:2181,10.10.1.76:2181
product=zh_news
proxy_id=codis-proxy_10
net_timeout=5000
proto=tcp4
dashboard_addr=10.10.32.10:18087
1cd/data/go/src/github.com/wandoulabs/codis/&& ./bin/codis-config-c /etc/codis/config_10.ini dashboard &
2、初始化 slots (codis-config上操作)
1cd/data/go/src/github.com/wandoulabs/codis/&& ./bin/codis-config-c /etc/codis/config_10.ini slot init
3、啟動 Codis Redis , 和官方的Redis Server引數一樣(codis-server上操作)
1cd/data/go/src/github.com/wandoulabs/codis/&& ./bin/codis-server/etc/redis_6379.conf &
4、新增 Redis Server Group , 每一個 Server Group 作為一個 Redis 伺服器組存在, 只允許有一個 master, 可以有多個 slave, group id 僅支援大於等於1的整數(codis-config上操作)
cd/data/go/src/github.com/wandoulabs/codis/
./bin/codis-config-c /etc/codis/config_10.ini server add 1 10.10.32.42:6379 master
./bin/codis-config-c /etc/codis/config_10.ini server add 1 10.10.32.43:6380 slave
./bin/codis-config-c /etc/codis/config_10.ini server add 2 10.10.32.43:6379 master
./bin/codis-config-c /etc/codis/config_10.ini server add 2 10.10.32.44:6380 slave
./bin/codis-config-c /etc/codis/config_10.ini server add 3 10.10.32.44:6379 master
./bin/codis-config-c /etc/codis/config_10.ini server add 3 10.10.32.42:6380 slave
5、設定
server group 服務的 slot 範圍 Codis 採用 Pre-sharding 的技術來實現資料的分片, 預設分成 1024 個
slots (0-1023), 對於每個key來說, 通過以下公式確定所屬的 Slot Id : SlotId = crc32(key) %
1024 每一個 slot 都會有一個特定的 server group id 來表示這個 slot 的資料由哪個 server group
來提供.(codis-config上操作)
cd/data/go/src/github.com/wandoulabs/codis/
./bin/codis-config-c /etc/codis/config_10.ini slot range-set0 300 1 online
./bin/codis-config-c /etc/codis/config_10.ini slot range-set301 700 2 online
./bin/codis-config-c /etc/codis/config_10.ini slot range-set701 1023 3 online
6、啟動 codis-proxy (codis-proxy上操作
cat/etc/codis/config_10.ini ##撰寫配置檔案
zk=10.10.0.47:2181,10.10.0.48:2181,10.10.1.76:2181
product=zh_news
proxy_id=codis-proxy_10 ##10.10.32.49上改成codis-proxy_49,多個proxy,proxy_id 需要唯一
net_timeout=5000
proto=tcp4
dashboard_addr=10.10.32.10:18087
cd/data/go/src/github.com/wandoulabs/codis/&& ./bin/codis-proxy-c /etc/codis/config_10.ini -L /data/log/codis-proxy_10.log --cpu=4 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000 &
cd/data/go/src/github.com/wandoulabs/codis/&& ./bin/codis-proxy-c /etc/codis/config_49.ini -L /data/log/codis-proxy_49.log --cpu=4 --addr=0.0.0.0:19000 --http-addr=0.0.0.0:11000 &
OK,整個叢集已經搭建成功了,截圖給你們show show

六、codis-server的HA
codis-ha實現codis-server的主從切換,codis-server主庫掛了會提升一個從庫為主庫,從庫掛了會設定這個從庫從叢集下線
1、安裝
exportGOPATH=/data/go
/usr/local/go/bin/goget github.com/ngaut/codis-ha
cd/data/go/src/github.com/ngaut/codis-ha
go build
cpcodis-ha /data/go/src/github.com/wandoulabs/codis/bin/
使用方法:
codis-ha --codis-config=dashboard地址:18087 --productName=叢集專案名稱
2、使用supervisord管理codis-ha程序
1yum -y installsupervisord
/etc/supervisord.conf中新增如下內容:
[program:codis-ha]
autorestart = True
stopwaitsecs = 10
startsecs = 1
stopsignal = QUIT
command= /data/go/src/github.com/wandoulabs/codis/bin/codis-ha--codis-config=10.10.32.17:18087 --productName=zh_news
user = root
startretries = 3
autostart = True
exitcodes = 0,2
3、啟動supervisord服務
/etc/init.d/supervisordstart
chkconfig supervisord on
此時,ps -ef |grep codis-ha 你回發現codis-ha程序已經啟動,這個時候你去停掉一個codis-server的master,看看slave會不會提升為master呢
七、關於監控
關於整個codis叢集的監控,我們這邊用的是zabbix,監控的指標比較簡單,所以這塊大家有什麼好的建議多給我提提哈
zookeeper:監控各個節點的埠聯通性(以後想著把程序也監控上)
codis-proxy:監控了埠的聯通性,這個監控遠遠不夠呀
codis-server:監控了記憶體使用率、連線數、聯通性
codis-ha:監控程序
dashboard:監控埠聯通性
八、使用過程中遇到的問題
1、codis-proxy的日誌切割,codis-proxy的預設日誌級別是info,日誌量很大,我們這邊每天產生50多G日誌,目前codis-proxy還不支援熱重啟,想修改啟動引數還是比較麻煩的,日誌切割推薦用logrotate
2、codis-proxy的監聽地址預設沒有具體ipv4,也就是codis-proxy啟動之後沒有0.0.0.0:19000這樣的監聽,這樣會導致的問題就是前端lvs沒有辦法負載均衡codis-proxy,不能轉發請求過,這個問題已聯絡作者處理了,在codis-proxy啟動的配置檔案中加上proto=tcp4這個引數就支援監聽ipv4了
3、新增
Redis Server
Group的時候,非codis-server(原生的redis)竟然也能加入到codis叢集裡面,在redis和codis-server共存在一個物理機上的清楚,很容易加錯,希望能有個驗證,非codis-server不能加入到codis叢集
4、codis叢集內部通訊是通過主機名的,如果主機名沒有做域名解析那dashboard是通過主機名訪問不到proxy的http-addr地址的,這會導致從web介面上看不到 OP/s的資料,至於還有沒有其他問題,目前我這邊還沒有發現,建議內部通訊直接用內網IP