环境:centos6.5 x86 32位 redis3.2.8 ruby-2.2.3
一. redis集群原理
redis是单线程,但是一般的作为缓存使用的话,redis足够了,因为它的读写速度太快了。
官方的一个简单测试:
测试完成了50个并发执行100000个请求。
设置和获取的值是一个256字节字符串。
结果:读的速度是110000次/s,写的速度是81000次/s
在这么快的读写速度下,对于一般程序来说足够用了,但是对于访问量特别大的网站来说,还是稍有不足。
那么,如何提升redis的性能呢?看标题就知道了,搭建集群。
先来一张redis集群的架构图:
在这个图中,每一个蓝色的圈都代表着一个redis的服务器节点。
它们任何两个节点之间都是相互连通的。客户端可以与任何一个节点相连接,
然后就可以访问集群中的任何一个节点。对其进行存取和其他操作。
那么redis是怎么做到的呢?首先,在redis的每一个节点上,都有这么两个东西,一个是插槽(slot)可以理解为是一个可以存储两个数值的一个变量。
这个变量的取值范围是:0-16383。还有一个就是cluster我个人把这个cluster理解为是一个集群管理的插件。当我们的存取的key到达的时候,
redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,
通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。
还有就是因为如果集群的话,是有好多个redis一起工作的,那么,就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务。
这个备用的redis称为从节点(slave)。那么这个集群是如何判断是否有某个节点挂掉了呢?
首先要说的是,每一个节点都存有这个集群所有主节点以及从节点的信息。
它们之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了,
然后去连接它的备用节点。如果某个节点和所有从节点全部挂掉,我们集群就进入faill状态。还有就是如果有一半以上的主节点宕机,那么我们集群同样进入发力了状态。
这就是我们的redis的投票机制,具体原理如下图所示:
(1)投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超时(cluster-node-timeout),认为当前master节点挂掉.
(2):什么时候整个集群不可用(cluster_state:fail)?
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完整时进入fail状态.
ps : redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.
b:如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态.
二 . 集群安装配置
2.1 安装配置redis
此步省略,请参考我到博文【http://blog.csdn.net/wx5040257/article/details/78347729】【http://blog.csdn.net/wx5040257/article/details/78388588】
我准备的服务器ip及各服务器角色如下图所示:
各节点间互联互通,master和slave由创建集群时确定。
2.2 安装cluster依赖环境
只需在任意一台主机上(如169.254.130.122)安装即可。
先按照Ruby,注意,不要用yum命令安装,yum命令安装的版本较低,后续步骤会报错,如图:
建议进行源码安装。
2.2.1 安装ruby
解压缩源码包,并移动到/usr/local/src目录下
tar -zxf
mv ruby-2.2.3 /usr/local/src/ruby
进入源码目录进行安装
cd /usr/local/src/ruby
./configure
make && make install
安装完毕后如图所示:
提示系统缺失zlib,可能后续还要安装zlib包,请继续往下看。可用ruby -v命令查看安装成功的ruby版本。
2.2.2 安装ruby redis接口
gem install redis
报错,如图所示:
解决方案,安装zlib-dev,yum命令安装即可
yum -y install zlib-devel
然后进入ruby源码文件夹
安装ruby自身提供的zlib包
#cd ext/zlib
#ruby ./extconf.rb
#make
#make install
接下来再执行
gem install redis
又报错,如下所示:
[root@localhost zlib]# gem install redis
ERROR: While executing gem ... (Gem::Exception)
Unable to require openssl, install OpenSSL and rebuild ruby (preferred) or use non-HTTPS sources
原因:
缺少openssl,需要安装openssl包,我现在这里来安装一个openssl-1.0.1s.tar.gz(下载链接:http://www.openssl.org/source/)
解决方法步骤:
1.解压在/usr/local/src目录下,进入/usr/local/src/openssl目录准备安装:
[root@localhost src]# cd /usr/local/src/openssl
[root@localhost openssl]# ./config -fPIC --prefix=/usr/local/openssl enable-shared
[root@localhost openssl]# ./config -t
[root@localhost openssl]# make && make install
openssl的配置文件必须要配置-fPIC参数,如果没有该参数下面的安装中会出现问题!
安装完成,可以检测一下是否安装成功:
[root@localhost openssl]# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
2.进入ruby源码[/usr/local/src/ruby]目录下的ext/openssl 目录:
[root@localhost openssl]# cd ../ruby-2.3.0
[root@localhost ruby]# cd ext/openssl
[root@localhost openssl]# ruby extconf.rb
checking for t_open() in -lnsl... no
checking for socket() in -lsocket... no
checking for assert.h... yes
checking for openssl/ssl.h... no
提示没有找到ssl.h, 因为出现了错误:openssl/ssl.h … no ,输入如下代码,重新执行:
# ruby extconf.rb --with-openssl-include=/usr/local/openssl/include/ --with-openssl-lib=/usr/local/openssl/lib
checking for EVP_CIPHER_CTX.engine in openssl/evp.h... yes
checking for X509_ATTRIBUTE.single in openssl/x509.h... yes
checking for OPENSSL_FIPS in openssl/opensslconf.h... no
checking for EVP_CTRL_GCM_GET_TAG in openssl/evp.h... yes
creating extconf.h
creating Makefile
[root@localhost openssl]#
ok,成功
3.接下来并且将ruby 源码目录下的include目录软链接到 / 目录下:
ln -s /usr/local/src/ruby/include /
注意:创建软链的时候一定要写全路径,不能写相对路径
- 接下来,继续在ext/openssl 目录下执行:
[root@localhost openssl]# pwd
/usr/local/src/ruby/ext/openssl
[root@localhost openssl]# make && make install
再次使用gem install 安装 ruby redis 接口:
gem install redis
仍然报错:
[root@localhost openssl]# gem install redis
ERROR: Could not find a valid gem 'redis' (>= 0), here is why:
Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
意思上无法自动下载rubygems安装,那好吧,我们自己下载安装,例如我下载的是:redis-3.2.1.gem
[root@localhost soft]# gem install redis-3.2.1.gem
Successfully installed redis-3.2.1
Parsing documentation for redis-3.2.1
Installing ri documentation for redis-3.2.1
Done installing documentation for redis after 1 seconds
WARNING: Unable to pull data from 'https://rubygems.org/': SSL_connect returned=1 errno=0 state=error: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)
1 gem installed
ok,安装成功了!
2.3 接下来进行集群的创建
- 在各节点进行集群配置,如图:
vi /usr/redis/redis.conf
cluster-enabled yes ==>表示开启集群功能
cluster-config-file nodes-6379.conf ====>表示自动生成的集群配置文件
cluster-node-timeout 15000====> 表示集群节点连接超时时间
- 创建集群
创建集群环境的命令格式为redis-trib.rb create --replicas masterNode1,masterNode2,masterNodeN,slaveNode1,slaveNode2,slaveNodeN
Node的格式为"IP:port",slaveCount表示每个masterNode对应的slaveNode个数,在集群环境中可以没有slave(在命令中省略掉slaveNode部分即可)。
但如果有slave,则命令中,前n中个节点都为master,后n个节点都为slave,第n个master节点对应的slave应该是第n个。
注意:创建集群前,每个节点到数据都要清空,用flushall命令
127.0.0.1:6379 > flushall
执行命令创建集群:
redis-trib.rb create --replicas 1 169.254.130.122:6379 169.254.130.10:6379 169.254.130.20:6379
169.254.130.12:6379 169.254.130.11:6379 169.254.130.25:6379
注意:这条命令没有跨行
出现如下提示信息:
--------------------------------------------------------------------
注:如果你对python感兴趣,我这有个学习Python基地,里面有很多学习资料,感兴趣的+Q群:895817687
--------------------------------------------------------------------
Creating cluster
Performing hash slots allocation on 6 nodes...
Using 3 masters:
169.254.130.122:6379
169.254.130.10:6379
169.254.130.20:6379
Adding replica 169.254.130.12:6379 to 169.254.130.122:6379
Adding replica 169.254.130.11:6379 to 169.254.130.10:6379
Adding replica 169.254.130.25:6379 to 169.254.130.20:6379
M: 89d0ca92c42dfd6fa8cd2286099a331687cc3620 169.254.130.122:6379
slots:0-5460,9189 (5462 slots) master
M: b5d5a4a43778b7fdb64520538ace4a3a258b552a 169.254.130.10:6379
slots:5461-10922 (5462 slots) master
M: daf3d1fa25405ae834db58d071f9b9a5165125ba 169.254.130.20:6379
slots:312,700,741,2076,2880,4377,4576,7141,8931,8975,9189,10780,10923-16383 (5473 slots) master
S: c79959320e43ea0884d6f5914ead5198cd3d3f22 169.254.130.12:6379
replicates 89d0ca92c42dfd6fa8cd2286099a331687cc3620
S: 8a38aee74310f5aeffbcabdc676f64853acf77d5 169.254.130.11:6379
replicates b5d5a4a43778b7fdb64520538ace4a3a258b552a
S: a3b0e2a4ce8c4df395506942163f21db39ae9fb3 169.254.130.25:6379
replicates daf3d1fa25405ae834db58d071f9b9a5165125ba
Can I set the above configuration? (type 'yes' to accept):
从上面可看出,六个节点都处于"OK"状态,并且前三个6379端口的都为master,而都三个6379端口的都为slave。
此时出现提示,键入yes后,各节点将会进行互联操作
输入yes,接下来报错了:
Can I set the above configuration? (type 'yes' to accept): yes
/usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis/client.rb:113:in `call': ERR Slot 4788 is already busy (Redis::CommandError)
from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:2556:in `block in method_missing'
from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:37:in `block in synchronize'
from /usr/local/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
from /usr/local/lib/ruby/gems/2.2.0/gems/redis-3.2.1/lib/redis.rb:2555:in `method_missing'
from /usr/redis/src/redis-trib.rb:212:in `flush_node_config'
from /usr/redis/src/redis-trib.rb:776:in `block in flush_nodes_config'
from /usr/redis/src/redis-trib.rb:775:in `each'
from /usr/redis/src/redis-trib.rb:775:in `flush_nodes_config'
from /usr/redis/src/redis-trib.rb:1296:in `create_cluster_cmd'
from /usr/redis/src/redis-trib.rb:1701:in `<main>'
错误提示是
slot插槽被占用了(这是 搭建集群前时,以前redis的旧数据和配置信息没有清理干净。)
解决方案是
用redis-cli 登录到每个节点执行 flushall 和 cluster reset 就可以了。
然后重新执行创建集群的命令:
redis-trib.rb create --replicas 1 169.254.130.122:6379 169.254.130.10:6379 …(省略)
接下来又卡住了,如下:
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........................................................................
.......................................................................................................
....................................................................................
原因:
redis集群不仅需要开通redis客户端连接的端口,而且需要开通集群总线端口
集群总线端口为redis客户端连接的端口 + 10000
如redis端口为6379
则集群总线端口为16379
故,所有服务器的点需要开通redis的客户端连接端口和集群总线端口
注意:iptables 放开,如果有安全组,也要放开这两个端口
受不了啦,把所有节点的防火墙全部关闭算了。重新执行创建集群的命令,这回成功了:
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
2210:M 04 Nov 04:02:59.467 # IP address for this node updated to 169.254.130.122
Waiting for the cluster to join.
>>> Performing Cluster Check (using node 169.254.130.122:6379)
M: 89d0ca92c42dfd6fa8cd2286099a331687cc3620 169.254.130.122:6379
slots:0-5460 (5461 slots) master
1 additional replica(s)
S: 8a38aee74310f5aeffbcabdc676f64853acf77d5 169.254.130.11:6379
slots: (0 slots) slave
replicates b5d5a4a43778b7fdb64520538ace4a3a258b552a
M: daf3d1fa25405ae834db58d071f9b9a5165125ba 169.254.130.20:6379
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: b5d5a4a43778b7fdb64520538ace4a3a258b552a 169.254.130.10:6379
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: a3b0e2a4ce8c4df395506942163f21db39ae9fb3 169.254.130.25:6379
slots: (0 slots) slave
replicates daf3d1fa25405ae834db58d071f9b9a5165125ba
S: c79959320e43ea0884d6f5914ead5198cd3d3f22 169.254.130.12:6379
slots: (0 slots) slave
replicates 89d0ca92c42dfd6fa8cd2286099a331687cc3620
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost redis]# 2210:M 04 Nov 04:03:02.322 * Slave 169.254.130.12:6379 asks for synchronization
2210:M 04 Nov 04:03:02.322 * Full resync requested by slave 169.254.130.12:6379
2210:M 04 Nov 04:03:02.322 * Starting BGSAVE for SYNC with target: disk
2210:M 04 Nov 04:03:02.326 * Background saving started by pid 2502
2502:C 04 Nov 04:03:02.347 * DB saved on disk
2502:C 04 Nov 04:03:02.348 * RDB: 0 MB of memory used by copy-on-write
2210:M 04 Nov 04:03:02.352 * Background saving terminated with success
2210:M 04 Nov 04:03:02.352 * Synchronization with slave 169.254.130.12:6379 succeeded
2210:M 04 Nov 04:03:04.371 # Cluster state changed: ok
从上面可看出16384个哈希槽已均匀分配给了三个master节点,分别为:
169.254.130.20:6379(10923-16384)
169.254.130.10:6379(5461-10922)
169.254.130.122:6379(0-5460)
大功告成!!!
2.5 进行测试
登录122主机,用redis-cli -c命令
-c命令在连接集群结点时使用,此选项可防止moved和ask异常。
[root@localhost redis]# redis-cli -c
127.0.0.1:6379> set key1 "hello redis cluster"
-> Redirected to slot [9189] located at 169.254.130.10:6379
OK
169.254.130.10:6379> set key2 java
-> Redirected to slot [4998] located at 169.254.130.122:6379
OK
169.254.130.122:6379>
169.254.130.122:6379> keys *
1) "key2"
169.254.130.122:6379> get key2
"java"
169.254.130.122:6379> get key1
-> Redirected to slot [9189] located at 169.254.130.10:6379
"hello redis cluster"
169.254.130.10:6379> get key20
-> Redirected to slot [905] located at 169.254.130.122:6379
"html"
169.254.130.122:6379>
从中可以发现存时是分布式存储,取时也是从集群中取,测试成功