????????Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
订阅的语法格式:
subscribe 主题名字
示例:
127.0.0.1:6379> subscribe channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1
发布命令的语法格式:
publish channel-1 hello
示例:
127.0.0.1:6379> publish channel-1 hello
(integer) 1
其中返回值1代表订阅者数量
打开第一个客户端可以看到发送的消息
127.0.0.1:6379> subscribe channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1
1) "message"
2) "channel-1"
3) "hello"
?慢查询,顾名思义就是比较慢的查询
Redis执行命令过程如下:
?
慢查询发生在第3阶段
客户端超时不一定慢查询,但慢查询是客户端超时的一个可能因素
慢查询日志是存放在Redis内存列表中
????????慢查询日志是Redis服务端在命令执行前后计算每条命令的执行时长,当超过某个阈值是记录下来的日志。日志中记录了慢查询发生的时间,还有执行时长、具体什么命令等信息,它可以用来帮助开发和运维人员定位系统中存在的慢查询。
????????可以使用 slowlog get 命令获取慢查询日志,在 slowlog get 后面还可以加一 个数字,用于指定获取慢查询日志的条数,比如,获取3条慢查询日志:
127.0.0.1:6379> SLOWLOG get 3
1) (integer) 0
2) (integer) 1640056567
3) (integer) 11780
4) 1) "FLUSHALL"
5) "127.0.0.1:43406"
6) ""
参数:
唯一标识ID
命令执行的时间戳
命令执行时长
执行的命名和参数
?配置慢查询参数:
命令执行时长的指定阈值 slowlog-log-slower-than:
slowlog-log-slower-than的作用是指定命令执行时长的阈值,执行命令的时长超过这个阈值时就会被记录下来。
存放慢查询日志的条数 slowlog-max-len。
slowlog-max-len的作用是指定慢查询日志最多存储的条数。实际上,Redis使用了一个列表存放慢查询日志,slowlog-max-len就是这个列表的最大长度。
?修改Redis配置文件:
把slowlog-log-slower-than设置为1000,slowlog-max-len 设置为1200
slowlog-log-slower-than 1000
slowlog-max-len 1200
使用 config set 命令动态修改。
> config set slowlog-log-slower-than 1000
OK
> config set slowlog-max-len 1200
OK
> config rewrite
OK
slowlog-max-len配置建议
线上建议调大慢查询列表,记录慢查询时Redis会对长命令做截断操作,并不会占用大量内存。
增大慢查询列表可以减缓慢查询被剔除的可能,例如线上可设置为1000以上。
slowlog-log-slower-than配置建议
默认值超过10毫秒判定为慢查询,需要根据Redis并发量调整该值。
由于Redis采用单线程响应命令,对于高流量的场景,如果命令执行时间在1毫秒以上,那么Redis最多可支撑OPS不到1000。因此对于高OPS场景的Redis建议设置为1毫秒。
?
?批量网络命令通信模型
经历了 n次时间 = n次网络时间 + n次命令时间 ?
?经历了 1次pipeline(n条命令) = 1次网络时间 + n次命令时间,这大大减少了网络时间的开销,这就是流水线。
在执行批量操作而没有使用pipeline功能,会将大量的时间耗费在每一次网络传输的过程上;而使用pipeline后,只需要经过一次网络传输,然后批量在redis端进行命令操作。这会大大提高了效率。
?????????由于Redis的数据都存放在内存中,如果没有配置持久化,Redis重启后数据就全丢失了,于是需要开启Redis的持久化功能,将数据保存到磁盘上,当Redis重启后,可以从磁盘中恢复数据。
????????对于Redis而言,持久化机制是指把内存中的数据存为硬盘文件, 这样当Redis重启或服务器故障时能根据持久化后的硬盘文件恢复数据
?redis持久化的意义,在于故障恢复。比如部署了一个redis,作为cache缓存,同时也可以保存一些比较重要的数据。
?
Redis提供了两个不同形式的持久化方式
RDB(Redis DataBase)
AOF(Append Only File)
?RDB是什么
????????在指定的时间间隔内将内存的数据集快照写入磁盘,也就是行话讲的快照,它恢复时是将快照文件直接读到内存里。(这种格式是经过压缩的二进制文件。 )
?配置dump.rdb文件
RDB保存的文件,在redis.conf中配置文件名称,默认为dump.rdb。
440 # The filename where to dump the DB
441 dbfilename dump.rdb
?rdb文件的保存位置,也可以修改。默认在Redis启动时命令行所在的目录下。
?触发机制-主要三种方式
快照默认配置:
save 3600 1:表示3600秒内(一小时)如果至少有1个key的值变化,则保存。
save 300 100:表示300秒内(五分钟)如果至少有100个 key 的值变化,则保存。
save 60 10000:表示60秒内如果至少有 10000个key的值变化,则保存。
flushall
执行flushall命令,也会触发rdb规则。
save与bgsave
手动触发Redis进行RDB持久化的命令有两种:
save
该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止,不建议使用。
bgsave
执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。
恢复数据
只需要将rdb文件放在Redis的启动目录,Redis启动时会自动加载dump.rdb并恢复数据。
RDB的优势与劣势
优势
适合大规模的数据恢复
对数据完整性和一致性要求不高更适合使用
节省磁盘空间
恢复速度快
劣势
在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
?以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来。
AOF默认不开启
可以在redis.conf中配置文件名称,默认为appendonly.aof。
?????????AOF文件的保存路径,同RDB的路径一致,如果AOF和RDB同时启动,Redis默认读取AOF的数据。
?
开启AOF
设置Yes:修改默认的appendonly no,改为yes(修改完需要重启redis服务?)
AOF同步频率设置 ?
appendfsync always 始终同步,每次Redis的写入都会立刻记入日志,性能较差但数据完整性比较好。
appendfsync everysec 每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
appendfsync no redis不主动进行同步,把同步时机交给操作系统。 ?
优势
备份机制更稳健,丢失数据概率更低。
可读的日志文本,通过操作AOF稳健,可以处理误操作。
劣势
比起RDB占用更多的磁盘空间。
恢复备份速度要慢。
每次读写都同步的话,有一定的性能压力。
4.如何选用持久化方式
不要仅仅使用RDB
RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。
也不要仅仅使用AOF
你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快。
RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug。
用AOF来保证数据不丢失,作为数据恢复的第一选择,用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。
?五、Redis事务
在数据库层面,事务是指一组操作,这些操作要么全都被成功执行,要么全都不执行
数据库事务的四大特性
A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
C:Consistent,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;
I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。
Redis事务是一组命令的集合,一个事务中的所有命令都将被序列化,按照一次性、顺序性、排他性的执行一系列的命令。
?
单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断;
没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”。
不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚;
?
?
开启:以 MULTI 开始一个事务;
入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面;
执行:由 EXEC 命令触发事务;
Multi、Exec、discard
事务从输入Multi命令开始,输入的命令都会依次压入命令缓冲队列中,并不会执行,直到输入Exec后,Redis会将之前的命令缓冲队列中的命令依次执行。组队过程中,可以通过discard来放弃组队。
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 1
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> incr k1
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) "1"
3) (integer) 2
4) "2"
放弃事务:discard
命令集合中含有错误的指令(注意是语法错误),均连坐,全部失败。
?运行时错误,即非语法错误,正确命令都会执行,错误命令返回错误。
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。
数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务 (即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
主从复制可以分为3个阶段
连接建立阶段(即准备阶段)
数据同步阶段
命令传播阶段?
复制过程大致分为6个过程
?
保存主节点(master)信息。
从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接
从节点与主节点建立网络连接
从节点会建立一个 socket 套接字,从节点建立了一个端口为51234的套接字,专门用于接受主节点发送的复制命令
发送ping命令
连接建立成功后从节点发送 ping 请求进行首次通信。
作用:
检测主从之间网络套接字是否可用。
检测主节点当前是否可以接受命令 。
权限验证。
如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。
同步数据集。
主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。
?
?
主从同步策略
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。 redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
?
?主从复制的缺点:当主机 Master 宕机以后,我们需要人工解决切换
?????????哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
?
集群监控:负责监控redis master和slave进程是否正常工作
消息通知:如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
故障转移:如果master node挂掉了,会自动转移到slave node上
配置中心:如果故障转移发生了,通知client客户端新的master地址
?
sentinel(哨兵1)----->向master(主)和slave(从)发起info,拿到全信息。
sentinel(哨兵2)----->向master(主)发起info,就知道已经存在的sentinel(哨兵1)的信息,并且连接slave(从)。
sentinel(哨兵2)----->向sentinel(哨兵1)发起subscribe(订阅)。
?sentinel不断的向master和slave发起通知,收集信息。
?通知阶段sentinel发送的通知没得到master的回应,就会把master标记为SRI_S_DOWN,并且把master的状态发给各个sentinel,其他sentinel听到master挂了,说我不信,我也去看看,并把结果共享给各个sentinel,当有一半的sentinel都认为master挂了的时候,就会把master标记为SRI_0_DOWN。
?自己最先接到哪个sentinel的竞选通知就会把票投给它。
剔除一些情况:
不在线的
响应慢的
与原来master断开时间久的
优先级原则
当master挂掉的时候,sentinel 会选举出来一个 master,选举的时候是没有办法去访问Redis的,会存在访问瞬断的情况;
哨兵模式,对外只有master节点可以写,slave节点只能用于读。尽管Redis单节点最多支持10W的QPS,但是在电商大促的时候,写数据的压力全部在master上。
Redis的单节点内存不能设置过大,若数据过大在主从同步将会很慢;在节点启动的时候,时间特别长;
Redis有三种集群模式
主从模式
Sentinel模式
Cluster模式
Redis集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。
Redis集群的优点
Redis集群有多个master,可以减小访问瞬断问题的影响
Redis集群有多个master,可以提供更高的并发量
Redis集群可以分片存储,这样就可以存储更多的数据
?Redis Cluster将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。只有master节点会被分配槽位,slave节点不会分配槽位。
槽位定位算法: k1 = 127001
Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。
HASH_SLOT = CRC16(key) % 16384
?可以通过{}来定义组的概念,从而是key中{}内相同内容的键值对放到同一个slot中。
mset k1{test} v1 k2{test} v2 k3{test} v3
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
redis:
cluster:
nodes: 192.168.184.137:8001,192.168.184.137:8002,192.168.184.138:8001,192.168.184.138:8002,192.168.184.139:8001,192.168.184.139:800
@Test
void contextLoads() {
redisTemplate.opsForValue().set("k6","v6");
System.out.println(redisTemplate.opsForValue().get("k6"));
}
答:String、List、Set、Map、ZSet、BitMaps、GEO、HyperLogLog。
常规缓存用String类型 、对象经常修改字段用Map类型 、BitMaps处理打卡上班记录等问题,GEO处理地理坐标类问题,HyperLogLo处理PV,UV等基数统计操作。
List可以实现排行榜,最新列表等功能。Set实现共同联系人,黑白名单功能。
ZSet可以实现特定条件的排行榜。按照人气排行,人气作为存储分数。
答:发布订阅机制可以实现类似你订阅某个频道后,该频带给你发送消息的功能,订阅频道命令
subscribie 频道
# 发送消息
publish 频道名 消息
答:通过慢查询日志解决,slowlog len获取慢查询记录数,在通过slowlog get n获取具体信息去排查。还可以通过慢查询阈值根据QPS设置
> config set slowlog-log-slower-than 1000
OK
> config set slowlog-max-len 1200
OK
> config rewrite
OK
答:一次网络连接 执行n条redis指令。
答:Redis支持两种持久化机制:RDB和AOF。RDB是快照持久化,读写速度快,占用磁盘空间小。但有丢失数据风险。AOF通过记录命令日志持久化,不易丢失数据,但是占用磁盘空间大,读写速度慢。RDB适合做冷备,如一天一备份的常规备份。AOF适合做REDIS正常重启前的数据备份,不会丢失数据。
答:redsi的事务和关系型数据库事务解决问题不一样,原则也不一样,没有acid原则,redis事务保证命令按照队列顺序执行问题,所以redis事务分为两个阶段,第一个阶段是命令入队,第二个阶段是命令执行。
如果队列中命令都证正确,那么按照入队顺序执行,如果队列中命令语法错误,队列所有命名都不执行,如果队列命令语法没错,但是执行失败,只有该命令本身不会执行,其他命令都会执行
redis事务命令
multi 开启事务
exec 执行事务
discard 取消事务
答:Redis集群模式分三种
主从模式
哨兵模式
集群模式
主从模式从一定程度上解决单机Redis的并发问题和可用性问题。但是主从模式问题很大,主节点挂了,需要手动将从节点切换为主节点,所以实际开发很少用到。然后Redis主从复制是哨兵机制和集群机制的根本,所以理解主从模式很重要。
主从模式原理如下:
从节点保存主节点(master)信息。
从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接。
从节点与主节点建立网络连接 。
发送ping命令 :连接建立成功后从节点发送 ping 请求进行首次通信
权限验证:如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。
主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。
主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。 redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
答:哨兵模式主要解决主从复制master节点挂掉之后的,切换从节点为主节点问题,哨兵模式通过监控主从复制主节点和从节点完成自动切换主节点功能。
原理如下:
答:集群模式至少需要6个redis服务器,集群模式就是n个主从复制模式,但是需要根据插槽机制分配每个节点存取数据范围。来解决单个主从redis不能存取数据过大问题,因为会降低从节点复制速度。
答:Redis主从模式下,由于主节点挂了,从节点新选出主节点,由于网络情况,挂掉主节点没有降级为从节点,导致有两个主节点可以写数据。导致挂掉的主节点的数据无法同步而丢失问题。解决办法
min-replicas-to-write 1
min-replicas-max-lag 5
第一个参数表示最少的slave节点为1个
第二个参数表示数据复制和同步的延迟不能超过5秒
答:冷启动是指服务器缓存中没有数据直接启动,访问量有比较大,mysql直接裸机运行。通过缓存预热解决,通过storm实时计算出热点数据,然后定时将热点数据写入缓存。
答:查询一个redis和mysql肯定都不存在的数据是缓存穿透,例如查询id为-1的数据,多半为认为恶意攻击。解决方案:去数据库查不存在在redis存null,并且设置过期时间5分钟。
或者用布隆过器解决:布隆过滤器是一个bitMap数组,它说不存在的元素一定不存在,他说存在的未必存在。
答:某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。从造成问题的原因去解决,当热点Key失效的一刹那,大并发裸奔访问数据库,数据库被打垮。我们只需要在热点Key失效的一刹那保证只有一个请求过来就可以了。这种需求肯定用锁解决,理论上可以用同步锁解决,但这个不靠谱,锁只能锁一个进程,但是微服务是多个服务是多个进程,根本不起作用。所以用分布式锁解决。
答:大量缓存同时失效,数据库被击垮问题。解决思路不让缓存同时失效,比如加给缓存过期时间加随机数,但是当缓存数据足够大时,这个效果不那么明显了,可以通过二级缓存技术实现。