redis复习大纲
2020-07-13 15:50:28 0 举报
AI智能生成
redis复习大纲
作者其他创作
大纲/内容
分布式锁
常见的几种解决方案
基于数据库实现
实现原理
<ul><li>1、在数据库中创建一张表,表中包含方法名等字段,并且为方法名创建唯一索引<br>2、想执行某一个方法时,则插入一条数据<br>3、成功插入则获取锁,执行完毕则释放锁</li></ul>
优点
实现简单
缺点
需要考虑数据库的可用性和性能<br>不具备可重入性<br>没有锁失效机制<br>不具备阻塞锁特性
zookeeper
实现原理
1、zookeeper内部是一个分层的文件系统目录树结构,规定一个目录下只能有一个唯一的文件名<br>2、创建一个mylock目录<br>3、线程A想获取锁就要去mylock目录下创建临时顺序节点<br>3、获取mylock下的所有节点,然后比较看有没有比自己小的节点,如果有,就获取锁失败,如果没有,就获取锁成功<br>4,线程B获取所有节点,判断自己是不是最小的节点,同时设置监听比自己小的节点<br>5、线程A处理完后,会删除自己的节点,这个时候B线程监听到事件变更,重复3
优点
高可用
可重入
阻塞锁特性
可解决失效死锁问题
缺点
需要频繁的创建和删除节点,性能上不如redis
redis
实现原理
1、通过setnx加锁,并用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,该锁的value为UUID<br>2、获取锁的时候判断是否超时,如果超时则放弃获取锁<br>3、释放锁的时候,通过UUID判断是否为当前锁,如果是,则执行delete进行锁释放
优点
redis的高性能
命令支持好,方便快捷
存在的问题
主从复制
?
业务执行时间大于设置的过期时间
设置上一个看门狗,及时的监听锁的状况,如果还持有锁,则延迟锁的过期时间<br>(一般会设置延长次数,防止无限制的延长下去)
缓存产品对比
服务器端缓存产品
redis
基于内存
数据结构多样
物理内存用完,还可以将不用的数据交换到磁盘
有过期策略
数据能够持久化
能够进行灾难恢复
高性能
memecache
基于内存
数据结构简单只有string k/v
有过期策略
数据不能够持久化
不能够进行灾难恢复
高性能
客户端缓存产品
ehcache
guava cache
spring cache
常见的问题
缓存穿透
现象
在高并发下,查询一个不存在的值时,缓存不会被命中,导致大量请求直接落到数据库上
解决方案
方案一
1、空值防护:直接缓存NULL值
2、校验前置,可以设置一些校验规则
3、过载防护
方案二
布隆过滤器
缓存雪崩
现象
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2、如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中
3、设置热点数据永远不过期。
缓存击穿
现象
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案
1、设置热点数据永远不过期
2、加互斥锁
缓存数据不一致
最初级的缓存不一致问题及解决方案
解决方案
先删除缓存,再删除数据库
并发场景下的缓存不一致性问题
解决方案
将更新请求和读取请求串行化
参考资料
https://zhuanlan.zhihu.com/p/62232835
淘汰策略(缓存)
常见缓存淘汰策略
FIFO
LRU
LFU
random
redisredis5.0淘汰机制
noeviction
当内存限制达到,谁也不删除,返回错误。
allkeys-lru
从数据集中挑选最近最少使用的数据淘汰
allkeys-lfu
从数据集中挑选使用频率最低的数据淘汰。
allkeys-random
从数据集中任意选择数据淘汰
volatile-lru
从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
volatile-lfu
从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
volatile-random
从已设置过期时间的数据集中任意选择数据淘汰。
volatile-ttl
从已设置过期时间的数据集中挑选将要过期的数据淘汰。
运维
数据类型
string
常见命令
set
setnx:键必须不存在才可以设置成功,用于添加<br><br>
set key value [ex seconds] [px millseconds] [xx]:键必须存在,才可以设置成功,用于更新<br>
mget、mset:批量获取
incr 对值进行加1操作,如果不是整数,返回错误,如果不存在按照从0开始<br><br>decr 同incr,但是是减1操作<br><br>incrby,decrby ,增加减去指定的数
适用场景
缓存:将数据以缓存的方式储存
共享session
所有的key-value储存场景
计数器
list
常见指令
lpop、lpush、blpop(阻塞弹出)
rpop、rpush、rlen、brpop(阻塞弹出)
llen(列表长度)
lrange key start end
lindex key index
……
适用场景
消息队列:lpush + brpop = 消息队列
用户关注列表
粉丝列表
hash
常见指令
hset、hsetnx
hget、hmget
hkeys、hvalues
hgetall key //获取所有的field-value ,如果元素数较多会存在阻塞redis的可能
hexists key field //判断filed是否存在
……
适用场景
存储对象:用户详情数据
set:不重复数据合集
常见指令
sadd、spop、srem<br><br>
sinter key1 key2 :交集
sunion key1 key2:求并集
sdiff key1 key2:求差集
……
适用场景
微博共同好友
tag分类
独立IP(没有重复值的list)
Sorted Sets
常见指令
zadd key score member//添加成员
zcard key 计算成员个数
zrange key start end [withscores] 分数
zrevrange
……...还有求交集,并集等操作
适用场景
排行榜
HLL
常见指令
PFADD
PFCOUNT
PFMERGE
适用场景
去重统计
Geo
BitMap
模式
主从模式(redis2.8版本之前的模式)
原理
全量同步
全量同步一般发生在slave初始化阶段,步骤:<br>1、从服务连接主服务,发送SYNC命令<br>2、主服务接收到SYNC命令后,开始执行bgsave命令生成RDB文件并使用缓冲区记录之后执行的所有命令<br>3、主服务bgsave完后,向所有的从服务发送快照文件,并在此期间记录被执行的命令<br>4、从服务收到快照后,丢弃所有的旧数据,载入收到的数据<br>5、主服务快照发送完毕,则开始发送缓冲区的写命令<br>6、从服务完成对快照的载入,开始接收命令请求,执行来自主服务器的缓冲区的写命令
增量同步
增量同步就是当 master 服务器有数据更新的时候,会立刻同步到所有的 slave 服务器
优点
1、解决数据备份问题<br>2、做到读写分离,提高服务器性能
缺点
1、每个客户端连接redis实例的时候都是指定了ip和端口号的,如果所连接的redis实例因为故障下线了,而主从模式也没有提供一定的手段通知客户端另外可连接的客户端地址,因而需要手动更改客户端配置重新连接<br>2、主从模式下,如果主节点由于故障下线了,那么从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作<br>3、无法实现动态扩容<br><br>
架构
一主多从或者级联结构
哨兵sentinel模式(redis2.8及之后的模式)
原理
名词解析
SDOWN:subjectively down,主观下线.
ODOWN:objectively down,客观下线
转换过程
1、每个sentinel实例在启动后,都会和已知的slaves/master以及其他sentinels建立TCP连接,并周期性发送PING(默认为1秒),在交互中,如果redis-server无法在”down-after-milliseconds”时间内响应或者响应错误信息,都会被认为此redis-server处于SDOWN状态<br>2、SDOWN的server为master,那么此时sentinel实例将会向其他sentinel间歇性(一秒)发送”is-master-down-by-addr ”指令并获取响应信息,如果足够多的sentinel实例检测到master处于SDOWN,那么此时当前sentinel实例标记master为ODOWN…其他sentinel实例做同样的交互操作.配置项”sentinel monitor ”,如果检测到master处于SDOWN状态的slave个数达到,那么此时此sentinel实例将会认为master处于ODOWN.<br>3、每个sentinel实例将会间歇性(10秒)向master和slaves发送”INFO”指令,如果master失效且没有新master选出时,每1秒发送一次”INFO”;”INFO”的主要目的就是获取并确认当前集群环境中slaves和master的存活情况.<br>4、经过上述过程后,所有的sentinel对master失效达成一致后,开始故障转移.
自动发现机制
Sentinel与slaves”自动发现”机制: <br><br>在sentinel的配置文件中,都指定了port,此port就是sentinel实例侦听其他sentinel实例建立链接的端口.在集群稳定后,最终会每个sentinel实例之间都会建立一个tcp链接,此链接中发送”PING”以及类似于”is-master-down-by-addr”指令集,可用用来检测其他sentinel实例的有效性以及”ODOWN”和”failover”过程中信息的交互.在sentinel之间建立连接之前,sentinel将会尽力和配置文件中指定的master建立连接.sentinel与master的连接中的通信主要是基于pub/sub来发布和接收信息,发布的信息内容包括当前sentinel实例的侦听端口.
选举
1. 每个做主观下线的 Sentinel 节点向其他 Sentinel 节点发送命令,要求将它设置为领导者.<br>2. 收到命令的 Sentinel 节点如果没有同意通过其他 Sentinel 节点发送命令,那么将同意该请求,否则拒绝<br>3. 如果该 Sentinel 节点发现自己的票数已经超过 Sentinel 集合半数且超过 quorum ,那么它将成为领导者<br>4. 如果此过程有多个 Sentinel 节点成为了领导者,那么将等待一段时间重新进行选举
原理
心跳机制+投票裁决。每个sentinel会向其它sentinal、master、slave定时发送消息,以确认对方是否活着,如果发现对方在指定时间内未回应,则暂时认为对方宕机。若哨兵群中的多数sentinel都报告某一master没响应,系统才认为该master真正宕机,通过Raft投票算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置。
哨兵的任务
1、监控
2、提醒
3、自动故障转移
优点
1、实现故障转移<br>2、主节点状态监控
缺点
1、如果是从节点下线了,sentinel是不会对其进行故障转移的,连接从节点的客户端也无法获取到新的可用从节点<br>2、无法实现动态扩容
架构
redis cluster模式(redis3.0版本之后)
含义
任何两个节点之间都是相互连通的;每一个节点都存有这个集群所有主节点以及从节点的信息
原理
数据分区
hash槽
为什么不用一致性hash
1、hash槽的好处是可以做到数据分配更均匀<br>如果有N个节点,每个节点是准确的承担1/N的容量。而一致性hash,它使用的是hash函数返回的值是随机的。而hash槽类似于我们准确配置每个节点的位置。 <br>2、更好的进行数据迁移<br>无论是hash槽还是一致性hash,本质上都是通过增加一层来解决依赖性问题。未使用时,key的分配依赖于节点个数,当节点个数变化时,key映射的节点也就改变了。增加了一个稳定层(hash槽),hash槽的个数是固定的,这样key分配到的hash槽也就是固定的。从而实现key与节点个数的解耦。hash槽与节点映射,当增加一个节点时,我们可以自己控制迁移哪些槽到新节点。
节点之间的通讯
Gossip 协议 ping-pong
请求分布式缓存的路由
缓存节点的扩展和收缩
故障发现和恢复
参考资料
https://baijiahao.baidu.com/s?id=1663270958212268352&wfr=spider&for=pc
https://baijiahao.baidu.com/s?id=1660962495209391868&wfr=spider&for=pc
优点
1、有效的解决了redis在分布式方面的需求<br>2、遇到单机内存,并发和流量瓶颈等问题时,可采用Cluster方案达到负载均衡的目的<br>3、可实现动态扩容<br>4、P2P模式,去中心化<br>5、通过Gossip协议同步节点信息<br>6、自动故障转移、Slot迁移中数据可用
缺点
1、架构比较新,最佳实践较少<br>2、为了性能提升,客户端需要缓存路由表信息<br>3、节点发现、reshard操作不够自动化
FAQ
主从复制过程
1. 保存主节点信息<br> > 从节点执行完 slaveof 命令后就直接返回,这个时候并没有开始建立连接,从节点仅仅只是保存主节点的地址信息。<br><br>2. 主从建立 socket 连接<br> > 从节点内部通过每秒运行的定时任务维护复制相关逻辑,当从节点发现存在新的主节点后,会尝试与该节点建立网络连接<br><br>3. 发送 ping 命令<br> > 建立连接后,从节点发送 ping 命令进行首次通信。<br>ping 请求的主要目的有:<br>1、检查主从之间的网络是否畅通;<br>2、检查主节点当前是否可以接受处理命令<br> > 如果从节点没有收到 pong 响应或者超时,从节点会断开复制链接,等待下次定时任务发起重连。<br><br>4. 权限认证<br> > 如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节点相同的密码才能通过验证,如果失败则复制终止,需要从节点重新发起复制流程。<br><br>5. 同步数据集<br> > 首次进行复制,主节点会把持有的数据全部发送给从节点。<br><br>6. 命令持续复制<br> > 主机点会持续把写命令发送给从节点,保证主从数据一致性
主从复制的拓扑结构
一主一从
最简单的拓扑结构,一般适用于没有太大的并发场景。当 master 宕机时,slave 提供故障转移支持
一主多从
适用于并发量较大的场景,一般都是读多写少,客户端可以将读命令发送到 salve 节点分担 master 节点压力。实现读写分离架构,当然也保证了高可用。但是该架构需要避免复制风暴
树状主从
slave 节点除了在 master 复制数据,也可以在其他 slave 节点复制数据。主要是通过引用复制中间层,降低 master 节点的负载和需要传送给从节点的数据量,这种架构可以避免复制风暴,但是延长了数据一致性。
模型
持久化方式
RDB
触发机制
手动触发
save(阻塞:不可取)
流程
阻塞当前redis服务器,执行save命令期间,redis不能提供服务,直至RDB完毕
优缺点
1、IO类型:同步<br>2、阻塞<br>3、不会消耗额外内存<br>4、阻塞客户端命令
bgsave(一般都采用这种)
流程
Redis进程执行fork操作创建子进程,RDB持久化过程由子<br><br>进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短
优缺点
1、IO类型:同步<br><br>2、阻塞<br><br>3、不阻塞客户端命令<br><br>4、需要fork,消耗内存
自动触发
通过配置redis.conf配置文件相关参数触发:save 300 1
使用场景
配置文件中使用了save相关配置
如果从节点执行全量复制操作,主节点自动执行bgsave生成RDB文 <br>
执行debug reload命令重新加载Redis时,也会自动触发save操作
默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则<br><br>自动执行bgsave
流程
1、客户端发送 bgsave 命令,Redis 进程首先判断当前是否存在其他子进程在执行操作,如 RDB 或者 AOF 子进程,如果有,则立刻返回,否则执行 2。<br>2、Redis 父进程执行 fork 操作创建子进程,在 fork 操作过程中父进程会阻塞。<br>3、Redis 父进程 fork 操作完成后,bgsave 命令返回 `Background saving started` 信息并不再阻塞 Redis 父进程,可以继续响应其他命令了。<br>4、fork 的子进程则根据 Redis 父进程的内存数据生成 RDB 文件,完成后替换原有的 RDB 文件。同时,发送信号给 Redis 父进程表示 RDB 操作已完成,父进程则更新统计信息。
优点
1、RDB是一个紧凑压缩的二进制文件,代表数据在某一个时间点的快照。非常适合备份,全景复制<br>2、RDB恢复数据速度快于AOF的方式。
缺点
1、RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。<br>2、RDB文件使用特定二进制格式保存,可能存在版本不兼容
AOF
触发机制
配置开启:appendonly yes(默认不开启)
流程
1、所有的写入命令会追加到aof_buf(缓冲区)中。<br>2、AOF缓冲区根据对应的策略向硬盘做同步操作。<br>3、随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。<br>4、当Redis服务器重启时,可以加载AOF文件进行数据恢复。
重写流程(bgrewriteaof)
触发
手动
直接调用bgrewriteaof命令
自动
根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机
流程
1、Redis 服务接收到 bgrewriteaof 命令的时候,会做两步检查。<br>- 如果当前进程正在执行 AOF 重写,则直接返回。<br>- 如果有进程正在执行 bgsave,那么需要等待 bgsave 执行完毕后再执行 AOF 重写。<br>2、Redis 进程会 fork 一个子进程执行 AOF 重写,成功后,Redis 服务继续响应命令,不会影响 Redis 原有的 AOF 流程(即命令写入 aof_buf 缓冲区和缓冲区的数据刷进硬盘)。<br>3、在子进程重写过程中,Redis 主进程会将受到的命令也会写入 AOF 重写缓冲区,这个缓冲区和 aof_buf 缓冲区不一样,需要区分,这样做的目的是为了防止重写过程中数据的丢失。<br>4、由于使用写时复制技术(copy-on-write),子进程只能拿到父进程在 fork 子进程时刻的文件进行重写。子进程根据内存快照,按照命令重写规则将命令重写到新的文件中。这里需要注意的是每次写入硬盘的数据量不能太大,否则容易导致硬盘阻塞,该值由 aof-rewrite-incremental-fsync 控制,默认为 32M。<br>5、子进程完成 AOF 重写后会给发消息给 Redis 主进程,主进程则会将 AOF 重写缓冲区的数据写进新的文件,然后用新的 AOF 文件 替换老的文件。<br>6. 完成 AOF 重写。
优点
<br>1. AOF可以更好的保护数据不丢失。<br> > 一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据,Redis进程挂了,最多丢掉1秒钟的数据;<br>2. AOF日志文件以append-only模式写入,写入性能比较高<br> <br> > AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修;<br><br>3. AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。<br> > 因为在rewrite log的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。<br> > 当新的merge后的日志文件ready的时候,再交换新老日志文件即可。<br><br>4. 适合做灾难性的误删除紧急恢复<br> > AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复
缺点
1. 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大,恢复速度慢<br>2. AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的;
写入策略
1、always:每一次系统 serverCorn 函数调用就刷新一次缓存区<br>2、everysec:每秒执行一次磁盘写入,期间所有的命令都会存储在 aof 缓存区<br>3、no:不做控制,任由操作系统决定什么时候刷新缓冲区
采用方式
具体场景分析?
缓存实际运用
秒杀系统设计
主要解决的问题
高并发
与其他业务的差别
系统的并发会非常大
并发大的时候,网络的流量也会特别大
核心思路
如何在大并发的情况下保证DB能刚得住压力,(大并发的瓶颈在DB)
要求
高可用:保证系统是可用且正确的,最差要设计PlaneB计划兜底
数据一致性:保证秒杀减库的数据一致性
高性能:涉及大量并发,所以要支持高并发,(动静分离、热点发现与隔离、请求削峰与分层过滤、等)
实现技术手段
数据预热(预加载)
将秒杀商品提前加入到缓存系统中如:redis、es等,防止商品超卖和缓存穿透设置雪崩
限流
通过网络代理如nginx,slb负载均衡,程序限流组件与算法、前端逻辑过滤等多种手段,防止大流量造成服务拒绝或者阻塞
削峰
通过异步通信的设计和解决方案如:rpc,mq等具体实现
隔离
通过隔离部署,在网络拓扑上将秒杀系统独立部署,即使异常或宕机,至少不会导致主营业务系统受损或者瘫痪,库表分离
架构图
扣减库存方式
下单减库存
付款减库存
预扣库存
高并发下如何扣减库存
redis操作 把检查库存-扣减库存-返回结果写成一个LUA脚本调用,操作原子化
利用sql事务
收藏
收藏
0 条评论
下一页