一、Redis集群概述
Redis官方近期推出的Redis Cluster,Redis集群有三種實(shí)現(xiàn)機(jī)制,分別介紹如下,(1)客戶端分片,(2)代理分片,(3)Redis Cluster
這種方案將分片工作放在業(yè)務(wù)程序端,程序代碼根據(jù)預(yù)先設(shè)置的路由規(guī)則,直接對(duì)多個(gè)Redis實(shí)例進(jìn)行分布式訪問(wèn)。這樣的好處是,不依賴于第三方分布式中間件,實(shí)現(xiàn)方法和代碼都自己掌控,可隨時(shí)調(diào)整,不用擔(dān)心踩到坑。
這實(shí)際上是一種靜態(tài)分片技術(shù)。Redis實(shí)例的增減,都得手工調(diào)整分片程序。基于此分片機(jī)制的開(kāi)源產(chǎn)品,現(xiàn)在仍不多見(jiàn)。
這種分片機(jī)制的性能比代理式更好(少了一個(gè)中間分發(fā)環(huán)節(jié))。但缺點(diǎn)是升級(jí)麻煩,對(duì)研發(fā)人員的個(gè)人依賴性強(qiáng)——需要有較強(qiáng)的程序開(kāi)發(fā)能力做后盾。如果主力程序員離職,可能新的負(fù)責(zé)人,會(huì)選擇重寫一遍。
所以,這種方式下,可運(yùn)維性較差。出現(xiàn)故障,定位和解決都得研發(fā)和運(yùn)維配合著解決,故障時(shí)間變長(zhǎng)。
這種方案,將分片工作交給專門的代理程序來(lái)做。代理程序接收到來(lái)自業(yè)務(wù)程序的數(shù)據(jù)請(qǐng)求,根據(jù)路由規(guī)則,將這些請(qǐng)求分發(fā)給正確的Redis實(shí)例并返回給業(yè)務(wù)程序。
這種機(jī)制下,一般會(huì)選用第三方代理程序(而不是自己研發(fā)),因?yàn)楹蠖擞卸鄠€(gè)Redis實(shí)例,所以這類程序又稱為分布式中間件。
這樣的好處是,業(yè)務(wù)程序不用關(guān)心后端Redis實(shí)例,運(yùn)維起來(lái)也方便。雖然會(huì)因此帶來(lái)些性能損耗,但對(duì)于Redis這種內(nèi)存讀寫型應(yīng)用,相對(duì)而言是能容忍的。
這是我們推薦的集群實(shí)現(xiàn)方案。像基于該機(jī)制的開(kāi)源產(chǎn)品Twemproxy,便是其中代表之一,應(yīng)用非常廣泛。
在這種機(jī)制下,沒(méi)有中心節(jié)點(diǎn)(和代理模式的重要不同之處)。所以,一切開(kāi)心和不開(kāi)心的事情,都將基于此而展開(kāi)。
Redis
Cluster將所有Key映射到16384個(gè)Slot中,集群中每個(gè)Redis實(shí)例負(fù)責(zé)一部分,業(yè)務(wù)程序通過(guò)集成的Redis
Cluster客戶端進(jìn)行操作??蛻舳丝梢韵蛉我粚?shí)例發(fā)出請(qǐng)求,如果所需數(shù)據(jù)不在該實(shí)例中,則該實(shí)例引導(dǎo)客戶端自動(dòng)去對(duì)應(yīng)實(shí)例讀寫數(shù)據(jù)。
Redis Cluster的成員管理(節(jié)點(diǎn)名稱、IP、端口、狀態(tài)、角色)等,都通過(guò)節(jié)點(diǎn)之間兩兩通訊,定期交換并更新。
由此可見(jiàn),這是一種非?!爸亍钡姆桨浮R呀?jīng)不是Redis單實(shí)例的“簡(jiǎn)單、可依賴”了??赡苓@也是延期多年之后,才近期發(fā)布的原因之一。
這令人想起一段歷史。因?yàn)镸emcache不支持持久化,所以有人寫了一個(gè)Membase,后來(lái)改名叫Couchbase,說(shuō)是支持Auto Rebalance,好幾年了,至今都沒(méi)多少家公司在使用。
這是個(gè)令人憂心忡忡的方案。為解決仲裁等集群管理的問(wèn)題,Oracle RAC還會(huì)使用存儲(chǔ)設(shè)備的一塊空間。而Redis Cluster,是一種完全的去中心化……
Twemproxy是一種代理分片機(jī)制,由Twitter開(kāi)源。Twemproxy作為代理,可接受來(lái)自多個(gè)程序的訪問(wèn),按照路由規(guī)則,轉(zhuǎn)發(fā)給后臺(tái)的各個(gè)Redis服務(wù)器,再原路返回。
這個(gè)方案順理成章地解決了單個(gè)Redis實(shí)例承載能力的問(wèn)題。當(dāng)然,Twemproxy本身也是單點(diǎn),需要用Keepalived做高可用方案。
我想很多人都應(yīng)該感謝Twemproxy,這么些年來(lái),應(yīng)用范圍最廣、穩(wěn)定性最高、最久經(jīng)考驗(yàn)的分布式中間件,應(yīng)該就是它了。只是,他還有諸多不方便之處。
Twemproxy最大的痛點(diǎn)在于,無(wú)法平滑地?cái)U(kuò)容/縮容。
這樣導(dǎo)致運(yùn)維同學(xué)非常痛苦:業(yè)務(wù)量突增,需增加Redis服務(wù)器;業(yè)務(wù)量萎縮,需要減少Redis服務(wù)器。但對(duì)Twemproxy而言,基本上都很難操作(那是一種錐心的、糾結(jié)的痛……)。
或者說(shuō),Twemproxy更加像服務(wù)器端靜態(tài)sharding。有時(shí)為了規(guī)避業(yè)務(wù)量突增導(dǎo)致的擴(kuò)容需求,甚至被迫新開(kāi)一個(gè)基于Twemproxy的Redis集群。
Twemproxy另一個(gè)痛點(diǎn)是,運(yùn)維不友好,甚至沒(méi)有控制面板。
Codis由豌豆莢于2014年11月開(kāi)源,基于Go和C開(kāi)發(fā),是近期涌現(xiàn)的、國(guó)人開(kāi)發(fā)的優(yōu)秀開(kāi)源軟件之一。
https://github.com/CodisLabs/codis
一、概要
Codis 是一個(gè)分布式Redis解決方案, 對(duì)于上層的應(yīng)用來(lái)說(shuō), 連接到 Codis Proxy 和連接原生的 Redis Server 沒(méi)有明顯的區(qū)別 (有一些命令不支持), 上層應(yīng)用可以像使用單機(jī)的 Redis 一樣使用, Codis 底層會(huì)處理請(qǐng)求的轉(zhuǎn)發(fā), 不停機(jī)的數(shù)據(jù)遷移等工作, 所有后邊的一切事情, 對(duì)于前面的客戶端來(lái)說(shuō)是透明的, 可以簡(jiǎn)單的認(rèn)為后邊連接的是一個(gè)內(nèi)存無(wú)限大的 Redis?服務(wù),當(dāng)然,前段時(shí)間redis官方的3.0出了穩(wěn)定版,3.0支持集群功能,codis的實(shí)現(xiàn)原理和3.0的集群功能差不多。
二、架構(gòu)

三、角色分批
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??##安裝服務(wù)
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/##創(chuàng)建zk的datadir目錄
echo"2">/data/zookeeper/myid##生成ID,這里需要注意,?myid對(duì)應(yīng)的zoo.cfg的server.ID,比如ZooKeeper-node2對(duì)應(yīng)的myid應(yīng)該是2
/usr/lib/zookeeper/bin/zkServer.sh?start??##?服務(wù)啟動(dòng)
2、go安裝(codis是go語(yǔ)言寫的,所以那些機(jī)器需要安裝你懂得)
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所在的機(jī)器)
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
五、服務(wù)啟動(dòng)及初始化集群
1、啟動(dòng) 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、啟動(dòng) Codis Redis , 和官方的Redis Server參數(shù)一樣(codis-server上操作)
1cd/data/go/src/github.com/wandoulabs/codis/&&?./bin/codis-server/etc/redis_6379.conf?&
4、添加 Redis Server Group , 每一個(gè) Server Group 作為一個(gè) Redis 服務(wù)器組存在, 只允許有一個(gè) master, 可以有多個(gè) slave, group id 僅支持大于等于1的整數(shù)(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、設(shè)置
server group 服務(wù)的 slot 范圍 Codis 采用 Pre-sharding 的技術(shù)來(lái)實(shí)現(xiàn)數(shù)據(jù)的分片, 默認(rèn)分成 1024 個(gè)
slots (0-1023), 對(duì)于每個(gè)key來(lái)說(shuō), 通過(guò)以下公式確定所屬的 Slot Id : SlotId = crc32(key) %
1024 每一個(gè) slot 都會(huì)有一個(gè)特定的 server group id 來(lái)表示這個(gè) slot 的數(shù)據(jù)由哪個(gè) server group
來(lái)提供.(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、啟動(dòng) 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,多個(gè)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,整個(gè)集群已經(jīng)搭建成功了,截圖給你們show show

六、codis-server的HA
codis-ha實(shí)現(xiàn)codis-server的主從切換,codis-server主庫(kù)掛了會(huì)提升一個(gè)從庫(kù)為主庫(kù),從庫(kù)掛了會(huì)設(shè)置這個(gè)從庫(kù)從集群下線
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=集群項(xiàng)目名稱
2、使用supervisord管理codis-ha進(jìn)程
1yum?-y?installsupervisord
/etc/supervisord.conf中添加如下內(nèi)容:
[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、啟動(dòng)supervisord服務(wù)
/etc/init.d/supervisordstart
chkconfig?supervisord??on
此時(shí),ps -ef |grep codis-ha 你回發(fā)現(xiàn)codis-ha進(jìn)程已經(jīng)啟動(dòng),這個(gè)時(shí)候你去停掉一個(gè)codis-server的master,看看slave會(huì)不會(huì)提升為master呢
七、關(guān)于監(jiān)控
關(guān)于整個(gè)codis集群的監(jiān)控,我們這邊用的是zabbix,監(jiān)控的指標(biāo)比較簡(jiǎn)單,所以這塊大家有什么好的建議多給我提提哈
zookeeper:監(jiān)控各個(gè)節(jié)點(diǎn)的端口聯(lián)通性(以后想著把進(jìn)程也監(jiān)控上)
codis-proxy:監(jiān)控了端口的聯(lián)通性,這個(gè)監(jiān)控遠(yuǎn)遠(yuǎn)不夠呀
codis-server:監(jiān)控了內(nèi)存使用率、連接數(shù)、聯(lián)通性
codis-ha:監(jiān)控進(jìn)程
dashboard:監(jiān)控端口聯(lián)通性
八、使用過(guò)程中遇到的問(wèn)題
1、codis-proxy的日志切割,codis-proxy的默認(rèn)日志級(jí)別是info,日志量很大,我們這邊每天產(chǎn)生50多G日志,目前codis-proxy還不支持熱重啟,想修改啟動(dòng)參數(shù)還是比較麻煩的,日志切割推薦用logrotate
2、codis-proxy的監(jiān)聽(tīng)地址默認(rèn)沒(méi)有具體ipv4,也就是codis-proxy啟動(dòng)之后沒(méi)有0.0.0.0:19000這樣的監(jiān)聽(tīng),這樣會(huì)導(dǎo)致的問(wèn)題就是前端lvs沒(méi)有辦法負(fù)載均衡codis-proxy,不能轉(zhuǎn)發(fā)請(qǐng)求過(guò),這個(gè)問(wèn)題已聯(lián)系作者處理了,在codis-proxy啟動(dòng)的配置文件中加上proto=tcp4這個(gè)參數(shù)就支持監(jiān)聽(tīng)ipv4了
3、添加
Redis Server
Group的時(shí)候,非codis-server(原生的redis)竟然也能加入到codis集群里面,在redis和codis-server共存在一個(gè)物理機(jī)上的清楚,很容易加錯(cuò),希望能有個(gè)驗(yàn)證,非codis-server不能加入到codis集群
4、codis集群內(nèi)部通訊是通過(guò)主機(jī)名的,如果主機(jī)名沒(méi)有做域名解析那dashboard是通過(guò)主機(jī)名訪問(wèn)不到proxy的http-addr地址的,這會(huì)導(dǎo)致從web界面上看不到?OP/s的數(shù)據(jù),至于還有沒(méi)有其他問(wèn)題,目前我這邊還沒(méi)有發(fā)現(xiàn),建議內(nèi)部通訊直接用內(nèi)網(wǎng)IP