目錄 1java
1. 前言 2node
2. 部署計劃 2linux
3. 目錄結構 2git
4. 編譯安裝 3github
5. 修改系統參數 3redis
5.2. TCP監聽隊列大小 4ruby
5.3. OOM相關:vm.overcommit_memory 4app
5.4. /sys/kernel/mm/transparent_hugepage/enabled 4框架
11.3. jedis(java cluster client) 11
11.4. r3c(C++ cluster client) 12
15.2. redis-trib.rb rebalance 14
本文參考官方文檔而成:http://redis.io/topics/cluster-tutorial。經測試,安裝過程也適用於redis-3.2.0。
依據官網介紹,部署6個redis節點,爲3主3從。3臺物理機每臺都建立2個redis節點:
服務端口 |
IP地址 |
配置文件名 |
6379 |
192.168.0.251 |
redis-6379.conf |
6379 |
192.168.0.252 |
redis-6379.conf |
6379 |
192.168.0.253 |
redis-6379.conf |
6380 |
192.168.0.251 |
redis-6380.conf |
6380 |
192.168.0.252 |
redis-6380.conf |
6380 |
192.168.0.253 |
redis-6380.conf |
疑問:3臺物理機,會不會主和從節點分佈在同一個物理機上?
redis.conf爲從https://raw.githubusercontent.com/antirez/redis/3.0/redis.conf下載的配置文件。redis-6379.conf和redis-6380.conf指定了服務端口,二者均經過include複用(包含)了redis.conf。
本文將redis安裝在/data/redis(每臺機器徹底相同,同一臺機器上的多個節點對應相同的目錄和文件,並建議將bin目錄加入到環境變量PATH中,以簡化後續的使用):
/data/redis |-- bin | |-- redis-benchmark | |-- redis-check-aof | |-- redis-check-dump | |-- redis-cli | |-- redis-sentinel -> redis-server | `-- redis-server |-- conf | |-- redis-6379.conf | |-- redis-6380.conf | `-- redis.conf `-- log
3 directories, 9 files |
打開redis的Makefile文件,能夠看到以下內容:
PREFIX?=/usr/local INSTALL_BIN=$(PREFIX)/bin INSTALL=install |
Makefile中的「?=」表示,若是該變量以前沒有定義過,則賦值爲/usr/local,不然什麼也不作。
若是不設置環境變量PREFIX或不修改Makefile中的值,則默認安裝到/usr/local/bin目錄下。建議不要使用默認配置,而是指定安裝目錄,如/data/redis-3.0.5:
$ make $ make install PREFIX=/data/redis-3.0.5 $ ln -s /data/redis-3.0.5 /data/redis $ mkdir /data/redis/conf $ mkdir /data/redis/log $ mkdir /data/redis/data |
修改文件/etc/security/limits.conf,加入如下兩行:
* soft nofile 102400 * hard nofile 102400
# End of file |
其中102400爲一個進程最大能夠打開的文件個數,當與RedisServer的鏈接數多時,須要設定爲合適的值。
修改後,須要從新登陸纔會生效,若是是crontab,則須要重啓crontab,如:service crond restart,有些平臺多是service cron restart。
即TCP listen的backlog大小,「/proc/sys/net/core/somaxconn」的默認值通常較小如128,須要修改大一點,好比改爲32767。當即生效還可使用命令:sysctl -w net.core.somaxconn=32767。
要想永久生效,須要在文件/etc/sysctl.conf中增長一行:net.core.somaxconn = 32767,而後執行命令「sysctl -p」以生效。
若是「/proc/sys/vm/overcommit_memory」的值爲0,則會表示開啓了OOM。能夠設置爲1關閉OOM,設置方法請參照net.core.somaxconn完成。
默認值爲「[always] madvise never」,建議設置爲never,以開啓內核的「Transparent Huge Pages (THP)」特性,設置後redis進程須要重啓。爲了永久生效,請將「echo never > /sys/kernel/mm/transparent_hugepage/enabled」加入到文件/etc/rc.local中。
從https://raw.githubusercontent.com/antirez/redis/3.0/redis.conf下載配置文件(也可直接複製源代碼包中的redis.conf,而後在它的基礎上進行修改),在這個基礎上,進行以下表所示的修改(配置文件名redis-6379.conf中的6379建議設置爲實際使用的端口號):
配置項 |
值 |
配置文件 |
說明 |
port |
6379 |
redis-6379.conf |
客戶端鏈接端口,而且總有一個恰好大於10000的端口,這個大的端口用於主從複製和集羣內部通信。 |
cluster-config-file |
nodes-6379.conf |
|
|
pidfile |
/var/run/redis-6379.pid |
只有當daemonize值爲yes時,纔有意義;而且這個要求對目錄/var/run有寫權限,不然能夠考慮設置爲/tmp/redis-6379.pid。 |
|
dir |
/data/redis/data/6379 |
|
|
dbfilename |
dump-6379.rdb |
位於dir指定的目錄下 |
|
appendfilename |
"appendonly-6379.aof" |
|
|
logfile |
/data/redis/log/redis-6379.log |
日誌文件,包含目錄和文件名 |
|
loglevel |
verbose |
|
日誌級別 |
port |
6380 |
redis-6380.conf |
|
cluster-config-file |
nodes-6380.conf |
|
|
pidfile |
/var/run/redis-6380.pid |
|
|
dir |
/data/redis/data/6380 |
AOF和RDB文件存放目錄 |
|
dbfilename |
dump-6380.rdb |
RDB文件名 |
|
appendfilename |
appendonly-6380.aof |
AOF文件名 |
|
logfile |
/data/redis/log/redis-6380.log |
|
|
loglevel |
verbose |
日誌級別 |
|
cluster-enabled |
yes |
redis.conf |
表示以集羣方式運行,爲no表示以非集羣方式運行 |
cluster-node-timeout |
3000 |
單位爲毫秒: repl-ping-slave-period+ (cluster-node-timeout* cluster-slave-validity-factor) |
|
cluster-slave-validity-factor |
0 |
若是要最大的可用性,值設置爲0 |
|
repl-ping-slave-period |
1 |
slave ping master的時間間隔,單位爲秒 |
|
repl-timeout |
10 |
複製超時,單位爲秒,須大於repl-ping-slave-period的值 |
|
slave-read-only |
yes |
slave是否只讀 |
|
slave-serve-stale-data |
yes |
當slave與master斷開鏈接,slave是否繼續提供服務 |
|
slave-priority |
100 |
slave權重值,當master掛掉,只有權重最大的slave接替master |
|
appendonly |
yes |
當同時寫AOF或RDB,則redis啓動時只會加載AOF,AOF包含了全量數據 |
|
daemonize |
yes |
相關配置項pidfile |
|
protected-mode |
no |
3.2.0新增的配置項,默認值爲yes,限制從其它機器登陸Redis server,而只能從127.0.0.1登陸。爲保證redis-trib.rb工具的正常運行,須要設置爲no,完成後能夠改回yes,但每次使用redis-trib.rb都須要改回爲no。要想從非127.0.0.1訪問也須要改成no。 |
|
tcp-backlog |
32767 |
取值不能超過系統的/proc/sys/net/core/somaxconn |
|
auto-aof-rewrite-percentage |
100 |
設置自動rewite AOF文件(手工rewrite只須要調用命令BGREWRITEAOF) |
|
auto-aof-rewrite-min-size |
64mb |
觸發rewrite的AOF文件大小,只有大於此大小時纔會觸發rewrite |
|
no-appendfsync-on-rewrite |
yes |
子進程在作rewrite時,主進程不調用fsync(由內核默認調度) |
|
cluster-require-full-coverage |
no |
爲no表示有slots不可服務時其它slots仍然繼續服務 |
登陸3臺物理機,啓動兩個redis實例(啓動以前,須要建立好配置中的各目錄):
1) redis-server redis-6379.conf
2) redis-server redis-6380.conf
能夠寫一個啓動腳本start-redis-cluster.sh:
#!/bin/sh
REDIS_HOME=/data/redis $REDIS_HOME/bin/redis-server $REDIS_HOME/conf/redis-6379.conf $REDIS_HOME/bin/redis-server $REDIS_HOME/conf/redis-6380.conf |
上一步啓動的redis只是單機版本,在啓動redis cluster以前,須要完成以下一些依賴的安裝。在此以後,才能夠建立和啓動redis cluster。
安裝命令:yum install ruby
安裝過程當中,如提示「[y/d/N]」,請選「y」而後回車。
查看版本:
$ ruby --version ruby 2.0.0p353 (2013-11-22) [x86_64-linux] |
也能夠從Ruby官網https://www.ruby-lang.org下載安裝包(如ruby-2.3.1.tar.gz)來安裝Ruby。截至2016/5/13,Ruby的最新穩定版本爲Ruby 2.3.1。
安裝命令:yum install rubygems
若是不使用yum安裝,也能夠手動安裝RubyGems,RubyGems是一個Ruby包管理框架,它的下載網址:https://rubygems.org/pages/download。
好比下載安裝包rubygems-2.6.4.zip後解壓,而後進入解壓生成的目錄,裏面有個setup.rb文件,以root用戶執行:ruby setup.rb安裝RubyGems。
安裝命令:gem install -l redis-3.0.0.gem
安裝以前,須要先下載好redis-3.0.0.gem。
redis-3.0.0.gem官網:https://rubygems.org/gems/redis/versions/3.0.0
redis-3.0.0.gem下載網址:https://rubygems.org/downloads/redis-3.0.0.gem
redis-3.3.0.gem官網:https://rubygems.org/gems/redis/versions/3.3.0
redis-trib.rb是redis官方提供的redis cluster管理工具,使用ruby實現。
將redis源代碼的src目錄下的集羣管理程序redis-trib.rb複製到/data/redis/bin目錄,並將bin目錄加入到環境變量PATH中,以簡化後續的操做。
redis-trib.rb用法(不帶任何參數執行redis-trib.rb即顯示用法):
$ ./redis-trib.rb Usage: redis-trib <command> <options> <arguments ...>
rebalance host:port --auto-weights --timeout <arg> --pipeline <arg> --use-empty-masters --weight <arg> --threshold <arg> --simulate add-node new_host:new_port existing_host:existing_port --slave --master-id <arg> reshard host:port --timeout <arg> --pipeline <arg> --yes --slots <arg> --to <arg> --from <arg> check host:port set-timeout host:port milliseconds call host:port command arg arg .. arg fix host:port --timeout <arg> info host:port create host1:port1 ... hostN:portN --replicas <arg> import host:port --replace --copy --from <arg> help (show this help) del-node host:port node_id
For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster. |
建立命令(3主3從):
redis-trib.rb create --replicas 1 192.168.0.251:6379 192.168.0.252:6379 192.168.0.253:6379 192.168.0.251:6380 192.168.0.252:6380 192.168.0.253:6380 |
Ø 參數說明:
1) create
表示建立一個redis cluster集羣。
2) --replicas 1
表示爲集羣中的每個主節點指定一個從節點,即一比一的複製。\
運行過程當中,會有個提示,輸入yes回車便可。從屏幕輸出,能夠很容易地看出哪些是主(master)節點,哪些是從(slave)節點:
>>> Creating cluster Connecting to node 192.168.0.251:6379: OK /usr/local/share/gems/gems/redis-3.0.0/lib/redis.rb:182: warning: wrong element type nil at 0 (expected array) /usr/local/share/gems/gems/redis-3.0.0/lib/redis.rb:182: warning: ignoring wrong elements is deprecated, remove them explicitly /usr/local/share/gems/gems/redis-3.0.0/lib/redis.rb:182: warning: this causes ArgumentError in the next release >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 192.168.0.251:6379 192.168.0.252:6379 192.168.0.253:6379 Adding replica 192.168.0.252:6380 to 192.168.0.251:6379 Adding replica 192.168.0.251:6380 to 192.168.0.252:6379 Adding replica 192.168.0.253:6380 to 192.168.0.253:6379 M: 150f77d1000003811fb3c38c3768526a0b25ec31 192.168.0.251:6379 slots:0-5460 (5461 slots) master M: de461d3337b17d2119b79024d57d8b119e7320a6 192.168.0.252:6379 slots:5461-10922 (5462 slots) master M: faf50658fb7b0bae64cee5371da782e0f4919eee 192.168.0.253:6379 slots:10923-16383 (5461 slots) master S: c567db02cc40eebf577f71f703214dd2f4f26dfb 192.168.0.251:6380 replicates de461d3337b17d2119b79024d57d8b119e7320a6 S: 284f8196b250ad9ac272316db84a07bebf661ab7 192.168.0.252:6380 replicates 150f77d1000003811fb3c38c3768526a0b25ec31 S: 39fdef9fd5778dc94d8add819789d7d73ca06899 192.168.0.253:6380 replicates faf50658fb7b0bae64cee5371da782e0f4919eee Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join.... >>> Performing Cluster Check (using node 192.168.0.251:6379) M: 150f77d1000003811fb3c38c3768526a0b25ec31 192.168.0.251:6379 slots:0-5460 (5461 slots) master M: de461d3337b17d2119b79024d57d8b119e7320a6 192.168.0.252:6379 slots:5461-10922 (5462 slots) master M: faf50658fb7b0bae64cee5371da782e0f4919eee 192.168.0.253:6379 slots:10923-16383 (5461 slots) master M: c567db02cc40eebf577f71f703214dd2f4f26dfb 192.168.0.251:6380 slots: (0 slots) master replicates de461d3337b17d2119b79024d57d8b119e7320a6 M: 284f8196b250ad9ac272316db84a07bebf661ab7 192.168.0.252:6380 slots: (0 slots) master replicates 150f77d1000003811fb3c38c3768526a0b25ec31 M: 39fdef9fd5778dc94d8add819789d7d73ca06899 192.168.0.253:6380 slots: (0 slots) master replicates faf50658fb7b0bae64cee5371da782e0f4919eee [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. |
[test@test-168-251 ~]$ ps aux|grep redis test 3824 0.7 5.9 6742404 3885144 ? Ssl 2015 1639:13 /data/redis/bin/redis-server *:6379 [cluster] test 3831 0.5 3.9 6709636 2618536 ? Ssl 2015 1235:43 /data/redis/bin/redis-server *:6380 [cluster] |
中止redis實例,直接使用kill命令便可,如:kill 3831,重啓和單機版相同,通過上述一系列操做後,重啓會自動轉換成cluster模式。。
官方提供的命令行客戶端工具,在單機版redis基礎上指定參數「-c」便可。如下是在192.168.0.251上執行redis-cli的記錄:
$ ./redis-cli -c -p 6379 127.0.0.1:6379> set foo bar -> Redirected to slot [12182] located at 192.168.0.253:6379 OK 192.168.0.253:6379> set hello world -> Redirected to slot [866] located at 192.168.0.251:6379 OK 192.168.0.251:6379> get foo -> Redirected to slot [12182] located at 192.168.0.253:6379 "bar" 192.168.0.253:6379> get hello -> Redirected to slot [866] located at 192.168.0.251:6379 "world"
查看集羣中的節點: 192.168.0.251:6379> cluster nodes |
默認不能從slaves讀取數據,但創建鏈接後,執行一次命令READONLY ,便可從slaves讀取數據。若是想再次恢復不能從slaves讀取數據,能夠執行下命令READWRITE。
官網:https://github.com/xetorthio/jedis
編程示例:
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); //Jedis Cluster will attempt to discover cluster nodes automatically jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379)); JedisCluster jc = new JedisCluster(jedisClusterNodes); jc.set("foo", "bar"); String value = jc.get("foo"); |
官網:https://github.com/eyjian/r3c
先以單機版配置和啓動好redis-server,而後執行命令:
./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000 |
執行上面這條命令時,可能遇到錯誤「[ERR] Sorry, can't connect to node 127.0.0.1:7006」。引發該問題的緣由多是由於ruby的版本太低(運行ruby -v能夠查看ruby的版本),能夠嘗試升級ruby再嘗試,好比ruby 1.8.7版本就須要升級。對於Redis 3.0.5和Redis 3.2.0,使用Ruby 2.3.1操做正常。請注意升級到最新版本的ruby也可能遇到這個錯誤。
另外一個會引發這個問題的緣由是從Redis 3.2.0版本開始引入了「保護模式(protected mode),防止redis-cli遠程訪問」,僅限redis-cli綁定到127.0.0.1才能夠鏈接Redis server。
爲了完成添加新主節點,能夠暫時性的關閉保護模式,使用redis-cli,不指定-h參數(但能夠指定-p參數,或者-h參數值爲127.0.0.1)進入操做界面:CONFIG SET protected-mode no。
注意7006是新增的節點,而7000是已存在的節點(可爲master或slave)。若是須要將7006變成某master的slave節點,執行命令:
cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e |
新加入的master節點上沒有任何數據(slots,運行redis命令cluster nodes能夠看到這個狀況)。當一個slave想成爲master時,因爲這個新的master節點無論理任何slots,它不參與選舉。
可使用工具redis-trib.rb的resharding特性爲這個新master節點分配slots,如:
redis-trib.rb reshard 127.0.0.1:7000,其中7000爲集羣中任意一個節點便可,redis-trib.rb將自動發現其它節點。
在reshard過程當中,將會詢問reshard多少slots:
How many slots do you want to move (from 1 to 16384)?,取值範圍爲1~16384,其中16384爲redis cluster的擁有的slots總數,好比想只移動100個,輸入100便可。若是遷移的slots數量多,應當設置redis-trib.rb的超時參數--timeout值大一點。不然,遷移過程當中易遇到超時錯誤「[ERR] Calling MIGRATE: IOERR error or timeout reading to target instance」,致使只完成部分,可能會形成數據丟失。
接着,會提示「What is the receiving node ID?」,輸入新加入的master節點ID。過程當中若是遇到錯誤「Sorry, can't connect to node 10.225.168.253:6380」,則可能須要暫時先關閉相應的保護模式。
若是在遷移過程遇到下面這樣的錯誤:
>>> Check for open slots... [WARNING] Node 192.168.0.3:6379 has slots in importing state (5461). [WARNING] Node 192.168.0.5:6380 has slots in migrating state (5461). [WARNING] The following slots are open: 5461 |
能夠考慮使用命令「redis-trib.rb fix 192.168.0.3:6379」嘗試修復。須要顯示有節點處於migrating或importing狀態,能夠登陸到相應的節點,使用命令「cluster setslot 5461 stable」修改,參數5461爲問題顯示的slot的ID。
./redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:7000 |
注意這種方式,若是添加了多個slave節點,可能致使master的slaves不均衡,好比一些有3個slave,其它只1個slave。能夠在slave節點上執行redis命令「CLUSTER REPLICATE」進行調整,讓它成爲其它master的slave。「CLUSTER REPLICATE」帶一個參數,即master ID,注意使用redis-cli -c登陸到slave上執行。
上面方法沒有指定7006的master,而是隨機指定。下面方法能夠明確指定爲哪一個master的slave:
./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000 |
從集羣中刪除一個節點:
./redis-trib del-node 127.0.0.1:7000 `<node-id>` |
第一個參數爲集羣中任意一個節點,第二個參數爲須要刪除節點的ID。
CLUSTER FORGET <node-id>
注意若是是刪除一個master節點,則須要先將它管理的slots的遷走,而後才能夠刪除它。
redis-trib.rb check 127.0.0.1:6380
如發現以下這樣的錯誤:
[WARNING] Node 192.168.0.11:6380 has slots in migrating state (5461).
[WARNING] The following slots are open: 5461
可使用redis命令取消slots遷移(5461爲slot的ID):
cluster setslot 5461 stable
須要注意,須登陸到192.168.0.11:6380上執行redis的setslot子命令。
CLUSTER ADDSLOTS slot1 [slot2] ... [slotN] CLUSTER DELSLOTS slot1 [slot2] ... [slotN] CLUSTER SETSLOT slot NODE node CLUSTER SETSLOT slot MIGRATING node CLUSTER SETSLOT slot IMPORTING node |
示例:將slot8從節點A遷移到節點B,有以下兩種方法:
在節點B上執行:CLUSTER SETSLOT 8 IMPORTING A 或 在節點A上執行:CLUSTER SETSLOT 8 MIGRATING B |
當有增減節點時,可使用命令:
redis-trib.rb rebalance 192.168.0.31:6379 --auto-weights
作一次均衡,簡單點能夠只指定兩個參數:「192.168.0.31:6379」爲集羣中已知的任何一個節點,參數「-auto-weights」表示自動權重。
在須要的slaves節點上執行命令:CLUSTER FAILOVER。
對應的redis命令爲:cluster info,示例:
127.0.0.1:6381> cluster info cluster_state:ok 全部slots正常則顯示爲OK,不然爲error cluster_slots_assigned:16384 多少slots被分配了,即多少被master管理了,16384爲所有slots cluster_slots_ok:16384 有多少slots是正常的 cluster_slots_pfail:0 有多少slots可能處於異常狀態,處於這個狀態並不表示有問題,仍能繼續提供服務 cluster_slots_fail:0 有多少slots處於異常狀態,須要修復才能服務 cluster_known_nodes:10 集羣中的節點數 cluster_size:3 集羣中master個數 cluster_current_epoch:11 本地的當前時間變量,用於故障切換時生成獨一無二的增量版本號 cluster_my_epoch:0 cluster_stats_messages_sent:4049 經過集羣消息總線發送的消息總數 cluster_stats_messages_received:4051 經過過集經過羣消息總線收到的消息總數 |
1) 若是最後一條日誌爲「16367:M 08 Jun 14:48:15.560 # Server started, Redis version 3.2.0」,節點狀態始終終於fail狀態,則多是aof文件損壞了,這時可使用工具edis-check-aof --fix進行修改,如:
../../bin/redis-check-aof --fix appendonly-6380.aof
0x a1492b9b: Expected prefix '
AOF analyzed: size=2705928192, ok_up_to=2705927067, diff=1125
This will shrink the AOF from 2705928192 bytes, with 1125 bytes, to 2705927067 bytes
Continue? [y/N]: y