redis的深度理解

上篇博客我们说到了redis的基本概念和基本操作,本篇我们就更深入去了解一些redis的操作和概念,我们就从red的主从同步、redis哨兵模式和redis集群三个方面来了解redis数据库

一、主从同步

像MySQL一样,redis是支持主从同步的,而且也支持一主多从以及多级从结构。 主从结构,一是为了纯粹的冗余备份,二是为了提升读性能,比如很消耗性能的SORT就可以由从服务器来承担。 redis的主从同步是异步进行的。

1.主从同步原理

bash 复制代码
从服务器会向主服务器发出SYNC指令,当主服务器接到此命令后,就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作,也就是将主服务器的数据写入RDB文件中。在数据持久化期间,主服务器将执行的写指令都缓存在内存中。
在BGSAVE指令执行完成后,主服务器会将持久化好的RDB文件发送给从服务器,从服务器接到此文件后会将其存储到磁盘上,然后再将其读取到内存中。这个动作完成后,主服务器会将这段时间缓存的写指令再以redis协议的格式发送给从服务器。
另外,要说的一点是,即使有多个从服务器同时发来SYNC指令,主服务器也只会执行一次BGSAVE,然后把持久化好的RDB文件发给多个从服务器。

2.部署主从同步(一主两从)

部署环境

bash 复制代码
192.168.91.5       redis-master
192.168.91.149     redis-slave-1
192.168.91.150     redis-slave-2

关闭防火墙和selinux
systemctl stop firewalld         
systemctl disable firewalld       #关闭防火墙
setenforce 0      #关闭selinux

修改master配置文件

bash 复制代码
# vim /usr/local/redis/redis.conf

bind 0.0.0.0
protected-mode no

修改slave配置文件

bash 复制代码
#vim /usr/local/redis/redis.conf

bind 0.0.0.0
protected-mode no
replicaof 192.168.91.5

重启redis服务,再netstat -nlpt查看一下端口即可

二、哨兵模式

哨兵模式是用于监控redis主从复制中Master状态的工具,所以我们的哨兵模式都是基于主从复制的基础去做的

1.作用

bash 复制代码
检测Master状态,如果Master异常,则会进行Master-Slave切换,将其中一个Slave作为Master,将之前的Master作为Slave, Master-Slave切换后,sentinel的监控目标会随之调换 

2.工作模式

bash 复制代码
1):每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令 

2):如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被 Sentinel 标记为主观下线。 

3):如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。 

4):当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线 

ps:quorum 的值一般设置为哨兵个数的二分之一加1,例如 3 个哨兵就设置 2。

3.主观下线和客观下线

bash 复制代码
主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。 
客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel(哨兵) 实例在对Master Server做出 SDOWN  判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master  Server下线判断,然后开启failover(故障转移)

4.配置哨兵模式

bash 复制代码
vim /usr/local/redis/sentinel.conf

daemonize yes                                #设置哨兵放后台运行
logfile "/var/log/sentinel.log"                    #设置哨兵日志
sentinel monitor mymaster 192.168.91.5 6379 2        #当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。 (slave上面写的是master的ip,master写自己ip)
protected-mode no             #将加密保护关闭
sentinel down-after-milliseconds mymaster 3000          #单位毫秒
sentinel failover-timeout mymaster 10000           #若sentinel在该配置值内未能完成failover(故障转移)操作(即故障时master/slave自动切换),则认为本次failover失败。

[root@redis-master redis]# ./src/redis-sentinel sentinel.conf   #开启哨兵模式

三、redis集群

1.使用redis集群的原因

bash 复制代码
1.首先Redis单实例主要有单点,容量有限,流量压力上限的问题。
Redis单点故障,可以通过主从复制replication,和自动故障转移sentinel哨兵机制。但Redis单Master实例提供读写服务,仍然有容量和压力问题。

2.并发问题
redis官方声称可以达到 10万/每秒,每秒执行10万条命令
假如业务需要每秒100万的命令执行呢?
解决方案如下
正确的应该是考虑分布式,加机器,把数据分到不同的位置,分摊集中式的压力。那么一堆机器做一件事.还需要一定的机制保证数据分区,并且数据在各个主Master节点间不能混乱。

总结:
redis cluster:主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster

2.redis集群特点

bash 复制代码
1.所有的redis节点彼此互联(PING-PONG机制)。
2.客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
3.节点的fail是通过集群中超过半数的节点检测失效时才生效。
4.Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

3.数据分布存储原理

bash 复制代码
Redis 集群使用数据分片来实现:Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数(集群使用公式 CRC16(key) % 16384),这样每个key 都会对应一个编号在 0-16384 之间的哈希槽,那么redis就会把这个key 分配到对应范围的节点上了。同样,当连接三个节点任何一个节点想获取这个key时,也会这样的算法,然后内部跳转到存放这个key节点上获取数据。

4.集群部署

准备环境

bash 复制代码
1.准备三机器,关闭防火墙和selinux
2.制作解析并相互做解析。
注:规划架构两种方案,一种是单机多实例,这里我们采用多机器部署:
三台机器,每台机器上面两个redis实例,一个master一个slave,第一列做主库,第二列做备库
#记得选出控制节点

redis-cluster1 192.168.91.5   7000、7001
redis-cluster2 192.168.91.149   7002、7003
redis-cluster3 192.168.91.150   7004、7005

安装redis(三台机器都需要操作)

bash 复制代码
yum -y install gcc automake autoconf libtool make    #安装编译工具
wget https://download.redis.io/releases/redis-6.2.0.tar.gz      #下载
tar xzvf redis-6.2.0.tar.gz -C /usr/local        #解压
mv /usr/local/redis-6.2.0 /usr/local/redis        #改名
cd /usr/local/redis
make                      #编译
mkdir /usr/local/redis/data        #创建存放数据的目录

创建节点目录:按照规划在每台redis节点的安装目录中创建对应的目录(以端口号命名)

bash 复制代码
[root@redis-cluster1 redis]# pwd
/usr/local/redis

[root@redis-cluster1 redis]# mkdir cluster #创建集群目录
[root@redis-cluster1 redis]# cd cluster/
[root@redis-cluster1 cluster]# mkdir 7000 7001 #创建节点目录

[root@redis-cluster2 redis]# mkdir cluster
[root@redis-cluster2 redis]# cd cluster/
[root@redis-cluster2 cluster]# mkdir 7002 7003

[root@redis-cluster3 redis]# mkdir cluster
[root@redis-cluster3 redis]# cd cluster/
[root@redis-cluster3 cluster]# mkdir 7004 7005

拷贝配置文件到节点目录中

bash 复制代码
[root@redis-cluster1 cluster]# cp /data/redis/redis.conf 7000/
[root@redis-cluster1 cluster]# cp /data/redis/redis.conf 7001/

[root@redis-cluster2 cluster]# cp /data/redis/redis.conf 7002/
[root@redis-cluster2 cluster]# cp /data/redis/redis.conf 7003/

[root@redis-cluster3 cluster]# cp /data/redis/redis.conf 7004/
[root@redis-cluster3 cluster]# cp /data/redis/redis.conf 7005/

修改集群redis配置文件。(主要是端口、ip、pid文件,三台机器相同操作)

bash 复制代码
[root@redis-cluster1 7000]# vim redis.conf 

bind 192.168.116.172               #每个实例的配置文件修改为对应节点的ip地址
port 7000                    #监听端口,运行多个实例时,需要指定规划的每个实例不同的端口号
daemonize yes #redis后台运行
pidfile /var/run/redis_7000.pid           #pid文件,运行多个实例时,需要指定不同的pid文件
logfile /var/log/redis_7000.log           #日志文件位置,运行多实例时,需要将文件修改的不同。
dir /data/redis/data            #存放数据的目录
appendonly yes           #开启AOF持久化,redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之前的状态。
appendfilename "appendonly.aof"           #AOF文件名称
appendfsync everysec        #表示对写操作进行累积,每秒同步一次

以下为打开注释并修改
cluster-enabled yes #启用集群
cluster-config-file nodes-7000.conf                 #集群配置文件,由redis自动更新,不需要手动配置,运行多实例时请注修改为对应端口
cluster-node-timeout 5000             #单位毫秒。集群节点超时时间,即集群中主从节点断开连接时间阈值,超过该值则认为主节点不可以,从节点将有可能转为master
cluster-replica-validity-factor 10               #在进行故障转移的时候全部slave都会请求申请为master,但是有些slave可能与master断开连接一段时间了导致数据过于陈旧,不应该被提升为master。该参数就是用来判断slave节点与master断线的时间是否过长。
cluster-migration-barrier 1         #一个主机将保持连接的最小数量的从机,以便另一个从机迁移到不再被任何从机覆盖的主机
cluster-require-full-coverage yes     #集群中的所有slot(16384个)全部覆盖,才能提供服务

注:所有节点配置文件全部修改切记需要修改的ip、端口、pid文件...避免冲突。确保所有机器都修改。

启动三台机器上面的每个节点

bash 复制代码
[root@redis-cluster1 src]# ./redis-server ../cluster/7000/redis.conf 
[root@redis-cluster1 src]# ./redis-server ../cluster/7001/redis.conf

[root@redis-cluster2 7003]# cd /data/redis/src/
[root@redis-cluster2 src]# ./redis-server ../cluster/7002/redis.conf 
[root@redis-cluster2 src]# ./redis-server ../cluster/7003/redis.conf

[root@redis-cluster3 7005]# cd /data/redis/src/
[root@redis-cluster3 src]# ./redis-server ../cluster/7004/redis.conf 
[root@redis-cluster3 src]# ./redis-server ../cluster/7005/redis.conf

查看端口

bash 复制代码
netsata -lnpt                   #查看端口

查看到这些信息之后,就说明我们的redis集群搭建成功了

四、总结redis在运维方面的经典问题

bash 复制代码
一、如何解决Redis,mysql双写一致性?
1.最经典的缓存+数据库读写的模式:
读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
更新的时候,先更新数据库,然后再删除缓存。
2.给缓存设置过期时间,这种方案下,可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存。

二、缓存雪崩
数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。

产生雪崩的简单过程:
1、redis集群大面积故障
2、缓存失效,但依然大量请求访问缓存服务redis
3、redis大量失效后,大量请求转向到mysql数据库,mysql的调用量暴增,很快就扛不住了,甚至直接宕机
4、由于大量的应用服务依赖mysql和redis的服务,这个时候很快会演变成各服务器集群的雪崩,最后网站彻底崩溃。

解决问题:
1.缓存的高可用性
缓存层设计成高可用,防止缓存大面积故障。即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,例如 Redis Sentinel 和 Redis Cluster 都实现了高可用。
2.缓存降级
可以利用ehcache等本地缓存(暂时支持),主要还是对源服务访问进行限流、资源隔离(熔断)、降级等。
当访问量剧增、服务出现问题仍然需要保证服务还是可用的。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级,这里会涉及到运维的配合。
降级的最终目的是保证核心服务可用,即使是有损的。
在进行降级之前要对系统进行梳理,比如:哪些业务是核心(必须保证),哪些业务可以容许暂时不提供服务(利用静态页面替换)等,以及配合服务器核心指标,来后设置整体。
3.Redis备份和快速预热
1)Redis数据备份和恢复
2)快速缓存预热
4.提前演练
最后,建议还是在项目上线前,演练缓存层宕掉后,应用以及后端的负载情况以及可能出现的问题,对高可用提前预演,提前发现问题。

三、缓存穿透
缓存穿透是指查询一个一不存在的数据。例如:从缓存redis没有命中,需要从mysql数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。

解决问题:
如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。设置一个过期时间或者当有值的时候将缓存中的值替换掉即可。

四、redis有哪些好处
(1) 速度快,因为数据存在内存中.
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
redis相比memcached有哪些优势
(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis可以持久化其数据
redis常见性能问题和解决方案
(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
(4) 尽量避免在压力很大的主库上增加从库
相关推荐
WangYaolove13148 分钟前
请解释Python中的装饰器是什么?如何使用它们?
linux·数据库·python
明志致远淡泊宁静27 分钟前
记录一次服务器redis被入侵
运维·服务器·redis
我是黄大仙29 分钟前
利用飞书多维表格自动发布版本
运维·服务器·数据库·飞书
曾经的三心草29 分钟前
Mysql之约束与事件
android·数据库·mysql·事件·约束
WuMingf_36 分钟前
redis
数据库·redis
张某布响丸辣44 分钟前
SQL中的时间类型:深入解析与应用
java·数据库·sql·mysql·oracle
P.H. Infinity2 小时前
【RabbitMQ】10-抽取MQ工具
数据库·分布式·rabbitmq
zgscwxd2 小时前
thinkphp6 --数据库操作 增删改查
数据库·thinkphp6
代码小鑫2 小时前
A031-基于SpringBoot的健身房管理系统设计与实现
java·开发语言·数据库·spring boot·后端