你的位置:首页 > 操作系统

[操作系统]redis 学习笔记


上次写redis的学习笔记还是2014年,一转眼已经快2年过去了,在段时间里,redis最大的变化之一就是cluster功能的正式发布,以前要搞redis集群,得借助一致性hash来自己搞sharding,现在方便多了,直接上cluster功能就行了,而且还支持节点动态添加、HA、节点增减后缓存重新分布(resharding)。

下面是参考官方教程cluster-tutorial 在mac机上搭建cluster的过程:

一、下载最新版redis 编译

目前最新版是3.0.7,下载地址:http://www.redis.io/download

编译很简单,一个make命令即可,不清楚的同学,可参考我之前的笔记: redis 学习笔记(1)-编译、启动、停止

二、建6个目录

mkdir ~/app/redis-cluster/ #先建一个根目录mkdir 7000 7001 7002 7003 7004 7005

注:与大多数分布式中间件一样,redis的HA也是依赖选举算法来保证高可用性的,所以类似ZK一样,一般是奇数个节点(可以允许N/2以下的节点失效),再考虑到每个节点做Master-Slave互为备份,所以一个redis cluster集群最少也得6个节点。

然后把步骤1里编译好的redis,复制到这6个目录下。

三、配置文件

port 7000cluster-enabled yescluster-config-file nodes.confcluster-node-timeout 5000appendonly yes

把上面这段保存成redis-cluster.conf,放到每个目录的redis目录中,注意修改port端口,即7000目录下的port为7000,7001目录下的port为7001...

cluster-node-timeout 是集群中各节点相互通讯时,允许"失联"的最大毫秒数,上面的配置为5秒,如果超过5秒某个节点没向其它节点汇报成功,认为该节点挂了。

四、依次启动各个redis

在每个目录redis的src子目录下,输入:

./redis-server ../redis-cluster.conf

这样7000~7005这6个节点就启动了。

五、安装redis的ruby模块

gem install redis #注:这个步骤建议翻~墙,不然你懂的

解释:虽然步骤4把6个redis server启动成功了,但是彼此之间是完全独立的,需要借助其它工具将其加入cluster,而这个工具就是redis提供的一个名为redis-trib.rb的ruby脚本(个人估计redis的作者比较偏爱ruby),mac自带了ruby2.0环境,但是没有redis模块,所以要安装这玩意儿,否则接下来的创建cluster将失败。

六、创建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

仍然保持在某个目录的src子目录下,运行上面这段shell脚本,cluster就创建成功了,replicas 1的意思,就是每个节点创建1个副本(即:slave),所以最终的结果,就是后面的127.0.0.1:7000~127.0.0.1:7005中,会有3个会指定成master,而其它3个会指定成slave。

注:利用redis-trib创建cluster的操作,只需要一次即可,假设系统关机,把所有6个节点全关闭后,下次重启后,即自动进入cluster模式,不用再次redis-trib.rb create。

此时,如何用ps查看redis进程,会看到每个进程后附带了cluster的字样

点击看大图

如果想知道,哪些端口的节点是master,哪些端口的节点是slave,可以用下面的命令:

./redis-trib.rb check 127.0.0.1:7000

输出结果如下:

>>> Performing Cluster Check (using node 127.0.0.1:7000)S: 0b7e0d5337e87ac7b59bba4c1248e5c9e8d1905e 127.0.0.1:7000  slots: (0 slots) slave  replicates 38910c5baafea02c5303505acfd9bd331c608cfcM: e0e8dfddd4e9d855090d6efd18e55ea9c0e1f7aa 127.0.0.1:7001  slots:5461-10922 (5462 slots) master  1 additional replica(s)S: 88e16f91609c03277f2ee6ce5285932f58c221c1 127.0.0.1:7005  slots: (0 slots) slave  replicates ec964a7c7cd53b986f54318a190c1426fc53a5faS: be7e9fd3b7d096b037306bc14e1017150fa59d7a 127.0.0.1:7004  slots: (0 slots) slave  replicates e0e8dfddd4e9d855090d6efd18e55ea9c0e1f7aaM: 38910c5baafea02c5303505acfd9bd331c608cfc 127.0.0.1:7003  slots:0-5460 (5461 slots) master  1 additional replica(s)M: ec964a7c7cd53b986f54318a190c1426fc53a5fa 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.

从上面的输出,可以看出7000、7004、7005是slave,而7001、7003、7002是master(如果大家人为做过一些failover的测试,比如把某个节点手动停掉,再恢复,输出的结果可能与上面不太一样),除了check参数,还有一个常用的参数info

./redis-trib.rb info 127.0.0.1:7000

输出结果如下:

127.0.0.1:7001 (e0e8dfdd...) -> 2 keys | 5462 slots | 1 slaves.127.0.0.1:7003 (38910c5b...) -> 2 keys | 5461 slots | 1 slaves.127.0.0.1:7002 (ec964a7c...) -> 0 keys | 5461 slots | 1 slaves.[OK] 4 keys in 3 masters.0.00 keys per slot on average.

它会把所有的master信息输出,包括这个master上有几个缓存key,有几个slave,所有master上的keys合计,以及平均每个slot上有多少key,想了解更多redis-trib脚本的其它参数,可以用

./redis-trib.rb help

输出如下:

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.

上面已经多次出现了slot这个词,略为解释一下:

点击看大图

如上图,redis-cluster把整个集群的存储空间划分为16384个slot(译为:插槽?),当6个节点分为3主3从时,相当于整个cluster中有3组HA的节点,3个master会平均分摊所有slot,每次向cluster中的key做操作时(比如:读取/写入缓存),redis会对key值做CRC32算法处理,得到一个数值,然后再对16384取模,通过余数判断该缓存项应该落在哪个slot上,确定了slot,也就确定了保存在哪个master节点上,当cluster扩容或删除节点时,只需要将slot重新分配即可(即:把部分slot从一些节点移动到其它节点)。

七、redis-cli客户端操作

./redis-cli -c -h localhost -p 7000

注意加参数-c,表示进入cluster模式,随便添加一个缓存试试:

localhost:7000> set user1 jimmy-> Redirected to slot [8106] located at 127.0.0.1:7001OK

注意第2行的输出,表示user1这个缓存通过计算后,落在8106这个slot上,最终定位在7001这个端口对应的节点上(解释:因为7000是slave,7001才是master,只有master才能写入),如果是在7001上重复上面的操作时,不会出现第2行(解释:7001是master,所以不存在redirect的过程)

➜ src ./redis-cli -c -h localhost -p 7001localhost:7001> set user1 yangOKlocalhost:7001>

八、FailOver测试

先用redis-trib.rb 查看下当前的主、从情况

➜ src ./redis-trib.rb check localhost:7000>>> Performing Cluster Check (using node localhost:7000)S: 0b7e0d5337e87ac7b59bba4c1248e5c9e8d1905e localhost:7000  slots: (0 slots) slave  replicates 38910c5baafea02c5303505acfd9bd331c608cfcM: ec964a7c7cd53b986f54318a190c1426fc53a5fa 127.0.0.1:7002  slots:10923-16383 (5461 slots) master  1 additional replica(s)M: e0e8dfddd4e9d855090d6efd18e55ea9c0e1f7aa 127.0.0.1:7001  slots:5461-10922 (5462 slots) master  1 additional replica(s)S: be7e9fd3b7d096b037306bc14e1017150fa59d7a 127.0.0.1:7004  slots: (0 slots) slave  replicates e0e8dfddd4e9d855090d6efd18e55ea9c0e1f7aaS: 88e16f91609c03277f2ee6ce5285932f58c221c1 127.0.0.1:7005  slots: (0 slots) slave  replicates ec964a7c7cd53b986f54318a190c1426fc53a5faM: 38910c5baafea02c5303505acfd9bd331c608cfc 127.0.0.1:7003  slots:0-5460 (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.

从输出上看7000是7003(38910c5baafea02c5303505acfd9bd331c608cfc)的slave,现在我们人工把7003的redis进程给kill掉,然后观察7000的终端输出:

872:S 21 Mar 10:55:55.663 * Connecting to MASTER 127.0.0.1:70033872:S 21 Mar 10:55:55.663 * MASTER <-> SLAVE sync started3872:S 21 Mar 10:55:55.663 # Error condition on socket for SYNC: Connection refused3872:S 21 Mar 10:55:55.771 * Marking node 38910c5baafea02c5303505acfd9bd331c608cfc as failing (quorum reached).3872:S 21 Mar 10:55:55.771 # Cluster state changed: fail3872:S 21 Mar 10:55:55.869 # Start of election delayed for 954 milliseconds (rank #0, offset 183).3872:S 21 Mar 10:55:56.703 * Connecting to MASTER 127.0.0.1:70033872:S 21 Mar 10:55:56.703 * MASTER <-> SLAVE sync started3872:S 21 Mar 10:55:56.703 # Error condition on socket for SYNC: Connection refused3872:S 21 Mar 10:55:56.909 # Starting a failover election for epoch 10.3872:S 21 Mar 10:55:56.911 # Failover election won: I'm the new master.3872:S 21 Mar 10:55:56.911 # configEpoch set to 10 after successful failover3872:M 21 Mar 10:55:56.911 * Discarding previously cached master state.3872:M 21 Mar 10:55:56.911 # Cluster state changed: ok