文章目录
Redis简介
什么是redis
REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
reids的优点
redis的优点
以下是Redis的一些优点。
异常快 - Redis非常快,每秒可执行大约110000次的设置(SET)操作,每秒大约可执行81000次的读取/获取(GET)操作。
支持丰富的数据类型 - Redis支持开发人员常用的大多数数据类型,例如列表,集合,排序集和散列等等。这使得Redis很容易被用来解决各种问题,因为我们知道哪些问题可以更好使用地哪些数据类型来处理解决。
操作具有原子性 - 所有Redis操作都是原子操作,这确保如果两个客户端并发访问,Redis服务器能接收更新的值。
多实用工具 - Redis是一个多实用工具,可用于多种用例,如:缓存,消息队列(Redis本地支持发布/订阅),应用程序中的任何短期数据,例如,web应用程序中的会话,网页命中计数等。
Redis集群都有哪些模式
Redis主流的模式有以下几种:
1、主从复制
2、哨兵模式
3、Redis官方提供的Cluster集群模式(服务端)
4、Jedis sharding集群(客户端sharding)
5、利用中间件代理,比如codis等
主从复制(Master-Slave Replication)
主从复制(Master-Slave Replication)的工作原理
:Slave从节点服务启动并连接到Master之后,它将主动发送一个SYNC命令。Master服务主节点收到同步命令后将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave从节点服务在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master主节点继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。
如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。
主从模式的优缺点
优点:
- 同一个Master可以同步多个Slaves。
- Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
- Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
- Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
- 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
- Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
缺点:
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
- Redis的主从复制采用全量复制,复制过程中主机会fork出一个子进程对内存做一份快照,并将子进程的内存快照保存为文件发送给从机,这一过程需要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新加入集群或者从机和主机网络断开重连时都会进行,也就是网络波动都会造成主机和从机间的一次全量的数据复制,这对实际的系统运营造成了不小的麻烦。
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
其实redis的主从模式很简单,在实际的生产环境中是很少使用的,我也不建议在实际的生产环境中使用主从模式来提供系统的高可用性,之所以不建议使用都是由它的缺点造成的,在数据量非常大的情况,或者对系统的高可用性要求很高的情况下,主从模式也是不稳定的。
哨兵模式(Sentinel)
哨兵模式是从Redis的2.6版本开始提供的,但是当时这个版本的模式是不稳定的,直到Redis的2.8版本以后,这个哨兵模式才稳定下来,无论是主从模式,还是哨兵模式,这两个模式都有一个问题,不能水平扩容,并且这两个模式的高可用特性都会受到Master主节点内存的限制。
Sentinel(哨兵)进程是用于监控redis集群中Master主服务器工作的状态
,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用。
Sentinel(哨兵)进程的作用:
- 监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
- 提醒(Notification):当被监控的某个Redis节点出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
- 自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master;当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用现在的Master替换失效Master。Master和Slave服务器切换后,Master的redis.conf、Slave的redis.conf和sentinel.conf的配置文件的内容都会发生相应的改变,即,Master主服务器的redis.conf配置文件中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换。
Sentinel(哨兵)进程的工作方式
- 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
- 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
- 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
- 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
- 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
- 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
哨兵模式的优缺点
优点:
- 哨兵集群模式是基于主从模式的,所有主从的优点,哨兵模式同样具有。
- 主从可以切换,故障可以转移,系统可用性更好。
- 哨兵模式是主从模式的升级,系统更健壮,可用性更高。
缺点:
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。
- 配置复杂
Redis官方 Cluster集群模式(本文使用)
Redis Cluster是一种服务器Sharding技术,3.0版本开始正式提供。
集群通过分片来进行数据共享,并提供复制和故障转移功能
。一个Redis集群通常由多个节点组成;最初,每个节点都是独立的,需要将独立的节点连接起来才能形成可工作的集群。
Redis中的集群分为主节点和从节点。其中主节点用于处理槽;而从节点用于复制某个主节点,并在被复制的主节点下线时,代替下线的主节点继续处理命令请求。
Jedis sharding集群(客户端sharding)
这是一个客户端分区方案。Redis Sharding可以说是在Redis cluster出来之前业界普遍的采用方式,客户端就已经决定数据会被 存储到哪个redis 节点或者从哪个 redis 节点 读取数据。其主要思想是采用哈希算法将 Redis 数据的 key 进行散列,通过 hash 函数,特定的 key 会映射 到特定的 Redis 节点上
。
庆幸的是,Java Redis客户端驱动Jedis已支持Redis Sharding功能,即ShardedJedis以及结合缓存池的ShardedJedisPool
优点:
- 采用一致性哈希算法,将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用简单类似哈希求模映射的主要原因是当增加或减少节点时,不会产生由于重新匹配造成的rehashing。一致性哈希只影响相邻节点key分配,影响量小。
- 为了避免一致性哈希只影响相邻节点造成节点分配压力,ShardedJedis会对每个Redis节点根据名字(没有,Jedis会赋予缺省名字)会虚拟化出160个虚拟节点进行散列。根据权重weight,也可虚拟化出160倍数的虚拟节点。用虚拟节点做映射匹配,可以在增加或减少Redis节点时,key在各Redis节点移动再分配更均匀,而不是只有相邻节点受影响。
- ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,这样通过合理命名key,可以将一组相关联的key放入同一个Redis节点,这在避免跨节点访问相关数据时很重要。
当然,Redis Sharding这种轻量灵活方式必然在集群其它能力方面做出妥协。比如扩容,当想要增加Redis节点时,尽管采用一致性哈希,毕竟还是会有key匹配不到而丢失,这时需要键值迁移。
缺点:
作为轻量级客户端sharding,处理Redis键值迁移是不现实的,这就要求应用层面允许Redis中数据丢失或从后端数据库重新加载数据。但有些时候,击穿缓存层,直接访问数据库层,会对系统访问造成很大压力。
利用中间件代理
原理:客户端发送请求到一个代理组件,代理解析客户端的数据,并将请求转发至正确的节点,最后将结果回复给客户端
。
优点:简化 客户端 的分布式逻辑,客户端 透明接入,切换成本低,代理的 转发 和 存储 分离。
缺点:多了一层 代理层,加重了 架构部署复杂度 和 性能损耗。
代理分区 主流实现的有方案有 Twemproxy 和 Codis
Redis集群安装(伪集群)
伪集群说明
去中心化
采用去中心化的思想: 没有中心节点的说法。
减少带宽占用性能很高: 它使用hash slot方式将16348个hash slot覆盖到所有节点上,对于存储的每个key值,使用CRC16(KEY)&16348=slot得到他对应的hash slot,并在访问key的时候就去找他的hash slot在哪一个节点上,然后由当前访问节点从实际被分配了这个hash slot的节点去取数据,节点之间使用轻量协议通信 减少带宽占用性能很高。
自动实现负载均衡与高可用: 自动实现负载均衡与高可用,自动实现failover并且支持动态扩展。
内部中也需要配置主从
其内部中也需要配置主从,并且内部也是采用哨兵模式,如果有半数节点发现某个异常节点,共同决定更改异常节点的状态,如果改节点是主节点,则对应的从节点自动顶替为主节点,当原先的主节点上线后,则会变为从节点。
如果集群中的master没有slave节点,则master挂掉后整个集群就会进入fail状态,因为集群的slot映射不完整。如果集群超过半数以上的master挂掉,无论是否有slave,集群都会进入fail状态。
部署节点要求
Redis集群至少要有6台服务器,其中3个主节点,3个从节点。因为集群中标记一个节点已失效至少要有超过半数的节点认为某一节点失效,所以需要至少3个节点。如果其中一个及节点失效了,没有从节点顶上,那集群就挂了,所以需要3个从节点做替补。 本文基于Redis官方Cluster集群模式版本redis-5.0.10。
伪集群搭建
创建目录并下载Redis安装包
官方下载地址:https://redis.io/download/
执行以下命令:
mkdir -p /usr/local/redis
cd /usr/local/redis
wget https://download.redis.io/releases/redis-5.0.10.tar.gz
将安装包解压:
tar -zxvf redis-5.0.10.tar.gz
将解压后的文件名修改为7001:
mv redis-5.0.10 7001
cd 7001
mkdir log
mkdir data
编译安装
make MALLOC=libc
make install
修改redis.conf
打开redis.conf配置文件:
vim /usr/local/redis/7001/redis.conf
修改如下内容字段:
################################## NETWORK #####################################
#bind 127.0.0.1 # 绑定监听的网卡IP,注释掉或配置成0.0.0.0可使任意IP均可访问
protected-mode no # 关闭保护模式,使用密码访问
port 7001 # 设置监听端口,建议生产环境均使用自定义端口
################################# GENERAL #####################################
daemonize yes # 在后台运行
pidfile "/var/run/redis_7001.pid" # pid进程文件名
logfile "/usr/local/redis/7001/log/redis.log" # 日志文件的位置
################################ SNAPSHOTTING ################################
dir "/usr/local/redis/7001/data"
################################ REDIS CLUSTER ###############################
cluster-enabled yes
cluster-config-file nodes-1001.conf
cluster-node-timeout 15000
################################## SECURITY ###################################
masterauth "admin@2021" # 连接主节点密码,用于主从通信
requirepass "admin@2021" # 连接集群密码
将7001拷贝成7002,7003,7004,7005,7006,并且修改上述的配置文件中的7001为7002,7003,7004,7005,7006。
cp -a 7001 7002
cp -a 7001 7003
cp -a 7001 7004
cp -a 7001 7005
cp -a 7001 7006
以7002配置文件修改为例:
首先使用vim打开文件:
vim /usr/local/redis/7002/redis.conf
然后执行统一替换命令,将7001替换为7002:
:%s/7001/7002/g
其他的以此类推。
启动所有节点
cd /usr/local/redis/7001/src
redis-server /usr/local/redis/7001/redis.conf
redis-server /usr/local/redis/7002/redis.conf
redis-server /usr/local/redis/7003/redis.conf
redis-server /usr/local/redis/7004/redis.conf
redis-server /usr/local/redis/7005/redis.conf
redis-server /usr/local/redis/7006/redis.conf
查看集群启动情况:
创建集群
注意:在redis5.0后 创建集群统一使用redis-cli,之前的版本使用redis-trib.rb,但是需要安装ruby软件相对复杂,相比之前的版本5.0不需要安装额外的软件,方便。具体的可以参照redis官方网站查看 https://redis.io/topics/cluster-tutorial
创建集群命令:其中 cluster-replicas 1 代表 一个master后有几个slave,1代表为1个slave节点
redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1 -a admin@2021
创建过程以及结果如下所示:
[root@hadoop-master 7001]# redis-cli --cluster create 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 127.0.0.1:7006 --cluster-replicas 1 -a admin@2021
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 127.0.0.1:7005 to 127.0.0.1:7001
Adding replica 127.0.0.1:7006 to 127.0.0.1:7002
Adding replica 127.0.0.1:7004 to 127.0.0.1:7003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 0b55e3dab127d38a29214298d89e1dcb539e069d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
M: ad5990ece8b89245fb218d030cfbeff77b6d9669 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
M: a46c4e47929dd64949a53787c6b753f444378db3 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
S: 54102bd86b6dd373f6186e97081a81a78146cfab 127.0.0.1:7004
replicates ad5990ece8b89245fb218d030cfbeff77b6d9669
S: a4527590baf6ea2004d5203cfddf2106684c499b 127.0.0.1:7005
replicates a46c4e47929dd64949a53787c6b753f444378db3
S: 438b30d76370ff6c750e4102333023761d01992e 127.0.0.1:7006
replicates 0b55e3dab127d38a29214298d89e1dcb539e069d
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
..
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: 0b55e3dab127d38a29214298d89e1dcb539e069d 127.0.0.1:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: a46c4e47929dd64949a53787c6b753f444378db3 127.0.0.1:7003
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: ad5990ece8b89245fb218d030cfbeff77b6d9669 127.0.0.1:7002
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 54102bd86b6dd373f6186e97081a81a78146cfab 127.0.0.1:7004
slots: (0 slots) slave
replicates ad5990ece8b89245fb218d030cfbeff77b6d9669
S: a4527590baf6ea2004d5203cfddf2106684c499b 127.0.0.1:7005
slots: (0 slots) slave
replicates a46c4e47929dd64949a53787c6b753f444378db3
S: 438b30d76370ff6c750e4102333023761d01992e 127.0.0.1:7006
slots: (0 slots) slave
replicates 0b55e3dab127d38a29214298d89e1dcb539e069d
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
测试
1、连接集群
redis-cli -c -p 7001 -a admin@2021
2、查看集群数据分配情况:
127.0.0.1:7006> cluster nodes
458ae71d614b66fe80539604b9691094749c8685 127.0.0.1:7004@17004 slave bbe46d62787b3983bc7ee22f539e28c8c9c00600 0 1609574226846 4 connected
bbe46d62787b3983bc7ee22f539e28c8c9c00600 127.0.0.1:7002@17002 master - 0 1609574225000 2 connected 5461-10922
62c47f88860eddb93a001323720114b5e12c1118 127.0.0.1:7001@17001 master - 0 1609574224802 1 connected 0-5460
bdfb945f7fddfb9d0d3756277815e00be57ad114 127.0.0.1:7005@17005 slave 6dc4e3d34be3606fd0a940c7b864a23fc6e19ab7 0 1609574227869 5 connected
bd1e3a9e5894199cf43da8bda1ec994184e4d656 127.0.0.1:7006@17006 myself,slave 62c47f88860eddb93a001323720114b5e12c1118 0 1609574226000 6 connected
6dc4e3d34be3606fd0a940c7b864a23fc6e19ab7 127.0.0.1:7003@17003 master - 0 1609574226000 3 connected 10923-16383
3、存取数据
存name
127.0.0.1:7001> set name test2021
-> Redirected to slot [5798] located at 127.0.0.1:7002
OK
取name
[root@hadoop-master src]# redis-cli -c -p 7004 -a admin@2021
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7004> get name
-> Redirected to slot [5798] located at 127.0.0.1:7002
"test2021"
验证故障转移
从下面的图中可以得到7002是主节点7004是从节点
查看redis集群的进程
[root@hadoop-master redis]# ps -ef|grep redis-server|grep -v 'grep'
root 15940 1 0 15:56 ? 00:00:00 /usr/local/redis/7001/src/redis-server *:7001 [cluster]
root 15942 1 0 15:56 ? 00:00:00 /usr/local/redis/7001/src/redis-server *:7002 [cluster]
root 15950 1 0 15:56 ? 00:00:00 /usr/local/redis/7001/src/redis-server *:7003 [cluster]
root 15952 1 0 15:56 ? 00:00:00 /usr/local/redis/7001/src/redis-server *:7004 [cluster]
root 15960 1 0 15:56 ? 00:00:00 /usr/local/redis/7001/src/redis-server *:7005 [cluster]
root 15965 1 0 15:56 ? 00:00:00 /usr/local/redis/7001/src/redis-server *:7006 [cluster]
杀掉7002节点,理论上7004节点将选举为master节点
kill -9 15942
其他题外话:
笔者一开始并没有出现预期的从节点切换到主节点情况,而且主节点宕机集群就不可用情况,查了从节点日志,发现有如下报错,从网上查资料显示是由于设置了密码主从同步需要密码
导致的。
解决方案如下,配置文件中增加如下配置:
masterauth "admin@2021"
注意,生产环境中集群创建的地址一定要写主机的ip地址
,不然使用java程序连接会报《连接Redis集群报 Unable to connect to 127.0.0.1:7008 错误》
redis-cli --cluster create 192.168.223.131:7001 192.168.223.131:7002 192.168.223.131:7003 192.168.223.131:7004 192.168.223.131:7005 192.168.223.131:7006 --cluster-replicas 1 -a admin@2021
参考:
https://juejin.cn/post/6844904097116585991