Redis 集羣是一個能夠在多個 Redis 節點之間進行數據共享的設施(installation)。html
Redis 集羣不支持那些須要同時處理多個鍵的 Redis 命令, 由於執行這些命令須要在多個 Redis 節點之間移動數據, 而且在高負載的狀況下, 這些命令將下降 Redis 集羣的性能, 並致使不可預測的行爲。node
Redis 集羣經過分區(partition)來提供必定程度的可用性(availability): 即便集羣中有一部分節點失效或者沒法進行通信, 集羣也能夠繼續處理命令請求。mysql
Redis 集羣提供瞭如下兩個好處:linux
Redis 集羣使用數據分片(sharding)而非一致性哈希(consistency hashing)來實現: 一個 Redis 集羣包含 16384
個哈希槽(hash slot), 數據庫中的每一個鍵都屬於這 16384
個哈希槽的其中一個, 集羣使用公式 CRC16(key) % 16384
來計算鍵 key
屬於哪一個槽, 其中 CRC16(key)
語句用於計算鍵 key
的 CRC16的校驗和 。git
集羣中的每一個節點負責處理一部分哈希槽。 舉個例子, 一個集羣能夠有三個哈希槽, 其中:github
0
號至 5500
號哈希槽。5501
號至 11000
號哈希槽。11001
號至 16384
號哈希槽。這種將哈希槽分佈到不一樣節點的作法使得用戶能夠很容易地向集羣中添加或者刪除節點。 好比說:redis
由於將一個哈希槽從一個節點移動到另外一個節點不會形成節點阻塞, 因此不管是添加新節點仍是移除已存在節點, 又或者改變某個節點包含的哈希槽數量, 都不會形成集羣下線。sql
爲了使得集羣在一部分節點下線或者沒法與集羣的大多數(majority)節點進行通信的狀況下, 仍然能夠正常運做, Redis 集羣對節點使用了主從複製功能: 集羣中的每一個節點都有 1
個至 N
個複製品(replica), 其中一個複製品爲主節點(master), 而其他的 N-1
個複製品爲從節點(slave)。數據庫
在以前列舉的節點 A 、B 、C 的例子中, 若是節點 B 下線了, 那麼集羣將沒法正常運行, 由於集羣找不到節點來處理 5501
號至 11000
號的哈希槽。api
另外一方面, 假如在建立集羣的時候(或者至少在節點 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目錄下,而且端口修改爲和文件夾對應。
[root@test 7000]# cp redis.conf ../7001/ [root@test 7000]# cp redis.conf ../7002/ [root@test 7000]# cp redis.conf ../7003/ [root@test 7000]# cp redis.conf ../7004/ [root@test 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
查看進程狀態
[root@test 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)
這裏發現有報錯
[root@test /]# 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 包
[root@test 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 [root@test zlib]# [root@test zlib]# make compiling zlib.c linking shared-object zlib.so [root@test zlib]# [root@test 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 了
[root@test/]# 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 程序建立一個包含三個主節點和三個從節點的集羣。
接着, 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 集羣比較簡單的辦法就是使用 redis-rb-cluster 或者 redis-cli , 接下來咱們將使用 redis-cli 爲例來進行演示:
[root@test 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
[root@test /]# redis-cli -p 7000 cluster nodes d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:7002@17002 master - 0 1506867732433 3 connected 10923-16383 045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:7003@17003 slave 2909642e736c8510a6b284139de164e5192749f4 0 1506867731000 4 connected 6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:7005@17005 slave d94fc8802b29df1c8601b337df927420492e7179 0 1506867730528 6 connected 079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:7004@17004 slave 67c520e08194014965474ffb6ac8e30c8f39fb63 0 1506867730427 5 connected 2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:7000@17000 myself,master - 0 1506867732000 1 connected 0-5460 67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:7001@17001 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 爲主
[root@test src]# redis-cli -c -p 7001 cluster nodes
079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:7004@17004 slave 67c520e08194014965474ffb6ac8e30c8f39fb63 0 1506868482542 5 connected
2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:7000@17000 master,fail - 1506868460710 1506868460595 1 disconnected
045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:7003@17003 master - 0 1506868482000 7 connected 0-5460
67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:7001@17001 myself,master - 0 1506868480000 2 connected 5461-10922
6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:7005@17005 slave d94fc8802b29df1c8601b337df927420492e7179 0 1506868481000 6 connected
d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:7002@17002 master - 0 1506868481096 3 connected 10923-16383
嘗試把7000從新啓動,7000並不會去搶佔,而是變成新的slave 加入集羣
[root@test src]# redis-cli -c -p 7001 cluster nodes
079ea3c2c8a4d75cf4e19e6cb6d4a0ccbbb6cd80 127.0.0.1:7004@17004 slave 67c520e08194014965474ffb6ac8e30c8f39fb63 0 1506868670539 5 connected
2909642e736c8510a6b284139de164e5192749f4 127.0.0.1:7000@17000 slave 045c473cb8e416f39444e455151eeff8168bff69 0 1506868672044 7 connected
045c473cb8e416f39444e455151eeff8168bff69 127.0.0.1:7003@17003 master - 0 1506868671542 7 connected 0-5460
67c520e08194014965474ffb6ac8e30c8f39fb63 127.0.0.1:7001@17001 myself,master - 0 1506868671000 2 connected 5461-10922
6bdaac36d8ea69968b061b44bb47657000340e4c 127.0.0.1:7005@17005 slave d94fc8802b29df1c8601b337df927420492e7179 0 1506868670000 6 connected
d94fc8802b29df1c8601b337df927420492e7179 127.0.0.1:7002@17002 master - 0 1506868671040 3 connected 10923-16383
Redis 除了RDB 以外還有另外一種持久化的方式叫AOF,有點像MySQL 的binlog
[root@test 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 [root@test 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