Redis之集群

一:简介

一:特点

Redis集群是一个可以在多个Redis节点之间进行数据共享的设施

Redis集群不支持那些需要同时处理多个键的Redis命令,因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,会降低Redis集群的性能

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 号哈希槽。

二:槽的计算公式

集群使用公式 CRC16(key) & 16383 计算键 key属于哪个槽。

 

三:集群运行机制

所有redis节点彼此互连(ping-pong机制),内部使用二进制协议优化传输速度和带宽

节点的fail是通过集群中超过半数的master节点检测失效时候才失效

客户端与节点之间相连,连接集群中任何一个可用的节点即可

把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key

 在redis集群中为了使得一部分节点在下线或者无法与集群大多数(majority)节点进行通讯的情况下,仍然可以正常运作,redis集群对节点使用主从复制功能,集群中的每个节点都有1至N个复制品,其中一个复制品为主节点(master),其余N-1为从节点(slave)

假设在上图中A B C三个节点中 因为某些原因A节点下线 那么redis集群将不能正常工作 因为集群找不到节点来处理0-5000的哈希槽

假如我们在创建集群之前(或者在A节点下线之前)创建了A的从节点A1 那么当A节点下线的时候 A1这个从节点会成为新的主节点 继续处理0-5000的哈希槽位 此时集群不会因为A节点的下线 导致集群无法正常使用

# 如果A1这个从节点此时也下线 那么集群仍然会失败

集群的复制特性重用了 SLAVEOF 命令的代码,所以集群节点的复制行为和SLAVEOF 命令的复制行为完全相同。

四:集群故障迁移

一:转移原理

在redis集群中,节点与节点之间会进行检查

当一个主节点下线的时候,其余主节点会检测下线的节点,并进行故障转移

换句话说,集群节点继承了线下检测以及故障转移等功能 有点类似于Sentinel的功能

因为Sentinel是一个独立的监控程序 而集群之间的下线检测以及故障转移是在节点内部完成的,其虽然功能很相似,但是运行模式并不相同,集群并没有实现Sentinel的代码

二:集群命令转发

情况一:发送到正确的节点

命令所处理的键所在的槽位正好在该节点的槽内,那么该节点就会想单机redis一样执行该命令

 情况二:发送到错误的节点

接收到命令的的节点并非处理键所在槽的节点,其会发送一个转向错误(redirection),告知客户端去那个节点处理该命令,客户端会根据错误提示信息,重新向正确的节点发送命令信息

 客户端根据转向错误 向正确的那个节点发送指令

 五:转向错误

在集群中每个节点都会告诉其余节点自己所维护的槽

 集群中每个节点都会记录0-16384这些槽位有哪些节点负责,所有节点将槽汇聚在一起,从而形成一个槽表(slot table)

节点在收到键的时候 会通过槽表查看该键位所在的槽是否在自己当前的槽范围内

1:如果在 该节点则会执行该命令

2:如果不在 则会从槽表取出正确的节点地址信息 然后发送转向错误 告诉客户端

给定 redis-trib.rb 程序的命令是 create , 这表示我们希望创建一个新的集群。

选项 --replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。

七:集群管理

redis集群搭建

Redis下载安装

下载

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

安装

yum -y install gcc gcc-c++ kernel-devel # 下载依赖
tar -zxvf redis-3.2.4.tar.gz -C /usr/loacl
cd redis-3.2.4
make
make PREFIX=/usr/local/redis install

环境变量

vim /etc/profile
export PATH="$PATH:/usr/local/redis/bin"
# 保存退出

# 让环境变量立即生效
source /etc/profile

集群搭建

拷贝文件

cd /usr/local/redis-3.2.4/src/
cp redis-trib.rb /usr/local/bin/

创建集群文件

mkdir /usr/local/redis-cluster/ 
cd /usr/local/redis-cluster/
mkdir {7000,7001,7002,7003,7004,7005}
cp redis-3.2.4/redis.conf redis-cluster/7000 # 依次复制到上述的文件夹

修改配置文件

# 其余配置文件下同
cd /usr/local/redis-cluster/7000
vim redis.conf
   84 port 7000 #端口[7000-7005]
   61 bind 0.0.0.0 #IP根据节点机器可访问IP
   128 daemonize yes #redis后台运行
   150 pidfile /var/run/redis_7000.pid #pidfile文件对应[7000-7005]
   247 dir /usr/local/redis-cluster/7000 #目录端口必须配置指定,否则无法启动
   593 appendonly yes #打开持久化

   721 cluster-enabled yes  #开启集群模式
   729 cluster-config-file nodes-7000.conf #集群的配置,配置文件首次启动自动生成
   735 cluster-node-timeout 6000 #请求超时自行设置

redis-server 7000/redis.conf # 启动redis 其余的配置文件依旧

ruby

安装

yum -y install ruby rubygems && gem install redis -v 3.2.2

创建redis集群

redis-trib.rb create --replicas 1 0.0.0.0:7000 0.0.0.0:7001 0.0.0.0:7002 0.0.0.0:7003 0.0.0.0:7004 0.0.0.0:7005 # 开启集群

启动集群

redis-cli -c -h 127.0.0.1 -p 7002

CLUSTER INFO # 查看集群信息

CLUSTER NODES # 查看集群节点

创建开机自启脚本

vim /etc/init.d/redis


#!/bin/sh
# chkconfig: 2345 80 90
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
REDISPORT1=7000
REDISPORT2=7001
REDISPORT3=7002
REDISPORT4=7003
REDISPORT5=7004
REDISPORT6=7005
EXEC=/usr/local/redis/bin/redis-server
CLIEXEC=/usr/local/redis/bin/redis-cli
PIDFILE=/var/run/redis_${REDISPORT1}.pid
CONF1="/usr/local/redis-cluster/${REDISPORT1}/redis.conf"
CONF2="/usr/local/redis-cluster/${REDISPORT2}/redis.conf"
CONF3="/usr/local/redis-cluster/${REDISPORT3}/redis.conf"
CONF4="/usr/local/redis-cluster/${REDISPORT4}/redis.conf"
CONF5="/usr/local/redis-cluster/${REDISPORT5}/redis.conf"
CONF6="/usr/local/redis-cluster/${REDISPORT6}/redis.conf"
case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis cluster server..."
                $EXEC $CONF1 &
                $EXEC $CONF2 &
                $EXEC $CONF3 &
                $EXEC $CONF4 &
                $EXEC $CONF5 &
                $EXEC $CONF6 &
                echo "启动成功..."
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT1 shutdown
                $CLIEXEC -p $REDISPORT2 shutdown
                $CLIEXEC -p $REDISPORT3 shutdown
                $CLIEXEC -p $REDISPORT4 shutdown
                $CLIEXEC -p $REDISPORT5 shutdown
                $CLIEXEC -p $REDISPORT6 shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis cluster to shutdown ..."
                    sleep 1
                done
                echo "Redis cluster stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

chmod a+x /etc/init.d/redis

chkconfig --add redis
chkconfig redis on


写数据,查看集群状态

redis-cli -c -p 7000
set foo bar
get foo

重新分片实践

cd /usr/local/redis/src/
./redis-trib.rb reshard 127.0.0.1:7000

集群状态

redis-cli -p 7000 cluster nodes | grep master

故障转移

redis-cli -p 7002 debug segfault

查看状态

redis-cli -p 7000 cluster nodes | grep master

增加新的节点

./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000

删除一个节点

redis-trib del-node ip:port '<node-id>'

# 删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点

添加一个从节点

./redis-trib.rb add-node --slave --master-id $[nodeid] 127.0.0.1:7008 127.0.0.1:7000

八:Python配置Redis集群

一:安装

pip install redis-py-cluster

二:配置文件

START_NODES =  [
     # redis的IP和端口
    {'host':'172.16.199.1','port':7000},

    {'host':'172.16.199.1','port':7001},

    {'host':'172.16.199.1','port':7002},

    {'host':'172.16.199.1','port':7003},

    {'host':'172.16.199.1','port':7004},

    {'host':'172.16.199.1','port':7005}
]

三:使用方式

from rediscluster import RedisCluster  # 导入集群类

from django.conf import settings      # 导入配置文件中的集群节点
  

def test_cluster():
    # 连接redis集群节点
    redis_cluster  = RedisCluster(startup_nodes=settings.START_NODES)
    redis_cluster.set('name','SR')
    
原文地址:https://www.cnblogs.com/SR-Program/p/12446092.html