1. 程式人生 > >Redis Cluster 4.0 on CentOS 6.9 搭建

Redis Cluster 4.0 on CentOS 6.9 搭建

combine zip config 失效 對應關系 誰的 direct iss 新節點

集群簡介

Redis 集群是一個可以在多個 Redis 節點之間進行數據共享的設施(installation)。

Redis 集群不支持那些需要同時處理多個鍵的 Redis 命令, 因為執行這些命令需要在多個 Redis 節點之間移動數據, 並且在高負載的情況下, 這些命令將降低 Redis 集群的性能, 並導致不可預測的行為。

Redis 集群通過分區(partition)來提供一定程度的可用性(availability): 即使集群中有一部分節點失效或者無法進行通訊, 集群也可以繼續處理命令請求。

Redis 集群提供了以下兩個好處:

  • 將數據自動切分(split)到多個節點的能力。
  • 當集群中的一部分節點失效或者無法進行通訊時, 仍然可以繼續處理命令請求的能力

Redis 集群數據共享

Redis 集群使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集群包含 16384 個哈希槽(hash slot), 數據庫中的每個鍵都屬於這 16384 個哈希槽的其中一個, 集群使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪個槽, 其中 CRC16(key) 語句用於計算鍵 key 的 CRC16的校驗和 。

集群中的每個節點負責處理一部分哈希槽。 舉個例子, 一個集群可以有三個哈希槽, 其中:

  • 節點 A 負責處理 0 號至 5500 號哈希槽。
  • 節點 B 負責處理 5501
    號至 11000 號哈希槽。
  • 節點 C 負責處理 11001 號至 16384 號哈希槽。

這種將哈希槽分布到不同節點的做法使得用戶可以很容易地向集群中添加或者刪除節點。 比如說:

  • 如果用戶將新節點 D 添加到集群中, 那麽集群只需要將節點 A 、B 、 C 中的某些槽移動到節點 D 就可以了。
  • 與此類似, 如果用戶要從集群中移除節點 A , 那麽集群只需要將節點 A 中的所有哈希槽移動到節點 B 和節點 C , 然後再移除空白(不包含任何哈希槽)的節點 A 就可以了。

因為將一個哈希槽從一個節點移動到另一個節點不會造成節點阻塞, 所以無論是添加新節點還是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會造成集群下線。

Redis 集群中的主從復制

為了使得集群在一部分節點下線或者無法與集群的大多數(majority)節點進行通訊的情況下, 仍然可以正常運作, Redis 集群對節點使用了主從復制功能: 集群中的每個節點都有 1 個至 N 個復制品(replica), 其中一個復制品為主節點(master), 而其余的 N-1 個復制品為從節點(slave)。

在之前列舉的節點 A 、B 、C 的例子中, 如果節點 B 下線了, 那麽集群將無法正常運行, 因為集群找不到節點來處理 5501 號至 11000號的哈希槽。

另一方面, 假如在創建集群的時候(或者至少在節點 B 下線之前), 我們為主節點 B 添加了從節點 B1 , 那麽當主節點 B 下線的時候, 集群就會將 B1 設置為新的主節點, 並讓它代替下線的主節點 B , 繼續處理 5501 號至 11000 號的哈希槽, 這樣集群就不會因為主節點 B 的下線而無法正常運作了。

不過如果節點 B 和 B1 都下線的話, Redis 集群還是會停止運作。

技術分享

開始搭建

要讓集群正常工作至少需要3個主節點,在這裏我們要創建6個redis節點,其中三個為主節點,三個為從節點,對應的redis節點的ip和端口對應關系如下(為了簡單演示都在同一臺機器上面)

127.0.0.1:7000
127.0.0.1:7001

127.0.0.1:7002

127.0.0.1:7003

127.0.0.1:7004

127.0.0.1:7005

1. 獲取最新版Redis

wget http://download.redis.io/releases/redis-stable.tar.gz

2. 解壓到/usr/local/redis/安裝

# cd /usr/local/redis/
#ls -l
-rw-r--r--  1 root root 131381 Oct  1 20:41 00-RELEASENOTES
-rw-r--r--  1 root root     53 Oct  1 20:41 BUGS
-rw-r--r--  1 root root   1815 Oct  1 20:39 CONTRIBUTING
-rw-r--r--  1 root root   1487 Oct  1 20:39 COPYING
drwxr-xr-x  6 root root   4096 Oct  1 20:41 deps
-rw-r--r--  1 root root     11 Oct  1 20:39 INSTALL
-rw-r--r--  1 root root    151 Oct  1 20:39 Makefile
-rw-r--r--  1 root root   4223 Oct  1 20:39 MANIFESTO
-rw-r--r--  1 root root  20530 Oct  1 20:39 README.md
-rw-r--r--  1 root root  57764 Oct  1 20:39 redis.conf
-rwxr-xr-x  1 root root    271 Oct  1 20:39 runtest
-rwxr-xr-x  1 root root    280 Oct  1 20:39 runtest-cluster
-rwxr-xr-x  1 root root    281 Oct  1 20:39 runtest-sentinel
-rw-r--r--  1 root root   7606 Oct  1 20:39 sentinel.conf
drwxr-xr-x  3 root root   4096 Oct  1 20:41 src
drwxr-xr-x 10 root root   4096 Oct  1 20:41 tests
drwxr-xr-x  8 root root   4096 Oct  1 20:41 utils
#make && make install

 3. 創建目錄

mkdir /data/redis/cluster -p
cd /data/redis/cluster
mkdir 7000 7001 7002 7003 7004 7005

 4. 修改配置文件

cp /usr/local/redis/redis.conf /data/redis/cluster/7000/

修改配置文件中下面選項

port 7000

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

文件中的 cluster-enabled 選項用於開實例的集群模式, 而 cluster-conf-file 選項則設定了保存節點配置文件的路徑, 默認值為nodes.conf 。其他參數相信童鞋們都知道。節點配置文件無須人為修改, 它由 Redis 集群在啟動時創建, 並在有需要時自動進行更新。

修改完成後,把修改完成的redis.conf復制到7001-7005目錄下,並且端口修改成和文件夾對應。

[[email protected] 7000]# cp redis.conf ../7001/
[[email protected] 7000]# cp redis.conf ../7002/
[[email protected] 7000]# cp redis.conf ../7003/
[[email protected] 7000]# cp redis.conf ../7004/
[[email protected] 7000]# cp redis.conf ../7005/
# sed -i ‘s/port 7000/port 7001/g‘ /data/redis/cluster/7001/redis.conf 
# sed -i ‘s/port 7000/port 7002/g‘ /data/redis/cluster/7002/redis.conf 
# sed -i ‘s/port 7000/port 7003/g‘ /data/redis/cluster/7003/redis.conf 
# sed -i ‘s/port 7000/port 7004/g‘ /data/redis/cluster/7004/redis.conf 
# sed -i ‘s/port 7000/port 7005/g‘ /data/redis/cluster/7005/redis.conf 

 5. 啟動6個redis實例

cd /data/redis/cluster/7000
redis-server redis.conf
cd /data/redis/cluster/7001
redis-server redis.conf
cd /data/redis/cluster/7002
redis-server redis.conf
cd /data/redis/cluster/7003
redis-server redis.conf
cd /data/redis/cluster/7004
redis-server redis.conf
cd /data/redis/cluster/7005
redis-server redis.conf

 查看進程狀態

[[email protected] 7005]# ps -ef|grep redis
root     24873     1  0 21:00 ?        00:00:00 redis-server 127.0.0.1:7001 [cluster]           
root     24898     1  0 21:01 ?        00:00:00 redis-server 127.0.0.1:7000 [cluster]
root     24905     1  0 21:01 ?        00:00:00 redis-server 127.0.0.1:7002 [cluster]
root     24910     1  0 21:01 ?        00:00:00 redis-server 127.0.0.1:7003 [cluster]
root     24915     1  0 21:01 ?        00:00:00 redis-server 127.0.0.1:7004 [cluster]
root     24930     1  0 21:02 ?        00:00:00 redis-server 127.0.0.1:7005 [cluster]

 6. 執行命令創建集群,首先安裝依賴

首先要升級Ruby 到2.2 以上的版本

yum remove ruby
wget http://cache.ruby-lang.org/pub/ruby/ruby-2.4.2.zip 按照說明編譯安裝  

安裝rubygems

yum install rubygems -y

安裝gem-redis (下載地址:https://rubygems.org/gems/redis/versions/4.0.1)

這裏發現有報錯

[[email protected] /]# gem install -l redis-4.0.1.gem 
ERROR:  Loading command: install (LoadError)

ERROR:  While executing gem ... (NoMethodError)
    undefined method `invoke_with_build_args‘ for nil:NilClass

 網上Google 搜到一堆apt-get 的Ubantu 解決方案, 最後在git 上面找到解決辦法

git clone https://github.com/ruby/zlib.git

 然後安裝zlib 包

[[email protected] zlib]# ruby extconf.rb
checking for deflateReset() in -lz... yes
checking for zlib.h... yes
checking for crc32_combine() in zlib.h... yes
checking for adler32_combine() in zlib.h... yes
checking for z_crc_t in zlib.h... no
creating Makefile
[[email protected] zlib]# 
[[email protected] zlib]# make
compiling zlib.c
linking shared-object zlib.so
[[email protected] zlib]# 
[[email protected] zlib]# make install
/usr/bin/install -c -m 0755 zlib.so /usr/local/lib/ruby/site_ruby/2.4.0/x86_64-linux

 解決這個問題之後就可以安裝 redis-4.0.1.gem 了

[[email protected]/]# gem install -l redis-4.0.1.gem 
Successfully installed redis-4.0.1
Parsing documentation for redis-4.0.1
Installing ri documentation for redis-4.0.1
Done installing documentation for redis after 2 seconds

  7. 使用redis-trib 創建集群

cp /usr/local/redis/src/redis-trib.rb /usr/local/bin/redis-trib.rb
redis-trib create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

命令的意義如下:

  • 給定 redis-trib.rb 程序的命令是 create , 這表示我們希望創建一個新的集群。
  • 選項 --replicas 1 表示我們希望為集群中的每個主節點創建一個從節點。
  • 之後跟著的其他參數則是實例的地址列表, 我們希望程序使用這些地址所指示的實例來創建新集群。

簡單來說, 以上命令的意思就是讓 redis-trib 程序創建一個包含三個主節點和三個從節點的集群。

接著, redis-trib 會打印出一份預想中的配置給你看, 如果你覺得沒問題的話, 就可以輸入 yes redis-trib 就會將這份配置應用到集群當中:

> 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
Adding replica 127.0.0.1:7003 to 127.0.0.1:7000
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
M: 2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: 045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:7003
   replicates 2909642e736c8510a6b284139de164e5192749f4
S: 079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:7004
   replicates 67c520e08194014965474ffb6ac8e30c8f39fb63
S: 6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:7005
   replicates d94fc8802b29df1c8601b337df927420492e7179
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 127.0.0.1:7000)
M: 2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 2909642e736c8510a6b284139de164e5192749f4
S: 6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:7005
   slots: (0 slots) slave
   replicates d94fc8802b29df1c8601b337df927420492e7179
S: 079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 67c520e08194014965474ffb6ac8e30c8f39fb63
M: 67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

  集群的客戶端

Redis 集群現階段的一個問題是客戶端實現很少。 以下是一些網上一些資料:

  • redis-rb-cluster 是antirez編寫的 Ruby 實現, 用於作為其他實現的參考。 該實現是對 redis-rb 的一個簡單包裝, 高效地實現了與集群進行通訊所需的最少語義(semantic)。
  • redis-py-cluster 看上去是 redis-rb-cluster 的一個 Python 版本, 這個項目有一段時間沒有更新了(最後一次提交是在六個月之前), 不過可以將這個項目用作學習集群的起點。
  • 流行的 Predis 曾經對早期的 Redis 集群有過一定的支持, 但我不確定它對集群的支持是否完整, 也不清楚它是否和最新版本的 Redis 集群兼容 (因為新版的 Redis 集群將槽的數量從 4k 改為 16k 了)。
  • Redis unstable 分支中的 redis-cli 程序實現了非常基本的集群支持, 可以使用命令 redis-cli -c 來啟動。

測試 Redis 集群比較簡單的辦法就是使用 redis-rb-cluster 或者 redis-cli , 接下來我們將使用 redis-cli 為例來進行演示:

[[email protected] src]# redis-cli -c -p 7000
127.0.0.1:7000> set name ray
-> Redirected to slot [5798] located at 127.0.0.1:7001
OK
127.0.0.1:7001> 
127.0.0.1:7001> set name2 Tim
-> Redirected to slot [742] located at 127.0.0.1:7000
OK
127.0.0.1:7000> set name3 Andy
OK

  關於redis 支持的數據類型和詳細的命令解釋,可以參考http://redisdoc.com

[[email protected] /]# redis-cli -p 7000 cluster nodes
d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:[email protected] master - 0 1506867732433 3 connected 10923-16383
045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:[email protected] slave 2909642e736c8510a6b284139de164e5192749f4 0 1506867731000 4 connected
6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:[email protected] slave d94fc8802b29df1c8601b337df927420492e7179 0 1506867730528 6 connected
079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:[email protected] slave 67c520e08194014965474ffb6ac8e30c8f39fb63 0 1506867730427 5 connected
2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:[email protected] myself,master - 0 1506867732000 1 connected 0-5460
67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:[email protected] master - 0 1506867731530 2 connected 5461-10922

 從上面的輸出可以看出,集群由3主3備組成,而且可以看出誰是誰的主和備,其中第一列是Redis 節點的ID,集群通信基於這個唯一的ID 而不是IP 和端口

另外info 命令可以看出集群的其他很多配置信息

127.0.0.1:7002> info
# Server
redis_version:4.0.2
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:5d2f34688764aa69
redis_mode:cluster
os:Linux 2.6.32-696.3.2.el6.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:sync-builtin
gcc_version:4.4.7
process_id:24905
run_id:cf77b38c7a0d209d5e86f0c58243b1c81b2b261b
tcp_port:7002
uptime_in_seconds:5094
uptime_in_days:0
hz:10
lru_clock:13695774
executable:/data/redis/cluster/7002/redis-server
config_file:/data/redis/cluster/7002/redis.conf

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:2623728
used_memory_human:2.50M
used_memory_rss:12177408
used_memory_rss_human:11.61M
used_memory_peak:2623728
used_memory_peak_human:2.50M
used_memory_peak_perc:100.04%
used_memory_overhead:2538992
used_memory_startup:1423928
used_memory_dataset:84736
used_memory_dataset_perc:7.06%
total_system_memory:4018335744
total_system_memory_human:3.74G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:4.64
mem_allocator:jemalloc-4.0.3
active_defrag_running:0
lazyfree_pending_objects:0

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1506867313
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:8572928
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
aof_current_size:0
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0

# Stats
total_connections_received:4
total_commands_processed:702
instantaneous_ops_per_sec:0
total_net_input_bytes:85105
total_net_output_bytes:11244
instantaneous_input_kbps:0.02
instantaneous_output_kbps:0.01
rejected_connections:0
sync_full:1
sync_partial_ok:0
sync_partial_err:1
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:1
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:4435
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0

# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7005,state=online,offset=952,lag=1
master_replid:6e3d41dcdd4c3c4767affccdd2b2150cb7d3fcd9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:966
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:966

# CPU
used_cpu_sys:4.53
used_cpu_user:2.50
used_cpu_sys_children:0.01
used_cpu_user_children:0.00

# Cluster
cluster_enabled:1

# Keyspace

  8. Redis 故障測試

嘗試kill 掉7000實例,集群自動識別並提升對應的slave 為主

[[email protected] src]# redis-cli -c -p 7001 cluster nodes
079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:[email protected] slave 67c520e08194014965474ffb6ac8e30c8f39fb63 0 1506868482542 5 connected
2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:[email protected] master,fail - 1506868460710 1506868460595 1 disconnected
045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:[email protected] master - 0 1506868482000 7 connected 0-5460
67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:[email protected] myself,master - 0 1506868480000 2 connected 5461-10922
6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:[email protected] slave d94fc8802b29df1c8601b337df927420492e7179 0 1506868481000 6 connected
d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:[email protected] master - 0 1506868481096 3 connected 10923-16383

嘗試把7000重新啟動,7000並不會去搶占,而是變成新的slave 加入集群

[[email protected] src]# redis-cli -c -p 7001 cluster nodes
079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:[email protected] slave 67c520e08194014965474ffb6ac8e30c8f39fb63 0 1506868670539 5 connected
2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:[email protected] slave 045c473cb8e416f39444e455151eeff8168bff69 0 1506868672044 7 connected
045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:[email protected] master - 0 1506868671542 7 connected 0-5460
67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:[email protected] myself,master - 0 1506868671000 2 connected 5461-10922
6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:[email protected] slave d94fc8802b29df1c8601b337df927420492e7179 0 1506868670000 6 connected
d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:[email protected] master - 0 1506868671040 3 connected 10923-16383

Redis 除了RDB 之外還有另一種持久化的方式叫AOF,有點像MySQL 的binlog

[[email protected] 7000]# ll
total 72
-rw-r--r-- 1 root root   124 Oct  1 22:28 appendonly.aof
-rw-r--r-- 1 root root   205 Oct  1 22:30 dump.rdb
-rw-r--r-- 1 root root   781 Oct  1 22:15 nodes.conf
-rw-r--r-- 1 root root 57758 Oct  1 20:52 redis.conf
[[email protected] 7000]# more appendonly.aof 
*2
$6 
SELECT
$1 
0
*3
$3 
set
$5 
name2
$3 
Tim
*3
$3 
set
$5 
name3
$4 
Andy
*3
$3 
set
$5 
name2
$4 
Tony

  

最後,想說說Redis 的集群方案,目前有3大方案:

1. Redis cluster

2. Twemproxy

3. Codis

網上有很多這三種方案的比較,目前最成熟的應該是Codis 由豌豆莢開源,後面會補充Codis 的搭建手冊 https://github.com/CodisLabs/codis/

本文主要參考資料:

http://www.cnblogs.com/gomysql/p/4395504.html

http://redisdoc.com/topic/cluster-tutorial.html

Redis Cluster 4.0 on CentOS 6.9 搭建