集群介绍
集群由多个节点(Node)组成,Redis的数据分布在这些节点中。
集群中的节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护;从节点只进行主节点数据和状态信息的复制。
集群的作用
1、数据分区(集群最核心的功能)
集群将数据分散到多个节点,一方面突破了Redis单机内存大小的限制,存储容量大大增加;另一方面每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力。
Redis单机内存大小受限问题,如果单机内存太大,bgsave和bgrewriteaof的fork操作可能导致主进程阻塞,主从环境下主机切换时可能导致从节点长时间无法提供服务等。
2、高可用(集群支持主从复制和主节点的自动故障转移)
当任一节点发生故障时,集群仍然可以对外提供服务。
分片集群介绍
Redis 分片集群是一种将 Redis 数据库分散到多个节点上的方式,以提供更高的性能和可伸缩性。在分片集群中,数据被分为多个片段,每个片段存储在不同的节点上,这些节点可以是物理服务器或虚拟服务器。
Redis 分片集群的主要目的是将数据分布在多个节点上,以便可以通过并行处理来提高读写吞吐量。每个节点负责处理一部分数据,并且在需要时可以进行扩展以适应更多的负载。此外,分片集群还提供了故障容错和高可用性的功能,即使其中一个节点发生故障,其他节点仍然可以继续工作。
如何分片
Redis 通过一种称为哈希槽(hash slot)的机制来实现分片集群。哈希槽将整个数据集分成固定数量的槽,每个槽都有一个唯一的编号,通常是从 0 到 16383。
在 Redis 分片集群中,有多个节点(主节点和从节点),每个节点负责存储其中一部分的槽数据。节点之间通过集群间通信协议进行数据的交互和同步。
当一个客户端发送一个命令到 Redis 分片集群时,集群会根据命令涉及的键的哈希值将命令路由到正确的槽上。这个槽所在的节点负责处理这个命令并返回结果给客户端。
分片过程
1. 客户端发送命令到 Redis 分片集群中的任意一个节点。
2. 节点根据命令涉及的键的哈希值计算出对应的槽号。
3. 节点根据槽号确定该槽所在的节点,并将命令路由到该节点。
4. 该节点处理命令并返回结果给客户端。
当节点加入或离开集群时,Redis 分片集群会自动进行数据的重新分片和迁移,以保持数据的均衡和高可用性。
数据的重新分片和迁移
1、当一个新节点加入集群时,集群会将一部分槽从现有节点迁移到新节点上,以平衡数据负载。
2、当一个节点离开集群时,集群会将该节点负责的槽迁移到其他可用节点上,以保证数据的可用性。
通过哈希槽的机制,Redis 分片集群实现了数据的分片和自动迁移,以提供高可用性、扩展性和容错性。同时,节点间的通信和数据同步保证了集群的一致性和可用性。
分片集群结构
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
海量数据存储问题
高并发写的问题
使用分片集群可以解决上述问题
分片集群特征
1、集群中有多个master,每个master保存不同数据
2、每个master都可以有多个slave节点
3、master之间通过ping监测彼此健康状态
4、客户端请求可以访问集群任意节点,最终都会被转发到正确节点
搭建分片集群
1.集群架构
同一台虚拟机中开启6个redis实例,模拟分片集群
IP | port | role |
172.16.3.152 | 7001 | master |
172.16.3.152 | 7002 | master |
172.16.3.152 | 7003 | master |
172.16.3.152 | 8001 | slave |
172.16.3.152 | 8002 | slave |
172.16.3.152 | 8003 | slave |
2.准备实例和配置
# 进入/tmp目录
cd /tmp
# 删除旧的,避免配置干扰
rm -rf 7001 7002 7003
# 创建目录
mkdir -p 7001 7002 7003 8001 8002 8003
[root@redis tmp]# mkdir -p 7001 7002 7003 8001 8002 8003
[root@redis tmp]# ll
总用量 432
drwxr-xr-x 2 root root 6 9月 5 20:14 7001
drwxr-xr-x 2 root root 6 9月 5 20:14 7002
drwxr-xr-x 2 root root 6 9月 5 20:14 7003
drwxr-xr-x 2 root root 6 9月 5 20:14 8001
drwxr-xr-x 2 root root 6 9月 5 20:14 8002
drwxr-xr-x 2 root root 6 9月 5 20:14 8003
在/tmp目录下编辑redis.conf文件
[root@redis tmp]# cat redis.conf
# 指定端口号
port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 172.16.3.152
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log
将这个文件拷贝到每个目录下
[root@redis tmp]# echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf
cp redis.conf 7001
cp redis.conf 7002
cp redis.conf 7003
cp redis.conf 8001
cp redis.conf 8002
cp redis.conf 8003
修改每个目录下的redis.conf
[root@redis tmp]# printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
sed -i s/6379/7001/g 7001/redis.conf
sed -i s/6379/7002/g 7002/redis.conf
sed -i s/6379/7003/g 7003/redis.conf
sed -i s/6379/8001/g 8001/redis.conf
sed -i s/6379/8002/g 8002/redis.conf
sed -i s/6379/8003/g 8003/redis.conf
3.启动redis
一键启动所有服务
[root@redis tmp]# printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf
redis-server 7001/redis.conf
redis-server 7002/redis.conf
redis-server 7003/redis.conf
redis-server 8001/redis.conf
redis-server 8002/redis.conf
redis-server 8003/redis.conf
查看进程和端口号
[root@redis tmp]# ps aux|grep redis
root 17414 0.1 0.4 153996 7692 ? Ssl 20:37 0:00 redis-server 0.0.0.0:7001 [cluster]
root 17419 0.1 0.4 153996 7692 ? Ssl 20:37 0:00 redis-server 0.0.0.0:7002 [cluster]
root 17421 0.1 0.4 153996 7692 ? Ssl 20:37 0:00 redis-server 0.0.0.0:7003 [cluster]
root 17426 0.1 0.4 153996 7688 ? Ssl 20:37 0:00 redis-server 0.0.0.0:8001 [cluster]
root 17431 0.1 0.4 153996 7692 ? Ssl 20:37 0:00 redis-server 0.0.0.0:8002 [cluster]
root 17433 0.1 0.4 153996 7688 ? Ssl 20:37 0:00 redis-server 0.0.0.0:8003 [cluster]
root 17446 0.0 0.0 112824 988 pts/1 S+ 20:38 0:00 grep --color=auto redis
[root@redis tmp]# netstat -anplut|grep redis
tcp 0 0 0.0.0.0:17001 0.0.0.0:* LISTEN 17414/redis-server
tcp 0 0 0.0.0.0:17002 0.0.0.0:* LISTEN 17419/redis-server
tcp 0 0 0.0.0.0:17003 0.0.0.0:* LISTEN 17421/redis-server
tcp 0 0 0.0.0.0:18001 0.0.0.0:* LISTEN 17426/redis-server
tcp 0 0 0.0.0.0:18002 0.0.0.0:* LISTEN 17431/redis-server
tcp 0 0 0.0.0.0:18003 0.0.0.0:* LISTEN 17433/redis-server
tcp 0 0 0.0.0.0:7001 0.0.0.0:* LISTEN 17414/redis-server
tcp 0 0 0.0.0.0:7002 0.0.0.0:* LISTEN 17419/redis-server
tcp 0 0 0.0.0.0:7003 0.0.0.0:* LISTEN 17421/redis-server
tcp 0 0 0.0.0.0:8001 0.0.0.0:* LISTEN 17426/redis-server
tcp 0 0 0.0.0.0:8002 0.0.0.0:* LISTEN 17431/redis-server
tcp 0 0 0.0.0.0:8003 0.0.0.0:* LISTEN 17433/redis-server
关闭redis服务
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown
ps -aux | grep redis | awk '{print $2}' | xargs kill
4.创建集群
Redis5.0之前,集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。
# 安装依赖
yum -y install zlib ruby rubygems
gem install redis
# 进入redis的src目录
cd /tmp/redis-5.0.14 /src
# 创建集群
./redis-trib.rb create --replicas 1 172.16.3.152:7001 172.16.3.152:7002 172.16.3.152:7003 172.16.3.152:8001 172.16.3.152:8002 172.16.3.152:8003
Redis5.0之后,集群管理以及集成到了redis-cli中
[root@redis tmp]# redis-cli --help
redis-cli 5.0.14
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
-h <hostname> Server hostname (default: 127.0.0.1).
-p <port> Server port (default: 6379).
-s <socket> Server socket (overrides hostname and port).
-a <password> Password to use when connecting to the server.
You can also use the REDISCLI_AUTH environment
variable to pass this password more safely
(if both are used, this argument takes predecence).
-u <uri> Server URI.
-r <repeat> Execute specified command N times.
-i <interval> When -r is used, waits <interval> seconds per command.
It is possible to specify sub-second times like -i 0.1.
-n <db> Database number.
-x Read last argument from STDIN.
-d <delimiter> Multi-bulk delimiter in for raw formatting (default: \n).
-c Enable cluster mode (follow -ASK and -MOVED redirections).
--raw Use raw formatting for replies (default when STDOUT is
not a tty).
--no-raw Force formatted output even when STDOUT is not a tty.
--csv Output in CSV format.
--stat Print rolling stats about server: mem, clients, ...
--latency Enter a special mode continuously sampling latency.
If you use this mode in an interactive session it runs
forever displaying real-time stats. Otherwise if --raw or
--csv is specified, or if you redirect the output to a non
TTY, it samples the latency for 1 second (you can use
-i to change the interval), then produces a single output
and exits.
--latency-history Like --latency but tracking latency changes over time.
Default time interval is 15 sec. Change it using -i.
--latency-dist Shows latency as a spectrum, requires xterm 256 colors.
Default time interval is 1 sec. Change it using -i.
--lru-test <keys> Simulate a cache workload with an 80-20 distribution.
--replica Simulate a replica showing commands received from the master.
--rdb <filename> Transfer an RDB dump from remote server to local file.
--pipe Transfer raw Redis protocol from stdin to server.
--pipe-timeout <n> In --pipe mode, abort with error if after sending all data.
no reply is received within <n> seconds.
Default timeout: 30. Use 0 to wait forever.
--bigkeys Sample Redis keys looking for keys with many elements (complexity).
--memkeys Sample Redis keys looking for keys consuming a lot of memory.
--memkeys-samples <n> Sample Redis keys looking for keys consuming a lot of memory.
And define number of key elements to sample
--hotkeys Sample Redis keys looking for hot keys.
only works when maxmemory-policy is *lfu.
--scan List all keys using the SCAN command.
--pattern <pat> Useful with --scan to specify a SCAN pattern.
--intrinsic-latency <sec> Run a test to measure intrinsic system latency.
The test will run for the specified amount of seconds.
--eval <file> Send an EVAL command using the Lua script at <file>.
--ldb Used with --eval enable the Redis Lua debugger.
--ldb-sync-mode Like --ldb but uses the synchronous Lua debugger, in
this mode the server is blocked and script changes are
not rolled back from the server memory.
--cluster <command> [args...] [opts...]
Cluster Manager command and arguments (see below).
--verbose Verbose mode.
--no-auth-warning Don't show warning message when using password on command
line interface.
--help Output this help and exit.
--version Output version and exit.
Cluster Manager Commands:
Use --cluster help to list all available cluster manager commands.
Examples:
cat /etc/passwd | redis-cli -x set mypasswd
redis-cli get mypasswd
redis-cli -r 100 lpush mylist x
redis-cli -r 100 -i 1 info | grep used_memory_human:
redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3
redis-cli --scan --pattern '*:12345*'
(Note: when using --eval the comma separates KEYS[] from ARGV[] items)
When no command is given, redis-cli starts in interactive mode.
Type "help" in interactive mode for information on available commands
and settings.
[root@redis tmp]#
创建集群
redis-cli --cluster create --cluster-replicas 1 172.16.3.152:7001 172.16.3.152:7002 172.16.3.152:7003 172.16.3.152:8001 172.16.3.152:8002 172.16.3.152:8003
redis-cli --cluster # 代表集群操作命令
create # 代表是创建集群
--cluster-replicas 1 # 指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master。
[root@redis tmp]# redis-cli --cluster create --cluster-replicas 1 172.16.3.152:7001 172.16.3.152:7002 172.16.3.152:7003 172.16.3.152:8001 172.16.3.152:8002 172.16.3.152:8003
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.16.3.152:8002 to 172.16.3.152:7001
Adding replica 172.16.3.152:8003 to 172.16.3.152:7002
Adding replica 172.16.3.152:8001 to 172.16.3.152:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 924f2fa20bda219d317bb27b7cd2e29d0299a68f 172.16.3.152:7001
slots:[0-5460] (5461 slots) master
M: d08715ade7f086a705ce581a3ff9d9b3dffb64aa 172.16.3.152:7002
slots:[5461-10922] (5462 slots) master
M: 58bd479eff14eae43809aa26792295748938273d 172.16.3.152:7003
slots:[10923-16383] (5461 slots) master
S: d50b7e4c4943cc03e2469bffe8184aa54a355fac 172.16.3.152:8001
replicates 58bd479eff14eae43809aa26792295748938273d
S: 2b4e2e4443b6be6bed5c39d7ac7779d233b81d49 172.16.3.152:8002
replicates 924f2fa20bda219d317bb27b7cd2e29d0299a68f
S: 99fd8e555d589fc2d07ddf10c4446c8631712bde 172.16.3.152:8003
replicates d08715ade7f086a705ce581a3ff9d9b3dffb64aa
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 172.16.3.152:7001)
M: 924f2fa20bda219d317bb27b7cd2e29d0299a68f 172.16.3.152:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 58bd479eff14eae43809aa26792295748938273d 172.16.3.152:7003
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 99fd8e555d589fc2d07ddf10c4446c8631712bde 172.16.3.152:8003
slots: (0 slots) slave
replicates d08715ade7f086a705ce581a3ff9d9b3dffb64aa
M: d08715ade7f086a705ce581a3ff9d9b3dffb64aa 172.16.3.152:7002
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: d50b7e4c4943cc03e2469bffe8184aa54a355fac 172.16.3.152:8001
slots: (0 slots) slave
replicates 58bd479eff14eae43809aa26792295748938273d
S: 2b4e2e4443b6be6bed5c39d7ac7779d233b81d49 172.16.3.152:8002
slots: (0 slots) slave
replicates 924f2fa20bda219d317bb27b7cd2e29d0299a68f
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
查看集群状态
[root@redis redis]# redis-cli -p 7001 cluster nodes
58bd479eff14eae43809aa26792295748938273d 172.16.3.152:7003@17003 master - 0 1693918397148 3 connected 10923-16383
99fd8e555d589fc2d07ddf10c4446c8631712bde 172.16.3.152:8003@18003 slave d08715ade7f086a705ce581a3ff9d9b3dffb64aa 0 1693918396132 6 connected
924f2fa20bda219d317bb27b7cd2e29d0299a68f 172.16.3.152:7001@17001 myself,master - 0 1693918395000 1 connected 0-5460
d08715ade7f086a705ce581a3ff9d9b3dffb64aa 172.16.3.152:7002@17002 master - 0 1693918396000 2 connected 5461-10922
d50b7e4c4943cc03e2469bffe8184aa54a355fac 172.16.3.152:8001@18001 slave 58bd479eff14eae43809aa26792295748938273d 0 1693918395000 4 connected
2b4e2e4443b6be6bed5c39d7ac7779d233b81d49 172.16.3.152:8002@18002 slave 924f2fa20bda219d317bb27b7cd2e29d0299a68f 0 1693918396638 5 connected
5.测试
连接7001节点,存储一个数据
[root@redis redis]# redis-cli -p 7001
127.0.0.1:7001> ping
PONG
127.0.0.1:7001> set num 123
OK
127.0.0.1:7001> get num
"123"
127.0.0.1:7001> set a 1
(error) MOVED 15495 172.16.3.152:7003
127.0.0.1:7001>
集群操作时,需要给redis-cli加上选项 -c (启用群集模式(遵循 -ASK 和 -MOVE 重定向))
-c Enable cluster mode (follow -ASK and -MOVED redirections).
[root@redis redis]# redis-cli -c -p 7001
127.0.0.1:7001> get num
"123"
127.0.0.1:7001> set a 1
-> Redirected to slot [15495] located at 172.16.3.152:7003
OK
172.16.3.152:7003> get a
"1"