Redis集群解决方案

redis缓存单机的时候有扩容限制以及宕机风险,在使用redis集群之后就可以解决 这两个问题。在redis3.0之后,增加了redis-cluster实现,所以当前主要依靠以 下几种方式解决集群分布式问题:

客户端分片

将分片工作放在业务程序端,程序代码根据预先设置的路由规则, 直接对多个Redis实例进行分布式访问。

代理分片

将分片工作交给专门的代理程序来做。代理程序接收到来自业务程序的数据请求, 根据路由规则,将这些请求分发给正确的Redis实例并返回给业务程序。代理分片 主要有以下两个开源组件:

  • Twemproxy
  • Codis

Redis Cluster

在这种机制下,没有中心节点(和代理模式的重要不同之处)。 所以,一切开心和不开心的事情,都将基于此而展开。

cluster相关基础

端口号

redis启动实例的时候,一般都会指定客户端连接端口,默认的是6379,这个端口主要 供客户端调用。其实启动的时候,还有另外一个端口被占用,就是当前指定的端口加上 10000,也就是1639。这个端口是在cluster集群中,用于集群中两个节点之间的通信。 注意,不能用于客户端的连接。

数据切分

想要解决将数据分布式的存储在多态机器上,就要使用按照一定的规则进行数据的拆分。 在redis中,有一个slot (槽) 的概念,将所有的存储空间分为16384个slot。存储的 时候将key进行CRC16计算之后,对16384取模,得到的结果就是数据存储的slot位置。 而slot可以存储在任意一个可以连接的服务器上,比如如果一共使用3台服务器,那么 slot可以设置分布如下:

  • Node A contains hash slots from 0 to 5500.
  • Node B contains hash slots from 5501 to 11000.
  • Node C contains hash slots from 11001 to 16383.

如果使用默认的切分方式,那么分片结果为:

  • Node A slots: 0-5460 (5461 slots)
  • Node A slots: 5461-10922 (5462 slots)
  • Node A slots: 10923-16383 (5461 slots)

主从结构

上面的数据切分解决了单台服务器上不能存储所有数据的问题,还有一个问题就是如果 集群中的任意一台服务器宕机,都会造成部分数据的丢失。想要解决数据丢失的问题, redis cluster使用了主从备份的方法。一个主服务器可以配置一个或者多个从服务器。

安装实例

安装路径

按需配置更改为自己所需路径即可:

  • 主目录:~/redis
  • redis最新源码:~/redis/redis-unstable
  • redis cluster目录:~/redis/redis-cluster

编译源码

进入目录,从github下载主干最新代码,并编译:

cd ~/redis/
git clone https://github.com/antirez/redis.git redis-unstable
cd ~/redis/redis-unstable
make
make test

编译完成之后,会在redis-unstable/src目录下生成redis-service可运行程序。 只要有此程序辅以相应的配置文件配置,就可以运行redis程序实现相关功能操作。

配置cluster

配置cluster使用到了redis-trib.rb工具,此工具需要系统安装了ruby,以及 gem中安装redis组件:

ruby -v
gem install redis

之后,创建6个实例目录,以及相关配置文件,并启动:

cd /home/redis/redis-cluster
mkdir 7000 7001 7002 7003 7004 7005
# 在这6个目录下分别创建redis.conf文件,相应端口设置为和文件夹名称一致即可:
    port 700X
    cluster-enabled yes
    cluster-config-file nodes.conf
    cluster-node-timeout 5000
    appendonly yes
    databases 1
    pidfile /home/redis/redis-cluster/700X/redis_700X.pid
    logfile /home/redis/redis-cluster/700X/redis_700X.log
    loglevel debug

# 拷贝上面编译好的redis-server到redis-cluster目录下:
cp /home/redis/redis-unstable/src/redis-server /home/redis/redis-cluster/
# 打开6个终端,分别进入6个目录,之后启动redis实例:
cd /home/redis/redis-cluster/7000/ && ../redis-server ./redis.conf
# 或者末尾添加 “&” 使用后台方式启动
cd /home/redis/redis-cluster/7000/ && ../redis-server ./redis.conf &

# 拷贝上面编译好的redis-trib.rb到redis-cluster目录下:
cp /home/redis/redis-unstable/src/redis-trib.rb /home/redis/redis-cluster/
# 启动cluster
cd /home/redis/redis-cluster
./redis-trib.rb 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

启动成功之后会有如下信息显示:

>>> 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: 84072fd637abd3e29094a653e3f25ac52d3ca798 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: 081da8052edae9a1b373569caa007733b47b50bd 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: 18c6ed2578cf04e44754ebc02ee04211f2e64cca 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: 6ea73447f79bedb8dd1fdc20791f8c168dbaa8f3 127.0.0.1:7003
   replicates 84072fd637abd3e29094a653e3f25ac52d3ca798
S: d0453790e80fbbf41a7296d2a005066b5b72c171 127.0.0.1:7004
   replicates 081da8052edae9a1b373569caa007733b47b50bd
S: 73236ac83b7f3d1696c072027fd1b24fd4eedbc0 127.0.0.1:7005
   replicates 18c6ed2578cf04e44754ebc02ee04211f2e64cca
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: 84072fd637abd3e29094a653e3f25ac52d3ca798 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 6ea73447f79bedb8dd1fdc20791f8c168dbaa8f3 127.0.0.1:7003
   slots: (0 slots) slave
   replicates 84072fd637abd3e29094a653e3f25ac52d3ca798
S: 73236ac83b7f3d1696c072027fd1b24fd4eedbc0 127.0.0.1:7005
   slots: (0 slots) slave
   replicates 18c6ed2578cf04e44754ebc02ee04211f2e64cca
M: 081da8052edae9a1b373569caa007733b47b50bd 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: d0453790e80fbbf41a7296d2a005066b5b72c171 127.0.0.1:7004
   slots: (0 slots) slave
   replicates 081da8052edae9a1b373569caa007733b47b50bd
M: 18c6ed2578cf04e44754ebc02ee04211f2e64cca 127.0.0.1:7002
   slots:10923-16383 (5461 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.

如果出现如上信息,则表示 cluster 启动完成。

cluster测试

使用redis-cli测试客户端,也是从编译好的目录中拷贝到cluster目录,比较清晰:

# 拷贝测试客户端
cp /home/redis/redis-unstable/src/redis-cli /home/redis/redis-cluster/
cd /home/redis/redis-cluster/

# 启动
redis-cli -c -p 7000

测试具体操作

redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
redis 127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
redis 127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
"bar"
redis 127.0.0.1:7000> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
"world"

可以看出,redis集群操作已经生效。集群节点的增加和删除,以及相关的rehash操作 后面继续处理。

参考资料