redis-集群环境搭建

Linux Redis集群搭建与集群客户端实现


Linux版本:CentOS release 6.7 (Final)

Redis版本:3.2.1


Redis已经成功安装,安装路径为/home/idata/yangfan/local/redis-3.2.1。

我们要在单台机器上搭建Redis集群,方式是通过不同的TCP端口启动多个实例,然后组成集群。


1.启动Redis多个实例

我们在Redis安装目录下创建目录cluster,并编写7000.conf~7005.conf 6个配置文件,这6个配置文件用来启动6个实例,后面将使用这6个实例组成集群。

以7000.conf为例,配置文件需要填写如下几项。 (配置文件最好用文件原来的文件,将原来的文件中的参数进行修改)


port  7000                                        //端口7000,7002,7003        

bind 10.93.84.53                                     //默认ip为127.0.0.1 需要改为其他节点机器可访问的ip 否则创建集群时无法访问对应的端口,无法创建集群

daemonize    yes                               //redis后台运行

pidfile  ./redis_7000.pid          //pidfile文件对应7000,7001,7002

cluster-enabled  yes                           //开启集群  把注释#去掉

cluster-config-file  nodes_7000.conf   //集群的配置  配置文件首次启动自动生成 7000,7001,7002

cluster-node-timeout  15000                //请求超时  默认15秒,可自行设置

appendonly  yes                           //aof日志开启  有需要就开启,它会每次写操作都记录一条日志 


启动多个实例

./src/redis-server ./cluster/7000/redis.conf

./src/redis-server ./cluster/7001/redis.conf 

./src/redis-server ./cluster/7002/redis.conf

./src/redis-server ./cluster/7003/redis.conf

./src/redis-server ./cluster/7004/redis.conf

./src/redis-server ./cluster/7005/redis.conf



启动成功后,看一下进程

ps -ef | grep redis | grep cluster


idata    15711 22329  0 18:40 pts/10   00:00:00 ./bin/redis-server 10.93.84.53:7000 [cluster]

idata    15740 22329  0 18:40 pts/10   00:00:00 ./bin/redis-server 10.93.84.53:7001 [cluster]

idata    15810 22329  0 18:40 pts/10   00:00:00 ./bin/redis-server 10.93.84.53:7002 [cluster]

idata    17023 22329  0 18:42 pts/10   00:00:00 ./bin/redis-server 10.93.84.53:7003 [cluster]

idata    17030 22329  0 18:42 pts/10   00:00:00 ./bin/redis-server 10.93.84.53:7004 [cluster]

idata    17035 22329  0 18:42 pts/10   00:00:00 ./bin/redis-server 10.93.84.53:7005 [cluster]


至此,ip=10.93.84.53机器上创建了6个实例,端口号为port=7000~7005。


Redis 3.0以上的集群方式是通过Redis安装目录下的bin/redis-trib.rb脚本搭建。

这个脚本是用Ruby编写的,尝试运行,如果打印如下,你可以跳过本文的第二部分。

idata@qa-f1502-xg01.xg01:~/yangfan/local/redis-3.2.1/bin$ ruby redis-trib.rb 

Usage: redis-trib <command> <options> <arguments ...>


  create          host1:port1 ... hostN:portN

                  --replicas <arg>

  check           host:port

  info            host:port

  fix             host:port

                  --timeout <arg>

  reshard         host:port

                  --from <arg>

                  --to <arg>

                  --slots <arg>

                  --yes

                  --timeout <arg>

                  --pipeline <arg>

  rebalance       host:port

                  --weight <arg>

                  --auto-weights

                  --use-empty-masters

                  --timeout <arg>

                  --simulate

                  --pipeline <arg>

                  --threshold <arg>

  add-node        new_host:new_port existing_host:existing_port

                  --slave

                  --master-id <arg>

  del-node        host:port node_id

  set-timeout     host:port milliseconds

  call            host:port command arg arg .. arg

  import          host:port

                  --from <arg>

                  --copy

                  --replace

  help            (show this help)


For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.


如果执行失败,那么不幸的是你的机器没有Ruby运行的环境,那么你需要安装Ruby。进入第二部分。


2.安装ruby

下面的过程都是在root权限下完成的。


1)yum安装ruby和依赖的包。

# yum -y install ruby ruby-devel rubygems rpm-build 

一般来说,这一步是能正常完成的。(会有版本问题,这里要求是2.2.2以上的 )


2)使用gem这个命令来安装redis接口(gem是ruby的一个工具包)

# gem install redis 


3)升级Ruby的版本

安装rvm,我不知道这是个什么东西,但是感觉像是Ruby的一个包管理器。

# curl -L get.rvm.io | bash -s stable 

WTF,又出问题了

气急败坏的照着他说的做(这里的数据要根据返回的数据进行执行,不是直接运行下方的代码就可以的)

gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3


重新安装rvm 

curl -L get.rvm.io | bash -s stable


接着,source环境,让rvm可用。

source /usr/local/rvm/scripts/rvm


查看Ruby可用版本

rvm list known

MRI Rubies


安装最新的rvm

rvm install 2.4.1


至此,我们升级了Ruby的版本。


4)安装gem redis接口,成功!

gem install redis


5)安装rubygems,成功!

yum install -y rubygems

至此,我们的Ruby和运行redis-trib.rb需要的环境安装完成了。 



3、Redis集群搭建

有了Ruby执行环境,可以开始将之前的6个实例组建成集群了。


ruby ./redis-trib.rb create --replicas 1 112.126.71.121:7000 112.126.71.121:7001 112.126.71.121:7002 112.126.71.121:7003 112.126.71.121:7004 112.126.71.121:7005


--replicas 1表示为集群的master节点创建1个副本。那么6个实例里,有三个master,有三个是slave。

后面跟上6个实例就好了,形式就是ip:port


4.验证集群状态

./src/redis-cli -h 127.0.0.1 -p 7000 -c




---------------------  一些原理--------------


redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。


Redis集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽(hash slot)的方式来分配的,一致性哈希对向集群中新增和删除实例的支持很好,但是哈希槽对向集群新增实例或者删除实例的话,需要额外的操作,需要手动的将slot重新平均的分配到新集群的实例中。


redis cluster 默认分配了 16384 个slot,当我们set一个key时,会用CRC16算法来取模得到所属的slot,然后将这个key分到哈希槽区间的节点上,具体算法就是:CRC16(key)%16384。


Redis 集群会把数据存在一个master节点,然后在这个master和其对应的salve之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的master节点获取数据。只有当一个master 挂掉之后,才会启动一个对应的salve节点,充当master。


需要注意的是:必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。





5、python集群客户端


以Python Redis Cluster集群的使用方式为例,简单说明一下如何使用,让大家更直观的了解一下Redis集群。


Redis集群方式与单机方式在python客户端实现上是有很大不同的。


包不同,单机依赖包redis-py,集群依赖包redis-py-cluster

对同时操作多个keys的命令(mset, mget, sinter, ...),redis-py-cluster重写StriceRedis(单机Redis操作类)了其方法,而这些方法丧失了命令的原子性。

Pipelines在集群中的表现也不同了。在单机版中,pipeline是批量batch提交redis批量执行的,但是在集群版中,是one by one提交redis执行完成直接返回,在客户端重新组合成一个列表返回。所以集群中只是看起来像是批量执行。

一些命令是会Fanout(扇形)发送到集群中各个shard中执行并汇总的,如ping,keys等。一些命令是不提倡使用(blocked),如watch,unwatch等。

我只是简单翻译了官网的一些内容,相信信息大家可以参考:


http://redis-py-cluster.readthedocs.io/en/master/commands.html


http://redis-py-cluster.readthedocs.io/en/master/limitations-and-differences.html


 


1)安装redis-py-cluster 


简单的通过pip安装redis-py-cluster包。如果安装失败,可以自助下载安装。


复制代码

# pip install redis-py-cluster     

Collecting redis-py-cluster

  Downloading redis_py_cluster-1.3.4-py2.py3-none-any.whl

Requirement already satisfied: redis>=2.10.2 in /home/idata/pythonEnv/idataPlatEnv/lib/python2.7/site-packages/redis-2.10.5-py2.7.egg (from redis-py-cluster)

Installing collected packages: redis-py-cluster

Successfully installed redis-py-cluster-1.3.4

复制代码

 


2)一个简单的demo


封装了RedisCluster操作类,实现了一些方法,其实就是做了一层封装。


封装的意义是:我喜欢对这些封装增加一些装饰器,控制异常和重试等逻辑。


复制代码

# -*- coding:utf-8 -*-


from rediscluster import StrictRedisCluster


redis_nodes = [

        {'host': '10.93.84.53', 'port': 7000},

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

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

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

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

        {'host': '10.93.84.53', 'port': 7005},

    ]



class RedisCluster(object):


    def __init__(self, redis_nodes):

        self.cluster = StrictRedisCluster(startup_nodes=redis_nodes)


    # 无差别的方法

    def set(self, name, value, ex=None, px=None, nx=False, xx=False):

        return self.cluster.set(name, value, ex, px, nx, xx)

    

    # 无差别的方法

    def get(self, name):

        return self.cluster.get(name)

    

    # 扇形发送的命令

    def cluster_info(self):

        return self.cluster.cluster_info()


    # 重写StrictRedis的方法

    def mset(self, *args, **kwargs):

        return self.cluster.mset(args, kwargs)

    

    # 重写StrictRedis的方法

    def mget(self, keys, *args):

        return self.cluster.mget(keys, args)

    

    

cluster = RedisCluster(redis_nodes)

cluster.cluster_info()





问题处理

 Node 112.126.71.121:7000 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0. Node 

 

 1.关闭所有的redis 连接

 2.删除readonly.aof ,node.config ,dump.rdb文件

 3,一般删除前两个就可以了。不行在删除第三个。