Redis基础与高级二
1、发布订阅模式
例子:比如说你们家有个收音机 你收听了 xxxxx 频道 那么只要你打开这个频道 你就能收听到这个频道的所有的内容
你的收音机-----------接收方(订阅方)
频道的内容发送方-------内容的发布者
subscribe 订阅的频道的名称
publish 频道名字 内容
场景:这个功能实际上就是咋们的 MQ中的功能(不用管它)
2、rdb模式实现持久化
Redis我们说是基于内存的、所以速度快、但是Redis的数据放到内存里面、当Redis重启的时候 这个数据会发生丢失
假设我们能把写入到内存的数据、持久化到硬盘 那是不是就能保证我们的数据即使发生丢失 也不会全部丢失、或者全部不丢失呢?
Redis的持久化就产生了----默认情况下 Redis本身也是有持久化策略的
我们即使不配置 那么这个Redis的持久化依然存在的
rdb是数据库默认的持久化模式-----又称为快照模式
这个模式是将内存的数据内容 直接保存到 dump.rdb这样的一个二进制文件中的
特点:因为保存的是二进制文件、所以做数据的恢复是相当的快的—适合于做数据的备份
rdb到底是如何保存我们的数据库的:rdb每一次在保存这个数据的时候、首先都会清空原有的dump.rdb文件、然后将整个内存的数据全部写入到这个文件中 rbd-------保存的是redis内存中某一个时刻的数据(适合备份、不适合开发用)
假设刚好清空dump.rdb这个文件、现在断电了------------数据全丢了
什么时候 rdb模式会触发内存的数据和硬盘进行同步呢?
save 900 1 在900秒的时间内如果有1和key发生改变 那么将触发内存和硬盘同步
save 300 10 在300秒的事件内如果有10个key发生改变 那么将会触发内存和硬盘同步
save 60 10000 在60秒的时间类假设有10000个key发生改变那么也变触发内存和硬盘同步
rdb模式是不用开启的、这个模式的redis自动开启的
3、持久化
3.1 aof实现持久化
aof模式是在redis1.1的版本的时候、才增加的一种持久化模式
aof模式在使用的时候 保存的不是数据 是我们操作的时候的一条一条的命令
只要调用了Redis 那么只要有命令的使用那么都会被记录到aof文件中
aof---------------记录的是操作的命令 不记录实际的数据
aof模式如果是在数据恢复还原的时候 效率并不高 数据恢复的话采用rdb文件恢复是最快的
aof模式如何使用
appendonly yes :表示的是开启aof的模式
*3 *代表的是命令的开始 3 :这个表示的是命令中一共有3块内容
$3 $使用修饰命令中的每一个参数的 3代表的是下面的这个命令一共有3个字符
set
$5
email
$5
xxxxx
rdb 存在 aof 现在也存在 ? 你们觉得会以谁优先 这里如果是开启了aof模式 那么会以aof模式为优先
aof模式是否有触发策略?
appendfsync always :只要有键发生改变 立马同步(每一次都触发IO操作、速度就慢下来、这种情况是不会丢数据)-----一般不用(效率太低了)
appendfsync everysec :每一秒钟进行数据同步一次(开发的时候一般选用他----速度上也比较快 即使出现数据的丢失也只会丢失1秒钟的数据)
appendfsync no :永远不同步、数据只是放到缓存里面 速度快 但是数据容易丢失
aof模式是如何同步数据的呢?
每一次在进行数据同步的时候 使用的是 追加的模式 以前的数据不用删除 只需要追加新的操作即可
aof模式消息的重写
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100 (这个表示的是必须达到100%的增加才重写 64M+64M=128M )
auto-aof-rewrite-min-size 64mb aof文件(简单的说就是至少aof文件达到64M才重写)
手动重写
bgrewriteaof :这个命令就是手动重写
重写的好处是对aof文件进行优化(最终的结果都是一样的)
如果你要去手动重写(需要关闭混合持久化的开关才能看到功能)
aof-use-rdb-preamble no
3.2 AOF 重写流程
aof实现持久化流程:
aof 重写流程:
3.3 RDB与AOF的区别
3.4、混合持久化的问题
我们在开发的时候到底是选择 rdb 还是aof呢?
如果你关心的是你的数据、但是任然可以接受在一段时间内依然可以接受一些数据的丢失 那么你可以使用rdb(速度快)
我们以前开发的时候基本上都使用aof模式来做开发、如果你用的版本是4.0以前的版本那么建议你呢还是使用aof
在4.0以后 就出现了一种新的持久化模式(混合持久化)
这个混合持久化 就集成了 rdb的有点和aof所有的有点
画图:理解混合持久化
3.5 持久化应用场景
Tips 1: redis用于控制数据库表主键id,为数据库表主键提供生成策略,保障数据库表的主键唯一性
结论:容易出现id 不连续问题:pass掉。
Tips 3: redis应用于各种结构型和非结构型高热度数据访问加速
结论: 这种数据来源于数据库 没必要在redis 中记性持久化操作: pass掉。
Tips 4: redis 应用于购物车数据存储设计
结论:pass 掉。
Tips 5: redis 应用于抢购,限购类、限量发放优惠卷、激活码等业务的数据存储设计
Tips 6: redis 应用于具有操作先后顺序的数据控制
Tips 7: redis 应用于最新消息展示
Tips 9: redis 应用于同类信息的关联搜索,二度关联搜索,深度关联搜索
结论: 数据库中查询,pass掉
Tips 12: redis 应用于基于黑名单与白名单设定的服务控制
Tips 13: redis 应用于计数器组合排序功能对应的排名
Tips 15: redis 应用于即时任务/消息队列执行管理
Tips 16: redis 应用于按次结算的服务控制
结论:pass掉,可以使用各种mq
3.6、缓存的淘汰策略
什么是缓存淘汰策略、简单的说就是咋们的redis中的内存已经满了、现在要保证内存中的Redis的数据 一定是最新的、那么这个时候就需要配置缓存的淘汰策略了
noeviction:只要缓存满了、那么就不继续服务器里面的写的请求、读的请求是可以完成的、这种模式缓存里面的所有数据 都不会丢失、这种情况会导致参与Redis的业务会失败
volatile-lru:他会优先淘汰掉 设置了过期时间的这个key、然后第二步才淘汰掉使用的比较少的key 假设我们的key没有设置过期时间的话 那么不会优先淘汰
这种模式也是咋们在开发中使用的比较多的一种缓存策略模式
allkeys-lfu:和lru是有区别的、这个在淘汰的时候、淘汰的是全体key的集合、不是过期的key的集合(过期这一说法没有)、这就意味着你没有设置过期时间的key 只要使用的比较少那么依然会被淘汰
volatile-ttl:这个淘汰策略不是LRU 、而是key剩余的寿命的ttl值 ttl值越小 越先被淘汰
allkeys-random:使用这个淘汰策略的时候 淘汰的是随机的key
maxmemory-policy volatile-lru 这个就是配置缓存的淘汰策略的
maxmemory <bytes> :这个是配置Redis的缓存的大小
4 redis 事务
简述:
redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性
按照添加顺序依次执行,中间不会被打断或者干扰。
一个队列中,一次性、顺序性、排他性的执行一系列命令
**事务的基本操作**
开启事务: multi
作用:设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中
执行事务: exec
作用: 设定事务的结束位置,同时执行事务。与multi成对出现,成对使用
注意: 加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行
取消事务: discard
作用: 终止当前事务的定义,发生在multi之后, exec之前
4.1 事务的工作流程
4.2 事务的注意事项
定义事务的过程中,命令格式输入错误怎么办?
语法错误:指命令书写格式有误
处理结果:如果定义的事务中所包含的命令存在语法错误,整体事务中所有命令均不会执行。包括那些语法正确的命令。
定义事务的过程中,命令执行出现错误怎么办?
运行错误:指命令格式正确,但是无法正确的执行。例如对list进行incr操作
处理结果:能够正确运行的命令会执行,运行错误的命令不会被执行
注意:已经执行完毕的命令对应的数据不会自动回滚,需要程序员自己在代码中实现回滚。
4.3 事务 锁
1. **基于特定条件的事务执行**
天猫双11热卖过程中,对已经售罄的货物追加补货, 4个业务员都有权限进行补货。补货的操作可能是一系
列的操作,牵扯到多个连续操作,如何保障不会重复操作?
**业务场景**
多个客户端有可能同时操作同一组数据,并且该数据一旦被操作修改后,将不适用于继续操作
在操作之前锁定要操作的数据,一旦发生变化,终止当前操作
**基于特定条件的事务执行——锁**
**解决方案**
对 key 添加监视锁,在执行exec前如果key发生了变化,终止事务执行
取消对所有 key 的监视:watch key1 [key2……]
redis 应用基于状态控制的批量任务执行: unwatch
- 业务场景:
天猫双11热卖过程中,对已经售罄的货物追加补货,且补货完成。客户购买热情高涨, 3秒内将所有商品购买完毕。本次补货已经将库存全部清空,如何避免最后一件商品不被多人同时购买? 【超卖问题】
业务分析:使用watch监控一个key有没有改变已经不能解决问题,此处要监控的是具体数据,虽然redis是单线程的,但是多个客户端对同一数据同时进行操作时,如何避免不被同时修改?
解决方案:使用 setnx 设置一个公共锁
setnx lock-key value
利用setnx命令的返回值特征,有值则返回设置失败,无值则返回设置成功
对于返回设置成功的,拥有控制权,进行下一步的具体业务操作
对于返回设置失败的,不具有控制权,排队或等待
操作完毕通过del操作释放锁
注意:上述解决方案是一种设计概念,依赖规范保障,具有风险性
-
业务场景: 依赖分布式锁的机制,某个用户操作时对应客户端宕机,且此时已经获取到锁。
业务分析: 由于锁操作由用户控制加锁解锁,必定会存在加锁后未解锁的风险。 需要解锁操作不能仅依赖用户控制,系统级别要给出对应的保底处理方案
解决方案
使用 expire 为锁key添加时间限定,到时不释放,放弃锁
expire lock-key second
pexpire lock-key milliseconds
由于操作通常都是微秒或毫秒级,因此该锁定时间不宜设置过大。具体时间需要业务测试后确认。
例如:持有锁的操作最长执行时间127ms,最短执行时间7ms。
测试百万次最长执行时间对应命令的最大耗时,测试百万次网络延迟平均耗时
锁时间设定推荐:最大耗时*120%+平均网络延迟*110%
如果业务最大耗时<<网络平均延迟,通常为2个数量级,取其中单个耗时较长即可
5、删除策略
5.1 简述
redis 中的数据特征:
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
redis有四种命令可以用于设置键的生存时间和过期时间:
EXPIRE <KEY> <TTL> : 将键的生存时间设为 ttl 秒
PEXPIRE <KEY> <TTL> :将键的生存时间设为 ttl 毫秒
EXPIREAT <KEY> <timestamp> :将键的过期时间设为 timestamp 所指定的秒数时间戳
PEXPIREAT <KEY> <timestamp>: 将键的过期时间设为 timestamp 所指定的毫秒数时间戳.
XX :具有时效性的数据
-1 :永久有效的数据
-2 :已经过期的数据 或 被删除的数据 或 未定义的数据
过期的数据真的立刻删除了吗?
如果Redis的一个键是过期的,那它到了过期时间之后并不是马上就从内存中被删除,而是采用了三种不同的删除策略:
1. 定时删除
2. 惰性删除
3. 定期删除
首先看下: 时效性数据的存储结构
注意: 数据删除策略的目标
在内存占用与CPU占用之间寻找一种平衡,顾此失彼都会造成整体redis性能的下降,甚至引发服务器宕机或
内存泄露。
5.2 定时删除
创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作
优点:节约内存,到时就删除,快速释放掉不必要的内存占用
缺点: CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量
总结:用处理器性能换取存储空间(拿时间换空间)
5.3 惰性删除
数据到达过期时间,不做处理。等下次访问该数据时
如果未过期,返回数据
发现已过期,删除,返回不存在
优点:节约CPU性能,发现必须删除的时候才删除
缺点:内存压力很大,出现长期占用内存的数据
总结:用存储空间换取处理器性能(拿时间换空间)
5.4 定期删除
周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度
特点1: CPU性能占用设置有峰值,检测频度可自定义设置
特点2:内存压力不是很大,长期占用内存的冷数据会被持续清理
总结:周期性抽查存储空间
expireIfNeeded() (随机抽查,重点抽查)
5.5 对比
定时删除 | 节省内存,无占用 | 不分时段占用cpu资源,频度高 | 拿时间换空间 |
---|---|---|---|
惰性删除 | 内存占用严重 | 延时执行,cpu利用率高 | 拿空间换时间 |
定期删除 | 内存定期随机清理 | 每秒花费固定的CPU资源维护内存 | 随机抽查,重点抽查 |
5.6 逐出算法
问题: 当新数据进入redis时,如果内存不足怎么办?
Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。
如果内存不满足新加入数据的最低存储要求, redis要临时删除一些数据为当前指令清理存储空间。
清理数据的策略称为逐出算法。
注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所
有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。
错误信息: (error) OOM command not allowed when used memory >'maxmemory'
影响数据逐出的相关配置
最大可使用内存 :maxmemory
占用物理内存的比例,默认值为0,表示不限制。生产环境中根据需求设定,通常设置在50%以上。
每次选取待删除数据的个数:maxmemory-samples
选取数据时并不会全库扫描,导致严重的性能消耗,降低读写性能。因此采用随机获取数据的方式作为待检测删除数据
删除策略: maxmemory-policy
达到最大内存后的,对被挑选出来的数据进行删除的策略
检测易失数据(可能会过期的数据集server.db[i].expires )
① volatile-lru:挑选最近最少使用的数据淘汰
② volatile-lfu:挑选最近使用次数最少的数据淘汰
③ volatile-ttl:挑选将要过期的数据淘汰
④ volatile-random:任意选择数据淘汰
检测全库数据(所有数据集server.db[i].dict )
⑤ allkeys-lru:挑选最近最少使用的数据淘汰
⑥ allkeys-lfu:挑选最近使用次数最少的数据淘汰
⑦ allkeys-random:任意选择数据淘汰
放弃数据驱逐
⑧ no-enviction(驱逐):禁止驱逐数据( redis4.0中默认策略),会引发错误OOM( Out Of Memory)
数据逐出策略配置依据
使用INFO命令输出监控信息,查询缓存 hit 和 miss 的次数,根据业务需求调优Redis配置
待续。。。。下一篇