最近研究redis-cluster,正好搭建了一個環境,遇到了不少坑,系統的總結下,等到redis3 release出來後,換掉memCache 集羣. 轉載請註明出處哈:http://hot66hot.iteye.com/admin/blogs/2050676 一:關於redis cluster
1:redis cluster的現狀
reids-cluster計劃在redis3.0中推出,能夠看做者antirez的聲明:http://antirez.com/news/49 (ps:跳票了很久,今年貌似加快速度了),目前的最新版本見:https://raw.githubusercontent.com/antirez/redis/3.0/00-RELEASENOTESnode
做者的目標:Redis Cluster will support up to ~1000 nodes. 贊...git
目前redis支持的cluster特性(已測試):github
1):節點自動發現redis
2):slave->master 選舉,集羣容錯shell
3):Hot resharding:在線分片api
4):集羣管理:cluster xxxruby
5):基於配置(nodes-port.conf)的集羣管理架構
6):ASK 轉向/MOVED 轉向機制.app
2:redis cluster 架構
1)redis-cluster架構圖
![](http://static.javashuo.com/static/loading.gif)
架構細節:運維
(1)全部的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.
(2)節點的fail是經過集羣中超過半數的節點檢測失效時才生效.
(3)客戶端與redis節點直連,不須要中間proxy層.客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可
(4)redis-cluster把全部的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value
2) redis-cluster選舉:容錯
![](http://static.javashuo.com/static/loading.gif)
(1)領着選舉過程是集羣中全部master參與,若是半數以上master節點與master節點通訊超過(cluster-node-timeout),認爲當前master節點掛掉.
(2):何時整個集羣不可用(cluster_state:fail)?
a:若是集羣任意master掛掉,且當前master沒有slave.集羣進入fail狀態,也能夠理解成集羣的slot映射[0-16383]不完成時進入fail狀態. ps : redis-3.0.0.rc1加入cluster-require-full-coverage參數,默認關閉,打開集羣兼容部分失敗.
b:若是集羣超過半數以上master掛掉,不管是否有slave集羣進入fail狀態.
ps:當集羣不可用時,全部對集羣的操做作都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤
二:redis cluster的使用
1:安裝redis cluster
1):安裝redis-cluster依賴:redis-cluster的依賴庫在使用時有兼容問題,在reshard時會遇到各類錯誤,請按指定版本安裝.
(1)確保系統安裝zlib,不然gem install會報(no such file to load -- zlib)
Java代碼
- #download:zlib-1.2.6.tar
- ./configure
- make
- make install
(2)安裝ruby:version(1.9.2)
Java代碼
- # ruby1.9.2
- cd /path/ruby
- ./configure -prefix=/usr/local/ruby
- make
- make install
- sudo cp ruby /usr/local/bin
(3)安裝rubygem:version(1.8.16)
Java代碼
- # rubygems-1.8.16.tgz
- cd /path/gem
- sudo ruby setup.rb
- sudo cp bin/gem /usr/local/bin
(4)安裝gem-redis:version(3.0.0)
Java代碼
- gem install redis --version 3.0.0
- #因爲源的緣由,可能下載失敗,就手動下載下來安裝
- #download地址:http://rubygems.org/gems/redis/versions/3.0.0
- gem install -l /data/soft/redis-3.0.0.gem
(5)安裝redis-cluster
Java代碼
- cd /path/redis
- make
- sudo cp /opt/redis/src/redis-server /usr/local/bin
- sudo cp /opt/redis/src/redis-cli /usr/local/bin
- sudo cp /opt/redis/src/redis-trib.rb /usr/local/bin
2:配置redis cluster
1)redis配置文件結構:
![](http://static.javashuo.com/static/loading.gif)
使用包含(include)把通用配置和特殊配置分離,方便維護.
2)redis通用配置.
Java代碼
- #GENERAL
- daemonize no
- tcp-backlog 511
- timeout 0
- tcp-keepalive 0
- loglevel notice
- databases 16
- dir /opt/redis/data
- slave-serve-stale-data yes
- #slave只讀
- slave-read-only yes
- #not use default
- repl-disable-tcp-nodelay yes
- slave-priority 100
- #打開aof持久化
- appendonly yes
- #每秒一次aof寫
- appendfsync everysec
- #關閉在aof rewrite的時候對新的寫操做進行fsync
- no-appendfsync-on-rewrite yes
- auto-aof-rewrite-min-size 64mb
- lua-time-limit 5000
- #打開redis集羣
- cluster-enabled yes
- #節點互連超時的閥值
- cluster-node-timeout 15000
- cluster-migration-barrier 1
- slowlog-log-slower-than 10000
- slowlog-max-len 128
- notify-keyspace-events ""
- hash-max-ziplist-entries 512
- hash-max-ziplist-value 64
- list-max-ziplist-entries 512
- list-max-ziplist-value 64
- set-max-intset-entries 512
- zset-max-ziplist-entries 128
- zset-max-ziplist-value 64
- activerehashing yes
- client-output-buffer-limit normal 0 0 0
- client-output-buffer-limit slave 256mb 64mb 60
- client-output-buffer-limit pubsub 32mb 8mb 60
- hz 10
- aof-rewrite-incremental-fsync yes
3)redis特殊配置.
Java代碼
- #包含通用配置
- include /opt/redis/redis-common.conf
- #監聽tcp端口
- port 6379
- #最大可用內存
- maxmemory 100m
- #內存耗盡時採用的淘汰策略:
- # volatile-lru -> remove the key with an expire set using an LRU algorithm
- # allkeys-lru -> remove any key accordingly to the LRU algorithm
- # volatile-random -> remove a random key with an expire set
- # allkeys-random -> remove a random key, any key
- # volatile-ttl -> remove the key with the nearest expire time (minor TTL)
- # noeviction -> don't expire at all, just return an error on write operations
- maxmemory-policy allkeys-lru
- #aof存儲文件
- appendfilename "appendonly-6379.aof"
- #不開啓rdb存儲,只用於添加slave過程
- dbfilename dump-6379.rdb
- #cluster配置文件(啓動自動生成)
- cluster-config-file nodes-6379.conf
- #部署在同一機器的redis實例,把auto-aof-rewrite搓開,由於cluster環境下內存佔用基本一致.
- #防止贊成機器下瞬間fork全部redis進程作aof rewrite,佔用大量內存(ps:cluster必須開啓aof)
- auto-aof-rewrite-percentage 80-100
3:cluster 操做
cluster集羣相關命令,更多redis相關命令見文檔:http://redis.readthedocs.org/en/latest/
Java代碼
- 集羣
- CLUSTER INFO 打印集羣的信息
- CLUSTER NODES 列出集羣當前已知的全部節點(node),以及這些節點的相關信息。
- 節點
- CLUSTER MEET <ip> <port> 將 ip 和 port 所指定的節點添加到集羣當中,讓它成爲集羣的一份子。
- CLUSTER FORGET <node_id> 從集羣中移除 node_id 指定的節點。
- CLUSTER REPLICATE <node_id> 將當前節點設置爲 node_id 指定的節點的從節點。
- CLUSTER SAVECONFIG 將節點的配置文件保存到硬盤裏面。
- 槽(slot)
- CLUSTER ADDSLOTS <slot> [slot ...] 將一個或多個槽(slot)指派(assign)給當前節點。
- CLUSTER DELSLOTS <slot> [slot ...] 移除一個或多個槽對當前節點的指派。
- CLUSTER FLUSHSLOTS 移除指派給當前節點的全部槽,讓當前節點變成一個沒有指派任何槽的節點。
- CLUSTER SETSLOT <slot> NODE <node_id> 將槽 slot 指派給 node_id 指定的節點,若是槽已經指派給另外一個節點,那麼先讓另外一個節點刪除該槽>,而後再進行指派。
- CLUSTER SETSLOT <slot> MIGRATING <node_id> 將本節點的槽 slot 遷移到 node_id 指定的節點中。
- CLUSTER SETSLOT <slot> IMPORTING <node_id> 從 node_id 指定的節點中導入槽 slot 到本節點。
- CLUSTER SETSLOT <slot> STABLE 取消對槽 slot 的導入(import)或者遷移(migrate)。
- 鍵
- CLUSTER KEYSLOT <key> 計算鍵 key 應該被放置在哪一個槽上。
- CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的鍵值對數量。
- CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 個 slot 槽中的鍵。
4:redis cluster 運維操做
1)初始化並構建集羣
(1)啓動集羣相關節點(必須是空節點,beta3後能夠是有數據的節點),指定配置文件和輸出日誌
Java代碼
- redis-server /opt/redis/conf/redis-6380.conf > /opt/redis/logs/redis-6380.log 2>&1 &
- redis-server /opt/redis/conf/redis-6381.conf > /opt/redis/logs/redis-6381.log 2>&1 &
- redis-server /opt/redis/conf/redis-6382.conf > /opt/redis/logs/redis-6382.log 2>&1 &
- redis-server /opt/redis/conf/redis-7380.conf > /opt/redis/logs/redis-7380.log 2>&1 &
- redis-server /opt/redis/conf/redis-7381.conf > /opt/redis/logs/redis-7381.log 2>&1 &
- redis-server /opt/redis/conf/redis-7382.conf > /opt/redis/logs/redis-7382.log 2>&1 &
(2):使用自帶的ruby工具(redis-trib.rb)構建集羣
Java代碼
- #redis-trib.rb的create子命令構建
- #--replicas 則指定了爲Redis Cluster中的每一個Master節點配備幾個Slave節點
- #節點角色由順序決定,先master以後是slave(爲方便辨認,slave的端口比master大1000)
- redis-trib.rb create --replicas 1 10.10.34.14:6380 10.10.34.14:6381 10.10.34.14:6382 10.10.34.14:7380 10.10.34.14:7381 10.10.34.14:7382
(3):檢查集羣狀態
Java代碼
- #redis-trib.rb的check子命令構建
- #ip:port能夠是集羣的任意節點
- redis-trib.rb check 10.10.34.14:6380
最後輸出以下信息,沒有任何警告或錯誤,表示集羣啓動成功並處於ok狀態
Java代碼
- [OK] All nodes agree about slots configuration.
- >>> Check for open slots...
- >>> Check slots coverage...
- [OK] All 16384 slots covered.
2):添加新master節點
(1)添加一個master節點:建立一個空節點(empty node),而後將某些slot移動到這個空節點上,這個過程目前須要人工干預
a):根據端口生成配置文件(ps:establish_config.sh是我本身寫的輸出配置腳本)
Java代碼
- sh establish_config.sh 6386 > conf/redis-6386.conf
b):啓動節點
Java代碼
- redis-server /opt/redis/conf/redis-6386.conf > /opt/redis/logs/redis-6386.log 2>&1 &
c):加入空節點到集羣
add-node 將一個節點添加到集羣裏面, 第一個是新節點ip:port, 第二個是任意一個已存在節點ip:port
Java代碼
- redis-trib.rb add-node 10.10.34.14:6386 10.10.34.14:6381
node:新節點沒有包含任何數據, 由於它沒有包含任何slot。新加入的加點是一個主節點, 當集羣須要將某個從節點升級爲新的主節點時, 這個新節點不會被選中
d):爲新節點分配slot
Java代碼
- redis-trib.rb reshard 10.10.34.14:6386
- #根據提示選擇要遷移的slot數量(ps:這裏選擇500)
- How many slots do you want to move (from 1 to 16384)? 500
- #選擇要接受這些slot的node-id
- What is the receiving node ID? f51e26b5d5ff74f85341f06f28f125b7254e61bf
- #選擇slot來源:
- #all表示從全部的master從新分配,
- #或者數據要提取slot的master節點id,最後用done結束
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:all
- #打印被移動的slot後,輸入yes開始移動slot以及對應的數據.
- #Do you want to proceed with the proposed reshard plan (yes/no)? yes
- #結束
3):添加新的slave節點
a):前三步操做同添加master同樣
b)第四步:redis-cli鏈接上新節點shell,輸入命令:cluster replicate 對應master的node-id
Java代碼
- cluster replicate 2b9ebcbd627ff0fd7a7bbcc5332fb09e72788835
note:在線添加slave 時,須要dump整個master進程,並傳遞到slave,再由 slave加載rdb文件到內存,rdb傳輸過程當中Master可能沒法提供服務,整個過程消耗大量io,當心操做.
例如本次添加slave操做產生的rdb文件
Java代碼
- -rw-r--r-- 1 root root 34946 Apr 17 18:23 dump-6386.rdb
- -rw-r--r-- 1 root root 34946 Apr 17 18:23 dump-7386.rdb
4):在線reshard 數據:
對於負載/數據不均勻的狀況,能夠在線reshard slot來解決,方法與添加新master的reshard同樣,只是須要reshard的master節點是老節點.
5):刪除一個slave節點
Java代碼
- #redis-trib del-node ip:port '<node-id>'
- redis-trib.rb del-node 10.10.34.14:7386 'c7ee2fca17cb79fe3c9822ced1d4f6c5e169e378'
6):刪除一個master節點
a):刪除master節點以前首先要使用reshard移除master的所有slot,而後再刪除當前節點(目前只能把被刪除
master的slot遷移到一個節點上)
Java代碼
- #把10.10.34.14:6386當前master遷移到10.10.34.14:6380上
- redis-trib.rb reshard 10.10.34.14:6380
- #根據提示選擇要遷移的slot數量(ps:這裏選擇500)
- How many slots do you want to move (from 1 to 16384)? 500(被刪除master的全部slot數量)
- #選擇要接受這些slot的node-id(10.10.34.14:6380)
- What is the receiving node ID? c4a31c852f81686f6ed8bcd6d1b13accdc947fd2 (ps:10.10.34.14:6380的node-id)
- Please enter all the source node IDs.
- Type 'all' to use all the nodes as source nodes for the hash slots.
- Type 'done' once you entered all the source nodes IDs.
- Source node #1:f51e26b5d5ff74f85341f06f28f125b7254e61bf(被刪除master的node-id)
- Source node #2:done
- #打印被移動的slot後,輸入yes開始移動slot以及對應的數據.
- #Do you want to proceed with the proposed reshard plan (yes/no)? yes
b):刪除空master節點
Java代碼
- redis-trib.rb del-node 10.10.34.14:6386 'f51e26b5d5ff74f85341f06f28f125b7254e61bf'