Redis集群安装

1        简介:

1.1   redis cluster介绍

1):节点自动发现 

2):slave->master 选举,集群容错

3):Hot resharding:在线分片

4):进群管理:cluster xxx 

5):基于配置(nodes-port.conf)的集群管理

6):ASK 转向/MOVED 转向机制

1.2   redis-cluster

1.2.1   redis cluster架构图

 

1.2.2   架构细节: 

1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽. 

2)节点的fail是通过集群中超过半数的节点检测失效时才生效. 

3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可 

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

1.2.3   redis-cluster选举:容错

 

 

 
   


(1)领着选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉. 

(2):什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误    

       a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.     

       b:如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态

2        Redis集群安装

要让集群正常工作至少需要3个主节点,在这里我们要创建6个redis节点,其中三个为主节点,三个为从节点,对应的redis节点的ip和端口对应关系如下

192.168.1.137:7000 、192.168.1.137:7001 

192.168.1.138:7000 、192.168.1.138:7001 

192.168.1.139:7000 、192.168.1.139:7001 

2.1    Ruby安装

 

安装gem 需要ruby的版本在 1.8.7 以上,默认的centos5 上都是1.8.5 版本,所以首先你的升级你的ruby

运行命令:yum install ruby

检查:ruby -v

 

 
   


显示ruby版本为1.8.7,标识安装成功

2.2    Rubygems安装

如果提示缺少rubygems组件,使用yum安装   

错误内容: 

./redis-trib.rb:24:in `require': no such file to load -- rubygems (LoadError) from ./redis-trib.rb:24 yum install rubygems 

安装命令:yum install rubygems,

检测是否安装成功:rpm -qa|grep ruby

 

2.3    gem install redis安装

如果提示不能加载redis,是因为缺少redis和ruby的接口,使用gem 安装 

错误内容: 

/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- redis (LoadError) 

from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require' from ./redis-trib.rb:25,则需要使用gem安装ruby接口,

安装命令

 
   


:gem install redis

 

2.4    tcl安装

对于编译文件需要安装测试,需要tcl工具包,

下载:wget http://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gz 

安装:sudo tar xzvf tcl8.6.1-src.tar.gz  -C /usr/local/ 

  cd  /usr/local/tcl8.6.1/unix/ 

  sudo ./configure 

  sudo make 

      sudo make install

2.5    服务器准备

要让集群正常工作至少需要3个主节点,在这里我们要创建6个redis节点,其中三个为主节点,三个为从节点,对应的redis节点的ip和端口对应关系如下

192.168.1.137:6379,192.168.1.137:6380

192.168.1.138:6379,192.168.1.138:6380

192.168.1.139:6379,192.168.1.139:6380

 

2.6    Redis安装

安装以上几个redis依赖的包后,就可以安装redis了。

1:下载

首先从官方网站下载redis,我下载的是redis-3.0.6.tar.gz

下载地址:http://download.redis.io/releases/redis-3.0.6.tar.gz

2:解压编译

tar xzf redis-3.0.6.tar.gz

cd redis-3.0.6

make

cd src & make test(检查,必须安装tcl)

make install

 

3:其他配置

     安装完之后,会在src目录下生成几个可执行文件,分别是

              mkreleasehdr.sh、redis-benchmark、redis-check-aof

              redis-check-dump、redis-cli、redis-sentinel、redis-server。

       其中redis-server是启动Redis服务的,redis-cli是进入Redis客户端的。

为了方便起见,我们将src下的可执行命令全部移动到/usr/local/redis/bin/目录下

2.7    Redis参数配置

#Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程

daemonize yes

 

#当 Redis 以守护进程的方式运行的时候,Redis 默认会把 pid 文件放在/var/run/redis.pid

#可配置到其他地址,当运行多个 redis 服务时,需要指定不同的 pid 文件和端口

pidfile /data/redis/redis_6379.pid

 

#端口,默认为6379

port 6379

 

#指定Redis可接收请求的IP地址,不设置将处理所有请求,建议生产环境中设置

# bind 127.0.0.1

 

#客户端连接的超时时间,单位为秒,超时后会关闭连接,0标识不超时

timeout 0

 

# debug (适合开发和测试)、# verbose (详细)、# notice (比较适合生产环境)、# warning (警告信息)

#日志记录等级,4个可选值

loglevel notice

 

#配置 log 文件地址,默认打印在命令行终端的窗口上,也可设为/dev/null屏蔽日志、

logfile stdout

 

#设置数据库的个数,可以使用 SELECT 命令来切换数据库,默认为0。

databases 16

 

#设置 Redis 自动进行数据库镜像的频率。保存数据到disk的策略,不设置认为自动不保存

#900秒之内有1个keys发生变化时

#30秒之内有10个keys发生变化时

#60秒之内有10000个keys发生变化时

save 900 1

save 300 10

save 60 10000

 

#在进行镜像备份时,是否进行压缩,默认为yes

rdbcompression yes

 

#镜像备份文件的文件名

dbfilename dump.rdb

 

#数据库镜像备份的文件放置的路径

#路径跟文件名分开配置是因为 Redis 备份时,先会将当前数据库的状态写入到临时文件

#等备份完成时,再把该临时文件替换为上面所指定的文件

#而临时文件和上面所配置的备份文件都会放在这个指定的路径当中

#默认值为 ./

dir /var/lib/redis/

 

# 使用slaveof把一个 Redis 实例设置成为另一个Redis server的从库(热备). 注意: #配置只对当前slave有效# slaveof

# slaveof <masterip> <masterport>

 

#指定与主数据库连接时需要的密码验证,当本机为从服务时,设置主服务的连接密码

# masterauth <master-password>

 

#当slave丢失与master的连接时,或slave仍然在于master进行数据同步时(未与master保持一致)

#slave可有两种方式来响应客户端请求:

#1)如果 slave-serve-stale-data 设置成 'yes'(默认),slave仍会响应客户端请求,此时可能会有问题

#2)如果 slave-serve-stale-data 设置成 'no',slave会返回"SYNC with master in progress"错误信息,但 INFO 和SLAVEOF命令除外。

slave-serve-stale-data yes

 

#设置客户端连接后进行任何其他指定前需要使用的密码

#redis速度相当快,一个外部用户在一秒钟进行150K次密码尝试,需指定强大的密码来防止暴力破解

# requirepass foobared

 

命令重命名.

# 例如:

# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52

# 同样可以通过把一个命令重命名为空串来彻底kill掉这个命令,比如:

# rename-command CONFIG ""

 

#限制同时连接的客户数量。

#当连接数超过这个值时,redis 将不再接收其他连接请求,客户端尝试连接时将收到 error 信息,默认没有限制,  '0' 意味着不限制

# maxclients 128

 

#设置redis能够使用的最大内存。

#达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key(设置过expire信息的key)

#在删除时,按照过期时间进行删除,最早将要被过期的key将最先被删除

#如果已到期或即将到期的key删光,仍进行set操作,那么将返回错误

#此时redis将不再接收写请求,只接收get请求。

#maxmemory的设置比较适合于把redis当作于类似memcached 的缓存来使用

#警告:如果你想把Redis视为一个真正的DB的话,那不要设置<maxmemory>,只有你只想  把Redis作为cache或者有状态的server('state' server)时才需要设置。

 

# maxmemory <bytes>

 

内存清理策略:如果达到了maxmemory,你可以采取如下动作:

# volatile-lru -> 使用LRU算法来删除过期的set

# allkeys-lru -> 删除任何遵循LRU算法的key

# volatile-random ->随机地删除过期set中的key

# allkeys->random -> 随机地删除一个key

# volatile-ttl -> 删除最近即将过期的key(the nearest expire time (minor TTL))

# noeviction -> 根本不过期,写操作直接报错

# 默认策略:

# maxmemory-policy volatile-lru

 

# 对于处理redis内存来说,LRU和minor TTL算法不是精确的,而是近似的(估计的)算

法。所以我们会检查某些样本#来达到内存检查的目的。默认的样本数是3,你可以修改它。

# maxmemory-samples 3

 

 

#redis 默认每次更新操作后会在后台异步的把数据库镜像备份到磁盘,但该备份非常耗时,且备份不宜太频繁

#redis 同步数据文件是按上面save条件来同步的

#如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失

#所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式

#开启append only 模式后,redis 将每一次写操作请求都追加到appendonly.aof 文件中

#redis重新启动时,会从该文件恢复出之前的状态。

#但可能会造成 appendonly.aof 文件过大,所以redis支持BGREWRITEAOF 指令,对appendonly.aof重新整理

appendonly no

 

# The name of the append only file (default: "appendonly.aof")

##更新日志文件名,默认值为appendonly.aof

# appendfilename appendonly.aof

 

#调用fsync()函数通知系统立刻向硬盘写数据设置对 appendonly.aof 文件进行同步的频率

#always 表示每次有写操作都进行同步,性能差,但很安全

#everysec 表示对写操作进行累积,每秒同步一次,折中。

#no只是通知OS可以flush数据了,具体是否flush取决于OS.性能更好

#系统默认为everysec

# appendfsync always

appendfsync everysec

# appendfsync no

 

#是否开启虚拟内存支持。

#redis 是一个内存数据库,当内存满时,无法接收新的写请求,所以在redis2.0后,提供了虚拟内存的支持

#但需要注意的,redis 所有的key都会放在内存中,在内存不够时,只把value 值放入交换区

#虽使用虚拟内存,但性能基本不受影响,需要注意的是要把vm-max-memory设置到足够来放下所有的key,

Redis官方文档对VM的使用提出了一些建议:

当key很小而value很大时,使用VM的效果会比较好.因为这样节约的内存比较大

当key不小时,可以考虑使用一些非常方法将很大的key变成很大的value,如可将key,value组合成一个新的value

但是使用redis 就别用虚拟内存了,绝对不是一个好主意

vm-enabled no

# vm-enabled yes

 

#设置虚拟内存的交换文件路径,不可多个Redis实例共享

vm-swap-file /tmp/redis.swap

 

#设置开启虚拟内存后,redis将使用的最大物理内存大小。

#默认为0,redis将把他所有能放到交换文件的都放到交换文件中,以尽量少的使用物理内存

#即当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘

#在生产环境下,需要根据实际情况设置该值,最好不要使用默认的 0

vm-max-memory 0

 

#设置虚拟内存的页大小

如果 value 值比较大,如要在 value 中放置博客、新闻之类的所有文章内容,就设大一点

vm-page-size 32

 

#设置交换文件的总的 page 数量

#注意page table信息是放在物理内存中,每8个page 就会占据RAM中的 1 个 byte

#总的虚拟内存大小 = vm-page-size * vm-pages

vm-pages 134217728

 

#设置 VM IO 同时使用的线程数量。

vm-max-threads 4

 

#redis 2.0后引入了 hash 数据结构。

#hash 中包含超过指定元素个数并且最大的元素当没有超过临界时,hash 将以zipmap来存储

#zipmap又称为 small hash,可大大减少内存的使用

hash-max-zipmap-entries 512

hash-max-zipmap-value 64

 

#是否重置Hash表

#设置成yes后redis将每100毫秒使用1毫秒CPU时间来对redis的hash表重新hash,可降低内存的使用

#当使用场景有较为严格的实时性需求,不能接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。

#如果没有这么严格的实时性要求,可以设置为 yes,以便能够尽可能快的释放内存

activerehashing yes

 

最好使用linux ext3 等对稀疏文件支持比较好的文件系统保存你的swap文件

 

# Redis slow log用来记录超过指定执行时间的查询。

# 你可以指定两个参数:一个是慢查询的阀值,单位是毫秒;另外一个是slow log的长度,相当于一个队列。

 # 负数则关闭slow log,0则会导致每个命令都被记录

slowlog-log-slower-than 10000

no-appendfsync-on-rewrite no

 

# append only 文件的自动重写

# 当AOF 日志文件即将增长到指定百分比时,Redis可以通过调用BGREWRITEAOF 来自动重写append only文件。

# 它是这么干的:Redis会记住最近一次重写后的AOF 文件size。然后它会把这个size与当前size进行比较,如果当前# size比指定的百分比大,就会触发重写。同样,你需要指定AOF文件被重写的最小size,这对避免虽然百分比达到了# 但是实际上文件size还是很小(这种情况没有必要重写)却导致AOF文件重写的情况很有用。

# auto-aof-rewrite-percentage 设置为 0 可以关闭AOF重写功能

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

 

2.8    Redis单机启动、关闭、重启

bin/redis-server conf/redis.6379.conf

bin/redis-cli shutdown

 

2.9    Redis单机效率测试

bin/redis-benchmark -n 10000 -h 192.168.1.130 -p 6379

 

 
   

 

bin/redis-benchmark -h 192.168.1.130 -p 6379 -t set,lpush -n 10000 -q

 

 
   

 

2.10      Redis集群启动

首先将所有的redis实例一个个启动,如下:

137:

bin/redis-server conf/redis.6379.conf

bin/redis-server conf/redis.6380.conf

138:

bin/redis-server conf/redis.6379.conf

bin/redis-server conf/redis.6380.conf

139:

bin/redis-server conf/redis.6379.conf

bin/redis-server conf/redis.6380.conf

检查redis启动情况:

ps -ef|grep redis

 

 
   

 

检查所有实例都启动完成后,可以启动redis集群,命令如下:

bin/redis-trib.rb create --replicas 1 192.168.1.138:6379 192.168.1.138:6380

192.168.1.137:6379 192.138.1.137:6380 192.168.1.139:6379 192.168.1.139:6380

然后根据提示,输入yes,具体日志信息如下截图所示:

(--replicas 则指定了为Redis Cluster中的每个Master节点配备几个Slave节点,我们的参数中设置为1,因此每个master上有1个slave节点)

 

 

 

 

 

 
   

 

Redis集群为三主三从,分别如下:

139:6379为master,137:6380为slave

137:6379为master,139:6380为slave

138:6380为master,139:6379为slave

 

 

 

 

 

3        Redis集群测试

3.1    客户端启动

选中一台服务器,然后启动命名

bin/redis-cli -c -p 6379

 

 
   

 

3.2    客户端测试

分别输入命令:set hello world、set whoareyou sunshine,设置两个数据,如下所示

 

 
   

 

set hello时,值定位到139服务器上

set whoareyou是,value定位到137服务器上

get hello时,从139机器上取值

get whoareyou时,从137上取值

 

3.3    分布式算法规则

Redis Cluster使用的分布式算法也很简单:crc16( key ) % HASH_SLOTS_NUMBER

 

3.4    Redis集群检测

./redis-trib.rb check 127.0.0.1:6379

3.5    Redis节点管理

3.5.1    添加新master节点 

添加一个master节点:创建一个空节点(empty node),然后将某些slot移动到这个空节点上,这个过程目前需要人工干预 

a):根据端口生成配置文件(ps:establish_config.sh是我自己写的输出配置脚本,也可自己配置),

       sh establish_config.sh 6386 > conf/redis-6386.conf

b):启动节点    

   nohup redis-server /opt/redis/conf/redis-6386.conf > /opt/redis/logs/redis-6386.log 2>&1 &     

c):加入空节点到集群  add-node  将一个节点添加到集群里面, 第一个是新节点ip:port, 第

二个是任意一个已存在节点ip:port    

       redis-trib.rb add-node 10.10.34.14:6386 10.10.34.14:6381     

       node:新节点没有包含任何数据, 因为它没有包含任何slot。

       新加入的节点是一个主节点, 当集群需要将某个从节点升级为新的主节点时, 这个新

节点不会被选中 

d):为新节点分配slot    

              redis-trib.rb reshard 10.10.34.14:6386   

              #根据提示选择要迁移的slot数量(ps:这里选择500)  

              How many slots do you want to move (from 1 to 16384)? 500  

              #选择要接受这些slot的node-id   

              What is the receiving node ID? f51e26b5d5ff74f85341f06f28f125b7254e61bf  

              #选择slot来源:   

              #all表示从所有的master重新分配,   

              #或者数据要提取slot的master节点id,最后用done结束  

              Please enter all the source node IDs.     

              Type 'all' to use all the nodes as source nodes for the hash slots

              Type 'done' once you entered all the source nodes IDs.   Source node #1:all   

              #打印被移动的slot后,输入yes开始移动slot以及对应的数据.  

              #Do you want to proceed with the proposed reshard plan (yes/no)? yes  

              #结束   

3.5.2     添加新的slave节点

a):根据端口生成配置文件(ps:establish_config.sh是我自己写的输出配置脚本,也可自己配置),

       sh establish_config.sh 6386 > conf/redis-6386.conf

b):启动节点    

   nohup redis-server /opt/redis/conf/redis-6386.conf > /opt/redis/logs/redis-6386.log 2>&1 &     

c):加入空节点到集群  add-node  将一个节点添加到集群里面, 第一个是新节点ip:port, 第

二个是任意一个已存在节点ip:port    

       redis-trib.rb add-node 10.10.34.14:6386 10.10.34.14:6381     

       node:新节点没有包含任何数据, 因为它没有包含任何slot。

       新加入的节点是一个主节点, 当集群需要将某个从节点升级为新的主节点时, 这个新

节点不会被选中

b):第四步:redis-cli连接上新节点shell,输入命令:cluster replicate 对应master的node-id     

       cluster replicate 2b9ebcbd627ff0fd7a7bbcc5332fb09e72788835     

       note:在线添加slave 时,需要dump整个master进程,并传递到slave,再由 slave加载                rdb文件到内存,rdb传输过程中Master可能无法提供服务,整个过程消耗大量io,小心操                 作. 例如本次添加slave操作产生的rdb文件    

              -rw-r--r-- 1 root root  34946 Apr 17 18:23 dump-6386.rdb  

              -rw-r--r-- 1 root root  34946 Apr 17 18:23 dump-7386.rdb     

3.5.3     在线reshard 数据: 

对于负载/数据均匀的情况,可以在线reshard slot来解决,方法与添加新master的reshard一样,只是需要reshard的master节点是老节点.

3.5.4     删除一个slave节点

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

redis-trib.rb  del-node  10.10.34.14:7386  'c7ee2fca17cb79fe3c9822ced1d4f6c5e169e378'   

3.5.5     删除一个master节点   

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

  (目前只能把被删除 master的slot迁移到一个节点上)    

#把10.10.34.14:6386当前master迁移到10.10.34.14:6380上  

       redis-trib.rb reshard 10.10.34.14:6380   

       #根据提示选择要迁移的slot数量(ps:这里选择500)   

       How many slots do you want to move (from 1 to 16384)? 500

    #(被删除master的所有slot数量)   

       #选择要接受这些slot的node-id(10.10.34.14:6380)   

       What is the receiving node ID? c4a31c852f81686f6ed8bcd6d1b13accdc947fd2

#(ps:10.10.34.14:6380的node-id)  

       Please enter all the source node IDs.     

       Type 'all' to use all the nodes as source nodes for the hash slots.    

       Type 'done' once you entered all the source nodes IDs.   

       Source node #1:f51e26b5d5ff74f85341f06f28f125b7254e61bf(被删除master的node-id)   

#Source node #2:done   

       #打印被移动的slot后,输入yes开始移动slot以及对应的数据.  

       #Do you want to proceed with the proposed reshard plan (yes/no)? yes     

b):删除空master节点

       redis-trib.rb del-node 10.10.34.14:6386  'f51e26b5d5ff74f85341f06f28f125b7254e61bf'

4        JAVA客户端测试

4.1.1     普通同步方式

 

参看:http://note.youdao.com/web/file/recent/note/WEB044cb73537f4f53faa76c62c5dcd929b

 

 

 

5        可视化管理工具

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6        redis常用命令

常用监控命令:

链接上redis节点后,输入命令:monitor,即可监控集群中redis的访问命令

 

 
   

 

 

 

redis常用命令可以参考:

http://www.yiibai.com/redis/redis_partitioning.html

http://www.redis.cn/commands.html

 

7        redis可靠性验证

当主节点宕机是,从节点会自动升级为主节点,对外提供服务,

当主从节点全部宕机是,改集群将不可用,数据也不会同步至其他节点