Redis 之二

发布于:2023-01-10 ⋅ 阅读:(388) ⋅ 点赞:(0)

Redis介绍:

是一个c语言写的非关系型数据库,基于内存操作,所以读写性能非常好,一般做缓存。也有做分布式锁,甚至消息队列,支持事务、持久化、Lua脚本 、集群等。

缓存数据一致性问题解决:

1、先更新数据库再更新缓存(不行)

2、先更新缓存,再更新数据 (不行)

 3、Cash Aside(旁路缓存策略)  先删除缓存,再更新数据库(不行)

 4、先更新数据库,再删除缓存,又或者等待一会,再删,即延时双删。(可以)

 注意:此方法,也会有不一致风险,但几率及其低,因为操作缓存比操作数据库要快很多。而且,为了保证,可以再b删除缓存后,等待一会(具体时间业务定),然后再删一次 ,即延时双删。

5、如果mysql是主从架构,主是增删改操作,从节点负责读,那么同步给从节点有可能因为网络抖动无法及时同步,此时数据一致性会再次出现。

 解决思路:

 引入canel中间件,其作用是伪装为slave去发送dump协议给master,master接受后发送bin log日志给canel,后重放,更新缓存。为了健壮,可以采用mq异步发送的形式,防止,从 binlog直接到redis出现故障。

Redis是单线程还是多线程?

redis操作命令是单线程的,因此每个命令都具有原子性。redis6.0之后引入了多线程,但也只是IO网络请求的多线程,而且默认不开启。命令还是单线程。引入网络IO多线程是为了提高网络IO的读写性能,因为redis的性能瓶颈主要是内存和网络。

Redis为什么不用多线程?

  • redis是存内存操作,执行速度非常快,性能瓶颈不是执行速度,而是网络延迟,因此多线程并不会带来性能提升
  • 多线程会导致上下文切换,带来不必要的开销
  • 多线程会面临线程安全问题,那必然要引入锁,实现复杂,而且性能也会大打折扣。

 过期数据的删除策略?

  • 惰性删除,ttl过期不会立马删除,而是下一次crud的时候,会去检查是否过期,然后进行删除。这样会对cpu友好,但是会造成大量的key过期了未被删除

  • 定期删除,每隔一段时间去抽取一批key,如果过期则删除。有两种模式,slow模式和fast模式。对内存友好

 Redis采用惰性删除+定期删除的模式

淘汰策略?

内存淘汰: 就是当redis的内存占用达到阈值时,redis会主动挑选部分key删除以释放更多内存。

 Redis的持久化机制?

  • RDB Redis Database Backfile(默认)以快照的形式保存到磁盘,重启速度快,但可能存在丢失数据。

 bgsave:控制台输入save命令是同步的,进行同步的话会阻塞主进程,然而,我们一般使用bgsave,fork子进程,然后采用CopyOnWrite技术,将内存数据记录为RDB文件,替换旧文件。

 

  AOF:Append-only File 以日志追加的形式写入磁盘,该方案默认不开启,追加的是操作的命令。数据保存较完整,但是体积大,重启缓慢。

Redis4.0以后有RDB+AOF持久化方式选择,把RDB的内容写到AOF开头,可以兼顾加载速度而不丢失更多的数据。缺点是,文件可读性差,RDB部分不再是AOF格式

Redis数据结构和应用场景:

1、String 字符串,应用于计数场景

2、hash 底层类似于hashmap,为键值对形式,适用于存储对象。购物车<用户ID,<商品ID,购买对象>>。文章点赞 <文章id,<用户ID,点赞记录数据>>

3、list,底层是双向链表,适用于做消息队列、也可以做栈

4、set 无序不重复集合,有交集、并集、差集等操作,适用于共同关注、公共好友等。点赞,key是文章,value是userID,isMember判断返回true,则点赞过。

5、sortset,每个value关联一个score,适用于做排行榜、消息的排行等。

6.geo,地理坐标,附近商铺。

7、bitmap,用户签到、布隆过滤器。

8、HyperLogLog, UV统计。

 Redis的缓存问题

缓存穿透:指一直请求数据库中不存在的数据,缓存形同虚设,请求全部打到数据库,造成数据库巨大压力。

解决办法:1、缓存空值  缺点:额外的内存消耗,短期数据不一致  2、布隆过滤器 实现复杂,有误判风险。判断为1,数据库中可能有数据,判断为0,数据库一定没有。

缓存雪崩:指同一时间,大量的key同时失效甚至是redis宕机,大量请求打到数据库中。

解决办法:1、给key添加随机ttl 2、搭建redis集群

缓存击穿:热点key问题,指单一热点数据key过期,重建时间漫长。

解决办法:1、逻辑过期+互斥锁 效率较好   2、利用互斥锁。 强一执行,但会有死锁风险

Redsi事务:

redis通过multi,exec,discard和watch实现事务功能,使用multi命令后可以输入多个命令,但不会立即执行,而是将他们放到队列,当调涌exex将执行所有命令。redis不支持回滚,因此不满足原子性,而且不满足持久性

Redis集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。

Redis解决秒杀超卖问题

秒杀条件:判断当前时间是否在活动开启时间与结束时间之间 。判断库存是否>1。都满足则执行扣减库存操作。

sql语句:update tb_stock set stock =stock -1 where voucher_id = 1 and stock >0;

一人一单问题:先去查询当前用户对应表是否有数据,判断是否大于0,如果>0,证明已经购买过,但是多线程环境下,查询数据与判断数据并非原子性,存在线程安全问题。

解决思路:锁定当前用户id,直到提交事务。

 以上是单机的解决方案,但是集群模式下,由于是多个jvm,因此也会存在并发安全问题。

 Redis主从架构

单节点的redis并发能力是有限的,因此为了解决高并发,我们可以搭建主从架构,主节点写,从节点读

 命令:在slave执行 slaveof  masterIP masterPort

数据同步原理

replication Id:是数据集的标记,id一致说明同一数据集,slave会继承master的replcaiton Id

offset:偏移量,在repl_baklog中,master offset一般大于slave offset,期间的差值,就是未同步的数据。

全量同步:

  1. slave向主节点发送自己的replication Id和offset,请求增量同步
  2. master判断slave的replication Id与自己的不一致,拒绝增量同步
  3. master将自己数据生成RDB文件,以及repl_backlog,里面记载着生成RDB期间新增的数据。然后RDB发送给slave,同时repl_backlog会不断的以命令形式发送个slave
  4. slave接受到RDB,然后清空自己的数据。加载master的RDB

 增量同步:
redis第一次是全量同步,重启后是增量同步。增量同步的原理就是携带offset给master,master把自己的offset与slave的offset的中间部分命令发送给slave节点

 全量同步发生:第一次同步。slave offset被覆盖

增量同步发生:slave offset小于master offset

优化

 问题:如果master宕机怎么办?哨兵模式

Redis哨兵模式

Sentinel作用: 1、监控集群的健康状态 2、自动故障转移 3、通知给客户端

 

 主观下线:每个一秒发送心跳检测给redis节点。超过一定时间没有回复给sentinel则主观认为下线。

客观下线:超过半数sentinel节点判定该redis节点下线。

故障转移步骤:1、选举一个slave执行slaveof no one升级为master  2、让所有节点执行slaveof 新master 3、修改故障节点配置,slaveof 新master

问题:主从能解决高并发读,哨兵能解决高可用。那高并发写,海量数据如何解决?分片集群

 散列插槽:redis会把数据映射到0-16383共16384个插槽位上,key不是跟节点绑定,而是跟插槽绑定。

为什么要用?master随时可能宕机或者是伸缩,那会导致该master不可用,如果绑定到master,则该数据会丢失,而用散列插槽,可以通过将该master节点上的散列插槽的数据转移到其他节点。

计算位值:key包含“{}”,则“{}”是有效部分 ,若不包含,则整个key是有效部分。

例子:

 

 也可以手动故障转移

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到