- 4、Redis管理实战
- 5、Redis主从复制
- 6、Redis主从复制实践
- 7、Redis HA实践(Redis Sentinel)
- 8、Redis Cluster集群
4、Redis管理实战
4.1 Redis基本数据类型
1、全局Key操作
2、String(字符串)
string是redis最基本的类型,一个key对应一个value。一个键最大能存储512MB。
应用场景
常规计数:微博数,粉丝数等。
3、Hash(字典)
我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器。
所以该类型非常适合于存储值对象的信息。如Username、Password和Age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储995701749个键值对。
应用场景
存储部分变更的数据,如用户信息等。
4、List(列表)
List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。
在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。
List中可以包含的最大元素数量是4294967295。
应用场景
消息队列系统,比如sina微博
在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是做了限制不能超过5000个ID,因此获取ID的函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。
系统不会像传统方式那样””刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取”很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
5、SET(集合)
Set类型看作为没有排序的字符集合。Set可包含的最大元素数量是4294967295。如果多次添加相同元素,Set中将仅保留该元素的一份拷贝。
应用场景
在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
6、 SortedSet(有序集合)
Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。成员是唯一的,但是分数(score)却是可以重复的。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为232-1(4294967295,每个集合可存储40多亿个成员)。
应用场景
排行榜应用,取TOPN操作这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sortedset的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。
4.2 Redis消息模式
Rddis发布消息通常有两种模式:
- 队列模式(queuing)
- 发布-订阅模式(publish-subscribe)
1、任务队列
顾名思义,就是”传递消息的队列”。与任务队列进行交互的实体有两类,一类是生产者(producer),另一类则是消费者(consumer)。生产者将需要处理的任务放入任务队列中,而消费者则不断地从任务独立中读入任务信息并执行。
1、任务队列的好处
- 松耦合
生产者和消费者只需按照约定的任务描述格式,进行编写代码。
- 易于扩展
多消费者模式下,消费者可以分布在多个不同的服务器中,由此降低单台服务器的负载。
4.3 Redis发布订阅
其实从Pub/Sub的机制来看,它更像是一个广播系统,多个Subscriber可以订阅多个Channel,多个Publisher可以往多个Channel中发布消息。可以这么简单的理解:
- Subscriber:收音机,可以收到多个频道,并以队列方式显示
- Publisher:电台,可以往不同的FM频道中发消息
- Channel:不同频率的FM频道
1、发布订阅模型
- 一个Publisher,多个Subscriber模型
如下图所示,可以作为消息队列或者消息管道。
主要应用:通知、公告。
- 多个Publisher,一个Subscriber模型
可以将PubSub做成独立的HTTP接口,各应用程序作为Publisher向Channel中发送消息,Subscriber端收到消息后执行相应的业务逻辑,比如写数据库,显示等等。
主要应用:排行榜、投票、计数。
- 多个Publisher,多个Subscriber模型
故名思议,就是可以向不同的Channel中发送消息,由不同的Subscriber接收。
主要应用:群聊、聊天。
2、实践发布订阅
发布订阅实践命令
注意∶使用发布订阅模式实现的消息队列,当有客户端订阅channel后只能收到后续发布到该频道的消息,之前发送的不会缓存,必须Provider和Consumer同时在线。
3、消息队列系统对比
客户端在执行订阅命令之后进入了订阅状态,只能接收SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE四个命令。
开启的订阅客户端,无法收到该频道之前的消息,因为Redis不会对发布的消息进行持久化。
和很多专业的消息队列系统(例如Kafka、RocketMQ)相比,Redis的发布订阅略显粗糙,例如无法实现消息堆积和回溯。但胜在足够简单,如果当前场景可以容忍的这些缺点,也不失为一个不错的选择。
4.4 Redis事务
- redis中的事务跟关系型数据库中的事务是一个相似的概念,但是有不同之处。
- 关系型数据库事务执行失败后面的sql语句不在执行,而redis中的一条命令执行失败,其余的命令照常执行。
- redis中开启一个事务是使用multi,相当于beginlstart transaction,exec提交事务,discard取消队列命令(非回滚操作)。
1、Redis与MySQL对比
2、Redis事务命令
- 事务执行举例
ZADD salary 2000 user1
ZADD salary 3000 user2
ZRANGE salary o -1 WITHSCORES
MULTI
ZINCRBY salary 1000 user1
ZINCRBY salary -1000 user2
EXEC
3、Redis中事务的锁机制
举例:我正在买票Ticket -1 , money -100
而票只有1张,如果在我multi之后,和exec之前,票被别人买了,即ticket变成0了。
我该如何观察这种情景,并不再提交:
- 悲观的想法:
世界充满危险,肯定有人和我抢,给ticket上锁,只有我能操作.[悲观锁]
- 乐观的想法:
没有那么人和我抢,因此,我只需要注意,有没有人更改ticket的值就可以了[乐观锁]
Redis的事务中,启用的是乐观锁,只负责监测key没有被改动.
4、Redis服务管理命令
5、Redis慢日志查询
- Slow log是Redis用来记录查询执行时间的日志系统。
- slow log 保存在内存里面,读写速度非常快
可以通过改写redis.conf文件或者用CONFIG GET和CONFIG SET命令对它们动态地进行修改
slowlog-log-slower-than 10000#超过多少微秒
CONFIG SET slowlog-log-slower-than 100
CONFIG SET slowlog-max-len 1000 # 保存多少条慢日志
CONFIG GET slow*
SLOWLOG GET
SLOWLOG RESET
5、Redis主从复制
5.1 Redis复制特性
- 使用异步复制。
- —个主服务器可以有多个从服务器。
- 从服务器也可以有自己的从服务器。
- 复制功能不会阻塞主服务器。
- 可以通过复制功能来让主服务器免于执行持久化操作,由从服务器去热行持久化操作即可。
- 关闭主服务器持久化时,复制功能的数据安全
- 当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。否则的话,由于延迟等问题,部署的服务应该要避免自动拉起。
为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考一下以下会导致主从服务器数据全部丢失的例子:
- 假设节点A为主服务器,并且关闭了持久化。并且节点B和节点C从节点A复制数据
- 节点A崩溃,然后由自动拉起服务重启了节点A.由于节点A的持久化被关闭了,所以重启之后没有任何数据
- 节点B和节点C将从节点A复制数据,但是A的数据是空的,于是就把自身保存的数据副本删除。
在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用Sentinel 来实现Redis 的高可用性,也是非常危险的。因为主服务器可能拉起得非常快,以至于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。
无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动拉起。
5.2 Redis主从复制原理
1、Redis主从同步方式
redis主从同步有两种方式(或者所两个阶段)︰全同步和部分同步。
主从刚刚连接的时候,进行全同步﹔全同步结束后,进行部分同步。当然,如果有需要,slave在任何时候都可以发起全同步。
redis策略是,无论如何,首先会尝试进行部分同步,如不成功,要求从机进行全同步,并启动BGSAV…..BGSAVE结束后,传输RDB文件;如果成功,允许从机进行部分同步,并传输积压空间中的数据。
下面这幅图,总结了主从同步的机制:
2、Redis主从复制原理
- 从服务器向主服务器发送SYNC命令。
- 接到SYNC命令的主服务器会调用BGSAVE 命令,创建一个RDB文件,并使用缓冲区记录接下来执行的所有写命令。
- 当主服务器执行完BGSAVE命令时,它会向从服务器发送RDB文件,而从服务器则会接收并载入这个文件。
- 主服务器将缓冲区储存的所有写命令发送给从服务器执行。
3、Redis命令传播
在主从服务器完成同步之后,主服务器每执行一个写命令,它都会将被执行的写命令发送给从服务器执行,这个操作被称为“命令传播”(command propagate)
命令传播是一个持续的过程︰只要复制仍在继续,命令传播就会一直进行,使得主从服务器的状态可以一直保持-致。
4、Redis复制中的SYNC和PSYNC
在Redis 2.8版本之前,断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作。从Redis 2.8 开始,Redis使用PSYNC命令代替SYNC命令。PSYNC比起SYNC的最大改进在于PSYNC实现了部分重同步(partial resync)特性︰在主从服务器断线并且重新连接的时候,只要条件允许,PSYNC可以让主服务器只向从服务器同步断线期间缺失的数据,而不用重新向从服务器同步整个数据库。
5、Redis复制的一致性问题
在读写分离环境下,客户端向主服务器发送写命令SET n 10086,主服务器在执行这个写命令之后,向客户端返回回复,并将这个写命令传播给从服务器。
接到回复的客户端继续向从服务器发送读命令GET n,并且因为网络状态的原因,客户端的GET命令比主服务器传播的SET命令更快到达了从服务器。
因为从服务器键n的值还未被更新,所以客户端在从服务器读取到的将是一个错误〈(过期)的n值。
6、Redis安全性提升
主服务器只在有至少N个从服务器的情况下,才执行写操作从Redis 2.8开始,为了保证数据的安全性,可以通过配置,让主服务器只在有至少N个当前已连接从服务器的情况下,才执行写命令。
不过,因为Redis使用异步复制,所以主服务器发送的写数据并不一定会被从服务器接收到,因此,数据丢失的可能性仍然是存在的。
通过以下两个参数保证数据的安全:
min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>
6、Redis主从复制实践
6.1 Redis多实例配置
准备两个或两个以上redis实例
$ tree
.
|——— 6380
| |——— redis.conf
| |——— redis-server
|——— 6381
| |—— redis.conf
| |—— redis-server
|
|——— 6382
| |—— redis.conf
| |—— redis-server
|—— install-redis.sh
|—— start-redis.sh
6.2 Redis配置文件实例
$ cat 6380/redis.conf
bind 127.0.0.1 192.168.6.20
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
loglevel notice
logfile "/var/log/redis_6380.log"
dbfilename dump.rdb
dir /application/redis/6380/
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no
6.3 启动Redis实例
./6380/redis-server ./6380/redis.conf
./6381/redis-server ./6381/redis.conf
./6382/redis-server ./6382/redis.conf
6.4 Redis复制环境说明
主节点:6380
从节点:6381、6382
6.5 Redis开启主从(在6381、6382实例中执行)
在从服务器的配置文件中加入:slaveof配置文件中配置:
在从服务中设置字段replicaof,格式如下replicaof
$ redis-cli -h 192.168.6.20 -p 6381 -a redis
192.168.6.20:6380>slaveof 192.168.6.20 6380
ok
$ redis-cli -h 192.168.6.20 -p 6382 -a redis
192.168.6.20:6380>slaveof 192.168.6.20 6380
ok
问题处理 - 主从不同步:
master_link_status:down日志中错误如下:
MASTER aborted replication with an error: NOAUTH Authentication required.
这有由于服务都开启了密码requirepass,导致不能验证成功
在redis从服务器的配置文件里面添加如下内容:masterauth 你主库的密码
6.6 Redis主从复制完成
6.7 Redis主从复制管理
主从复制状态监控:info replication
主从切换: slaveof no one
7、Redis HA实践(Redis Sentinel)
官方文档:<https://redis.io/topics/sentinel
Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。
Sentinel是一个监视器,它可以根据被监视实例的身份和状态来判断应该执行何种动作。
7.1 Redis Sentinel功能
1、监控(monitoring)
Sentinel会不断地检查你的主服务器和从服务器是否运作正常。
2、提醒(Notification)
当被监控的某个Redis 服务器出现问题时, Sentinel可以通过API向管理员或者其他应用程序发送通知。
3、自动故障迁移(Automatic failover)
当一个主服务器不能正常工作时,Sentinel会开始一次自动故障迁移操作,它会将失效主服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器。
7.2 Redis Sentinel服务器连接
1、发现并连接主服务器
Sentinel通过用户给定的配置文件来发现主服务器。
Sentinel会与被监视的主服务器创建
两个网络连接:
- 命令连接用于向主服务器发送命令。
- 订阅连接用于订阅指定的频道,从而发现
- 监视同一主服务器的其他Sentinel。
2、发现并连接从服务器
Sentinel通过向主服务器发送INFO命令来自动获得所有从服务器的地址。
跟主服务器一样,Sentinel会与每个被发现的从服务器创建命令连接和订阅连接。
3、发现其他Sentinel
Sentinel会通过命令连接向被监视的主从服务器发送“HELLO”信息,该消息包含Sentinel的IP、端口号、ID等内容,以此来向其他Sentinel宣告自己的存在。与此同时Sentinel会通过订阅连接接收其他Sentinel 的”HELLO”信息,以此来发现监视同一个主服务器的其他Sentinel 。
sentinel1通过发送HELLO信息来让sentinel2和sentinel3发现自己,其他两个sentinel也会进行类似的操作。
4、多个Sentinel之间的连接
Sentinel之间只会互相创建命令连接,用于进行通信。因为已经有主从服务器作为发送和接收HELLO信息的中介,所以Sentinel之间不会创建订阅连接。
7.3 Redis Sentinel检测实例的状态
Sentinel使用PING命令来检测实例的状态∶如果实例在指定的时间内没有返回回复,或者返回错误的回复,那么该实例会被Sentinel判断为下线。
Redis的Sentinel中关于下线(down)有两个不同的概念︰
- 主观下线(Subjectively Down,简称SDOWN)指的是单个Sentinel 实例对服务器做出的下线判断。
- 客观下线(Objectively Down,简称ODOWN)指的是多个Sentinel 实例在对同一个服务器做出SDOWN判断,并且通过SENTINEL is-master-down-by-addr命令互相交流之后,得出的服务器下线判断。(一个Sentinel可以通过向另一个Sentinel发送SENTINEL is-master-down-by-addr命令来询问对方是否认为给定的服务器已下线。)
如果一个服务器没有在master-down-after-milliseconds选项所指定的时间内,对向它发送PING命令的Sentinel返回一个有效回复(valid reply) ,那么Sentinel就会将这个服务器标记为主观下线。
7.4 Redis Sentinel故障转移FAILOVER
一次故障转移操作由以下步骤组成︰
- 发现主服务器已经进入客观下线状态。
- 基于Raft leader election协议,进行投票选举
- 如果当选失败,那么在设定的故障迁移超时时间的两倍之后,重新尝试当选。如果当选成功,那么执行以下步骤。
- 选出一个从服务器,并将它升级为主服务器。
- 向被选中的从服务器发送SLAVEOF NO ONE命令,让它转变为主服务器。
- 通过发布与订阅功能,将更新后的配置传播给所有其他Sentinel,其他Sentinel对它们自己的配置进行更新。
- 向已下线主服务器的从服务器发送SLAVEOF命令,让它们去复制新的主服务器。
- 当所有从服务器都已经开始复制新的主服务器时, leader Sentinel终止这次故障迁移操作。
7.5 Redis Sentinel配置
1、创建程序目录
mkdir /application/26380
cp /usr/local/redis-5.0.5/src/redis-sentinel /application/26380/
2、编辑配置文件
vi /application/26380/sentinel.conf
port 26380
dir "/tmp"
daemonize yes
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel down-after-milliseconds mymaster 60000
sentinel config-epoch mymaster 0
3、启动Sentinel
./redis-sentinel ./sentinel.conf
4、配置文件说明
# 指定监控master (2表示多个sentinel同意)
sentinel monitor mymaster 127.0.0.1 6380 2
# 安全信息
sentinel auth-pass mymaster root
# 超过15000毫秒后认为主机宕机
sentinel down-after-milliseconds mymaster 15000
# 当主从切换多久后认为主从切换失败
sentinel failover-timeout mymaster 900000
#这两个配置后面的数量主从机需要一样, epoch为master的版本
sentinel leader-epoch mymaster 1
sentinel config-epoch mymaster 1
7.6 Redis Sentinel命令操作
7.7 Redis Sentinel发布与订阅信息
客户端可以将Sentinel看作是一个只提供了订阅功能的Redis 服务器︰你不可以使用PUBLISH 命令向这个服务器发送信息,但你可以用SUBSCRIBE命令或者PSUBSCRIBE命令,通过订阅给定的频道来获取相应的事件提醒。一个频道能够接收和这个频道的名字相同的事件。比如说,名为+sdown的频道就可以接收所有实例进入主观下线(SDOWN)状态的事件。
通过执行PSUBSCRIBE*命令可以接收所有事件信息。
以下列出的是客户端可以通过订阅来获得的频道和信息的格式:
第一个英文单词是频道/事件的名字,其余的是数据的格式。
注意:当格式中包含instance details字样时,表示频道所返回的信息中包含了以下用于识别目标实例的内容:
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
@ 字符之后的内容用于指定主服务器,这些内容是可选的,它们仅在@字符之前的内容指定的实例不是主服务器时使用。
7.8 Redis Sentinel(哨兵)实现Redis的高可用性
1、环境准备
机器名称 | IP | port | 服务角色 | 备注 |
---|---|---|---|---|
k8s-master1 | 192.168.6.20 | 6380 | redis主 | 开启Sentinel |
k8s-master1 | 192.168.6.20 | 6381 | redis从 | 开启Sentinel |
k8s-master1 | 192.168.6.20 | 6382 | redis从 | 开启Sentinel |
注意:如果是多台服务,拷贝/usr/local/redis-5.0.5/
目录到其他主机并添加systemd服务即可
2、按照实验实现以上主从
(1)启动redis服务
(2)在主服务上查询主从关系,确认主从已实现
/usr/local/redis-5.0.5/src/redis-cli -h 192.168.6.20 -p 6380 -a redis
192.168.6.20:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.6.20,port=6381,state=online,offset=1792,lag=1
slave1:ip=192.168.6.20,port=6382,state=online,offset=1792,lag=1
...
3、所有节点配置Redis Sentinel哨兵
(1)Redis Sentinel配置
$ vi sentinel.conf
# 默认监听端口26379
port 26380
# 监听地址,注释默认是0.0.0.0
# sentinel announce-ip 1.2.3.4
# 指定主redis和投票裁决的机器数,即至少有1个sentinel节点同时判定主节点故障时,才认为其真的故障
sentinel monitor mymaster 192.168.6.20 6380 1
# 下面保存默认就行,根据自己的需求修改
# 如果联系不到节点5000毫秒,我们就认为此节点下线。
sentinel down-after-milliseconds mymaster 5000
# 设定转移主节点的目标节点的超时时长。
sentinel failover-timeout mymaster 60000
# 如果redis节点启用了auth,此处也要设置password。
# sentinel auth-pass <master-name> <password>
# sentinel auth-pass k8s-master1 redis
# 指在failover过程中,能够被sentinel并行配置的从节点的数量;
# sentinel parallel-syncs <master-name><numslaves>
# 开启守护进程方式启动
daemonize yes
注意:只需指定主机器的IP,等sentinel服务开启,它能自己查询到主上的从redis;并能完成自己的操作
(2)启动redis sentinel
$ vi start-sentinel.sh
#!/bin/bash
for i in 0 1 2
do
/application/2638$i/redis-sentinel /application/2638$i/sentinel.conf
done
$ bash start-sentinel.sh
- sentinel.conf 配置文件会生成从redis的信息
(3)指定master选举优先级
- vim /etc/redis.conf 根据自己的需求设置优先级
- slave-priority 100 复制集群中,主节点故障时, sentinel应用场景中的主节点选举时使用的优先级:
- 数字越小优先级越高,但0表示不参与选举;当优先级一样时,随机选举。
8、Redis Cluster集群
8.1 Redis Cluster介绍
Redis在3.0版正式引入redis-cluster集群这个特性。Redis集群是一个提供在多个Redis间节点间共享数据的程序集。Redis集群是一个分布式(distributed)、容错(fault-tolerant)的Redis内存K/V服务,集群可以使用的功能是普通单机Redis所能使用的功能的一个子集(subset) ,比如Redis集群并不支持处理多个keys的命令,因
为这需要在不同的T点E13ins)和交集(intersections)操作,就没有实现。FCOPV命令,在集群上用计误。还有比如set里的并集(unions)和交集((intersections)操作,就没有实现。通常来说,
点获取不到键值的所有操作都不会被实现。在将来,用户或许可以通过使用MIGRATE COPY命令,
在集群上用计
算节点(Computation Nodes)来执行多键值的只读操作,但Redis集群本身不会执行复杂的多键值操作来把键值在节点间移来移去。Redis集群不像单机版本的Redis那样支持多个数据库,集群只有数据库0,而且也不支持SELECT命令。Redis集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令。
- Redis集群是一个可以在多个Redis 节点之间进行数据共享的设施(installation)。
- Redis集群不支持那些需要同时处理多个键的Redis 命令,因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,这些命令将降低Redis集群的性能,并导致不可预测的行为。
- Redis集群通过分区(partition)来提供一定程度的可用性(availability)︰即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。将数据自动切分(split)到多个节点的能力。
- 当集群中的一部分节点失效或者无法进行通讯时,仍然可以继续处理命令请求的能力。
8.2 Redis Cluster集群优点
无中心架构,分布式提供服务。数据按照slot存储分布在多个redis实例上。增加slave做standby数据副本,用于failover,使集群快速恢复。实现故障auto failover,节点之间通过gossip协议交换状态信息﹔投票机制完成slave到master角色的提升。支持在线增加或减少节点。降低硬件成本和运维成本,提高系统的扩展性和可用性。
8.3 Redis Cluster集群缺点
client实现复杂,驱动要求实现smart client,缓存slots mapping信息并及时更新。目前仅JedisCluster相对成熟,异常处理部分还不完善,比如常见的”max redirect exception”。客户端的不成熟,影响应用的稳定性,提高开发难度。节点会因为某些原因发生阻塞(阻塞时间大于clutser-node-timeout),被判断下线。这种failover是没有必要,sentinel也存在这种切换场景。
8.4 Redis Cluster参考资料
参考:http://redis.io/topics/cluster-tutorial。
集群部署交互式命令行工具:https://github.com/eyjian/redis-tools/tree/masterldeploy
集群运维命令行工具:https://github.com/eyjian/redis-tools/tree/master
批量操作工具:https://github.com/eyjian/libmooon/releases
8.5 Redis Cluster专业术语
8.6 Redis Cluster集群数据共享
Redis集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现:一个Redis集群包含16384个哈希槽(hash slot) ,数据库中的每个键都属于这16384个哈希槽的其中一个,集群使用公式
CRC16(key) % 16384来计算键key属于哪个槽,其中CRC16(key)语句用于计算键key 的CRC16校验和。
- 节点A负责处理О号至5500号哈希槽。
- 节点B负责处理5501号至11000号哈希槽。
- 节点C负责处理11001号至16384号哈希槽。
1、哈希槽的计算方式
集群使用公式CRC16(key) & 16383计算键key属于哪个槽。
8.7 Redis Cluster集群运行机制
- 所有的redis 节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽
- 节点的fail是通过集群中超过半数的master节点检测失效时才失效。
- 客户端与redis节点直连,不需要中间proxy 层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- 把所有的物理节点映射到[0-16383]slot上,cluster负责维护node<->slot<->key
为了使得集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下,仍然可以正常运作,Redis集群对节点使用了主从复制功能︰集群中的每个节点都有1个至N个复制品(replica)
其中一个复
制品为主节点(master) ,而其余的N-1个复制品为从节点(slave) 。
- 在之前列举的节点A、B、C的例子中,如果节点B下线了,那么集群将无法正常运行,因为集群找不到节点来处理5501号至11000号的哈希槽。
- 假如在创建集群的时候(或者至少在节点B下线之前),我们为主节点B添加了从节点B1,那么当主节点B下线的时候,集群就会将B1设置为新的主节点,并让它代替下线的主节点B,继续处理5501号至11000号的哈希槽,这样集群就不会因为主节点B的下线而无法正常运作了。
- 不过如果节点B和B1都下线的话, Redis集群还是会停止运作。
- 集群的复制特性重用了SLAVEOF命令的代码,所以集群节点的复制行为和SLAVEOF命令的复制行为完全相同。
8.8 Redis Cluster集群故障转移
- 在集群里面,节点会对其他节点进行下线检测。
- 当一个主节点下线时,集群里面的其他主节点负责对下线主节点进行故障千移。
- 换句话说,集群的节点集成了下线检测和故障转移等类似Sentinel的功能。
- 因为 Sentinel是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,它们的运行模式非常地不同,所以尽管这两者的功能很相似,但集群的实现没有重用Sentinel的代码
1、Redis Cluster集群里面执行命令的两种情况
(1)命令发送到了正确的节点
命令要处理的键所在的槽正好是由接收命令的节点负责,那么该节点执行命令,就像单机Redis服务器一样。
槽位说明
7000∶槽0~500
7001∶槽5001~10000
7002∶槽10001~16383
键date 位于2022槽,该槽由节点7000负责,命令会直接执行。
(2)命令发送到了错误的节点
接收到命令的节点并非处理键所在槽的节点,那么节点将向客户端返回一个转向((redirection)错误,告知客户端应该到哪个节点去执行这个命令,客户端会根据错误提示的信息,重新向正确的节点发送命令。
键 date位于2022槽,该槽由节点 7000 负责,但错误发送到了7001节点,7001向客户返回转向错误。
客户端根据转向错误的指引,转向到节点7000,并重新发送命令
8.9 Redis Cluster集群关于转向错误
在集群中的节点会互相告知对方,自己负责处理哪些槽。
集群中的每个节点都会记录16384个槽分别由哪个节点负责,从而形成一个“槽表”(slot table).节点在接收到命令请求时,会通过槽表检查键所在的槽是否由本节点处理:
- 如果是的话,那么节点直接执行命令;
- 如果不是的话,那么节点就从槽表里面提取出正确节点的地址信息,然后返回转向错误。
8.10 Redis Cluster集群配置
1、部署计划
redis cluster要求至少三主三从共6个节点才能组成redis集群,测试环境可一台物理上启动6个redis节点,但生产环境至少要准备3台物理机或者虚拟机。
目录将前面的/usr/local/redis-5.0.5/重命名为/usr/local/redis-cluster即可
2、修改集群主机名
hostnamectl --static set-hostname redis01
hostnamectl --static set-hostname redis02
hostnamectl --static set-hostname redis03
3、配置hosts文件
cat >> /etc/hosts <<-EOF
192.168.152.193 redis01
192.168.152.193 redis02
192.168.152.193 redis03
EOF
从redis 3.0之后版本支持redis-cluster集群,redis-4.0.0开始支持module,redis-5.0.0开始支持类似于kafka那样的消息队列,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。这样就可以很好的保证redis的高可用性,下面就来部署个Redis Cluster,在两台服务器上部署6个redis节点
4、修改系统参数(测试环境跳过)
(1)修改最大打开文件数
cat >> letc/security/limits.conf << EOF
*soft nofile 102400
*hard nofile 102400
EOF
- 其中102400为一个进程最大可以打开的文件个数,当与RedisServer的连接数多时,需要设定为合适的值。
- 有些环境修改后,root用户需要重启机器才生效,而普通用户重新登录后即生效。如果是crontab,则需要重启crontab,如: service crond restart,有些平台可能是service cron restart(类似重启系统日志服务︰service rsyslog restart或systemctl restart rsyslog) 。
- 有些环境下列设置即可让root重新登录即生效,而不用重启机器︰
- 但是要小心,有些环境上面这样做,可能导致无法ssh登录,所以在修改时最好打开两个窗口,万一登录不了还可自救。
如何确认更改对一个进程生效?按下列方法(其中$PID为被查的进程ID):
cat /proc/$PID/limits
系统关于/etc/security/limits.conf文件的说明:
#This file sets the resource limits for the users logged in via PAM.
#It does not affect resource limits of the system services.
PAM︰全称”Pluggable Authentication Modules”,中文名“插入式认证模块”。letc/securitylimits.conf实际为pam_limits.so(位置:/lib/security/pam_limits.so)的配置文件,只针对单个会话。要使用limits.conf生效,必须保证pam_limits.so被加入到了启动文件中。
注释说明只对通过PAM登录的用户生效,与PAM相关的文件(均位于/etc/pam.d目录下)∶
/etc/pam.d/login
/etc/pam.d/sshd
/etc/pam.d/crond
如果需要设置Linux用户的密码策略,可以修改文件/etc/login.defs,但这个只对新增的用户有效,如果要影响已有用户,可使用命令chage
(2)TCP监听队列大小
要想永久生效,需要在文件/etc/sysctl.conf中增加一行: net.core.somaxconn = 32767,然后执行命令”sysctl -p”以生效。
Redis配置项tcp-backlog的值不能超过somaxconn的大小。
echo "net.core.somaxconn = 32767" >>letc/sysctl.conf
sysctl -p
即TCP listen的backlog大小,“lproc/sys/net/corelsomaxconn”的默认值一般较小如128,需要修改大一点,比如改成32767。立即生效还可以使用命令:
sysctl -w net.core.somaxconn=32767
(3)OOM相关:vm.overcommit_memory
echo "vm.overcommit_memory=1" >> letclsysctl.conf
sysctl -p
/proc/sys/vm/overcommit_memory”默认值为0,表示不允许申请超过CommitLimmit大小的内存。
可以设置为
1关闭Overcommit,设置方法请参照net.core.somaxconn完成
(4)开启内核的Transparent Huge Pages (THP)””特性
默认值为“[always] madvise never”,建议设置为never,以开启内核的“Transparent Huge Pages(THP)”特性,设置后redis进程需要重启。
为了永久生效,请将
echo never > /sys/kernel/mm/transparent_hugepage/enabled
加入到文件l/etc/rc.local中。
echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled">>/etc/rc.local
chmod +x /etc/rc.local
- 什么是Transparent Huge Pages?为提升性能,通过大内存页来替代传统的4K页,使用得管理虚拟地址数变少,加快从虚拟地址到物理地址的映射,以及摒弃内存页面的换入换出以提高内存的整体性能。内核Kernel将程序缓存内存中,每页内存以2M为单位。相应的系统进程为khugepaged。
- 在Linux中,有两种方式使用Huge Pages,一种是2.6内核引入的HugeTLBFS,另一种是2.6.36内核引入的THP。HugeTLBFS主要用于数据库,THP广泛应用于应用程序。
- 一般可以在rc.local或/etc/default/grub中对Huge Pages进行设置
5、安装redis并配置redis-cluster集群
- redis01安装
[root@redis01 ~]# cd /opt
[root@redis01 ~]# wget http://download.redis.io/releases/redis-5.0.5.tar.gz
[root@redis01 ~]# tar -zxvf redis-5.0.5.tar.gz
[root@redis01 ~]# cd redis-5.0.5/
[root@redis01 ~]# make
[root@redis01 ~]# make install PREFIX=/usr/local/redis-cluster
1)创建实例目录
mkdir -p /redis/{6001,6002}/{conf,data,log}
2)配置
配置官方配置文件,去掉#开头的和空格行
[ root@redis01 ~]# cat redis.conf | grep -v ^# | grep -v ^$
1. redis01 6001配置文件
cat redis.conf
bind 0.0.0.0
protected-mode no
port 6001
daemonize no
dir /redis/6001/data
cluster-enabled yes
cluster-config-file /redis/6001/conf/nodes.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
pidfile /redis/6001/redis.pid
logfile /redis/6001 / log/redis.log
2. redis01 6002配置文件
sed 's/6001/6002/g' redis.conf > /redis/6002/conf/redis.conf
3. 启动脚本start-redis-cluster.sh
cat > /usr/local/redis-cluster/start-redis-cluster.sh <<-EOF
#!/bin/bash
REDIS HOME=/usr/local/redis-cluster
REDIS_CONF=/redis
$REDIS_HOME/bin/redis-server
\$REDIS_CONF/6001/conf/redis.conf
\$REDIS_HOME/bin/redis-server
\$REDIS_CONF/6002/conf/redis.conf
EOF
4. 添加权限
chmod +x /usr/local/redis-cluster/start-redis-cluster.sh
5. 启动
./start-redis-cluster.sh
6. 查看redis启动状态
ss -tnlp | grep redis
# 查看进程启动状态
ps -ef | grep redis
6、创建Redis Cluster
如果只是想快速创建和启动redis集群,可使用redis官方提供的脚本create-cluster,注意redis-5.0.0版本开始才支持”—cluster”
cd /usr/local/redis-cluster/bin
./redis-cli --cluster create redis01:6001 redis01:6002 redis02:6001 redis02:6002 redis03:6001 redis03:6002 --cluster-replication 1
注意:
如果配置项cluster-enabled 的值不为yes,则执行时会报错”[ERR] Node 192.168.152.193:6001 is not
configured as a cluster node.”。这个时候需要先将cluster-enabled的值改为yes,然后重启redis-server进程,之后才可以重新执行redis-cli创建集群。
- redis-cli的参数说明
- create 表示创建一个redis集群。
- —cluster-replicas 1 表示为集群中的每一个主节点指定一个从节点,即一比一的复制2、查看redis进程是否已切换为集群状态(cluster)
- 查看redis进程是否已切换为集群状态(cluster)
ps -ef | grep redis
- 停止redis实例,直接使用kill命令即可
kill -9 <PID>
- 设置命令 行工具redis-cli
ln -s /usr/local/redis-cluster/src/redis-cli /bin/redis-cli
- 查看集群中的节点
6001> cluster nodes
字段从左至右分别是
节点ID、IP地址和端口,节点角色标志、最后发送ping时间、最后接收到pong时间、连接状态、节点负责处理的hash slot。
集群可以自动识别出ip/port的变化,并通过Gossip(最终一致性,分布式服务数据同步算法)协议广播给其他节点知道。Gossip也称“病毒感染算法”、“谣言传播算法”
- 集群验证
# 随表找一个节点进入添加数据
set name china
# 根据提示到相对应的节点上获取数据(keys * 是获取不到数据的)
get name
登陆测试:
redis-cli -h <IP> -c -p <PORT>
# -c 表示登陆集群
- 节点健康检查
redis-cli --cluster check <IP>:<PORT>
- 查看集群信息
> cluster info
- redis cluster集群加上认证
- 登陆到redis节点设置登陆验证
redis-cli -h <IP> -p <PORT> -c
> config set masterauth redispws
> config set requirepass redispws
> auth redispws
> config rewrite
2. 使用密码登陆集群
redis-cli -h <IP> -p <PORT> -c -a 'redispws'
8.11 Redis Cluster的客户端扩展(PHP开发)
https://www.bilibili.com/video/BV1pz4y1D73n?p=566&spm_id_from=pageDriver
1、安装PHP7版本及php-fpm,php-redis,hiredis,swoole扩展
- 更换YUM源
rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
- 查看PHP信息
yum search php71w
- 安装PHP7.1以及扩展
[ root@web ~]# yum -y install php71w php71w-fpm php71w-cli php71w-common php71w-devel php71w-gd php7lw-pdo php71w-mysql php71w-mbstring php71w-bcmath
- 查看PHP版本
php -v
- 安装swoole扩展
- 下载swoole源码
wget http://git.oschina.net/swoole/swoole
2. **编译安装swoole**
cd swoole
phpize (ubuntu没有安装phpize可执行命令: sudo apt-get install php-dev来安装phpize)
./configure
make
make install
除了手工下载编译外,还可以通过PHP官方提供的pecl命令,一键下载安装
pecl install swoole
- 安装php-redis扩展