发布时间:2024-09-27 13:01
掌握完这些应该可以说自己熟悉Redis了吧
图片资源https://www.processon.com/view/626910710e3e742d46183bbc
简单来说Redis就是一个使用C语言开发的非关系型NoSQL的键值对数据库。与传统数据库不同的是,它的数据是存在内存中的,所以读写速度非常快,可以用作数据库、缓存、分布式锁和消息中间件。
Redis提供了多种数据类型来支持不同的业务场景。Redis还支持事务、持久化、Lua脚本、和多种集群方案。
因为Redis是存在内存中的,内存的读取速度远大于硬盘,我们可以将热点数据存放在Redis中,等再次查询直接在缓存中查询,性能更高,并发更高。
Redis基于 Reactor 模式开发了网络事件处理器,这个处理器叫 文件事件处理器, 是单线程的, 采用IO多路复用机制同时监听多个socket, 根据socket上的事件来选择对应的事件处理器来处理这个事件。
Redis客户端对服务端的每次调用都经历了 发送命令、执行命令、返回结果三个过程。 由于Redis是单线程的,所以每一条到达服务器的命名不会被立刻执行,所有命令都会进入一个队列中,然后被逐个执行。且多个客户端执行顺序是不确定的,但是一定不会有两条命令同时执行。所以不会有并发问题。
因为Redis是基于内存的操作,CPU不受Redis的瓶颈, 内存和网络是它的瓶颈。 单线程容易实现,且避免了不必要的上下文切换,不用考虑各种锁的问题,不会出现死锁导致性能消耗。
Redis6.0之后Redis引入了多线程, 因为随着硬件性能提升,Redis 的性能瓶颈可能出现网络 IO 的读写,引入多线程只是为了在网络数据的读写上,执行命令仍然是单线程顺序执行。
Redis 通过⼀个叫做过期字典(可以看作是hash表)来保存数据过期的时间。过期字典的键指向Redis数据库中的某个key(键),过期字典的值是⼀个long long类型的整数,这个整数保存了key所指向的数据库键的过期时间。
常用的过期数据的删除策略有两个:
Redis 中同时使用了惰性删除和定期过期两种删除策略。
但是还是有可能存在定期删除和惰性删除都漏掉了很多过期key的情况,导致大量过期key堆积在内存,然后就OOM了。
Redis采用内存淘汰机制解决这个问题
内存淘汰机制即内存溢出控制策略,是指在Redis的用于缓存的内存不足时,怎么处理需要重新写入且需要申请额外空间的数据。
内存达到maxmemory上限时,触发内存溢出控制策略
相关问题: MySQL里有2000w数据, Redis中只存20w数据, 如何保证Redis中的数据都是热点数据?
我们可以使用Redis内存淘汰机制中的allkeys-lru淘汰策略, 该策略是冲Redis中挑选最近最少使用的数据进行删除,这样被频繁访问的数据就可以保留下来
Redis内存回收使用的LRU算法
很多时候需要持久化数据,Redis支持两种持久化操作:
快照(RDB)
只追加文件(AOF)
以日志的形式记录每个写操作, 将Redis执行过的所有写指令记录下来,读操作不记录, 只许追加文件但不可改写文件。Redis启动之初会读取该文件重新构建数据。
优缺点:
Redis事务ACID只支持 I 隔离性、 D一致性。 Reids事务不支持回滚。 简单来说Redis事务就是一个将多种请求打包,然后按顺序执行的命令
缓存预热就是系统上线后,将相关缓存数据直接加载到缓存系统。这样用户请求的时候可以直接查询事先被预热的缓存数据。
解决方案
为了防止缓存穿透,布隆过滤器可以快速判断一个元素是否在一个集合中。
布隆过滤器原理:当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组(Bit array)中的 K 个点,把它们置为 1 。检索时,只要看看这些点是不是都是1就知道元素是否在集合中;如果这些点有任何一个 0,则被检元素一定不在;如果都是1,则被检元素很可能在(之所以说“可能”是误差的存在)。
数据库和缓存都修改,不推荐这种方式,因为万一是写多读少,会带来大量的无效写入,浪费性能,删除的话,最多多一次查数据库。
而且也会有数据不一致情况,比如两个线程,顺序是:线程1写入数据库,线程2写入数据库,线程2更新缓存,线程1更新缓存。这样就出现了数据不一致。
修改数据库,删除缓存
先更新数据库,再删除缓存。
数据库更新失败,捕获异常不再继续删除缓存,不会出现数据不一致
缓存删除失败或还没删除导致数据库是新数据,缓存是旧数据,出现数据不一致。
这种情况如果对数据实时性要求不高,可以给缓存加上过期时间,实现最终一致性
先删除缓存,再更新数据库
删除缓存失败,可以捕获异常,直接返回结果,不再更新数据库,不会出现数据不一致
删除缓存成功,更新数据库失败或还没更新。可能会出现数据不一致。
比如一个线程删了缓存,数据更新还没成功,另一个线程取数据发现缓存没了,从数据库读取旧数据放入缓存,然后数据库更新了数据,导致数据库和缓存数据不一致
可以用延迟双删来解决这个问题
延迟双删
先删除缓存,再更新数据库,再延长3-5秒后删除缓存,实现最终一致性
【这个延迟时间是业务读数据的时间+几百毫秒】
可以使用canal订阅binlog的方式,只要发现数据库有更新,canal就会自动更新缓存
Redistribution replication是一种主从模式复制机制, 这种机制使得从节点可以成为和主节点完全相同的副本
一个主节点用于写,多个从节点用于分摊读的压力,如果主节点挂了,可以提升一个从节点成为新的主节点,实现故障转移
1.当从服务器连上主服务器只会,从服务器会向主服务器发送数据同步消息
2.主服务器接到从服务器发送过来的同步消息,把主服务器数据进行持久化,生成RDB文件,把RDB文件发给从服务器,从服务器拿到RDB文件进行读取
3.每次主服务器进行写操作只会,和从服务器进行数据同步
从节点第一次连接主节点,主节点会生成RDB文件进行全量复制,同时将新写入的命令存储进缓冲区,发送给从节点,从而保证数据一致性。
网络中断,重新连接后,采用增量复制的方式,与全量复制不同的是,它是根据从节点的偏移量来进行数据同步的。主从节点分别会维护一个偏移量offset。刚开始主从节点写的位置和从节点读的位置在同一起点,随着主节点不断写入,偏移量会逐渐增大,同样的,从节点复制完数据后,偏移量也在不断增加。当网络断开,从节点不再同步,主节点还在不断写数据,偏移量就会大于从节点的偏移量,当连接恢复时,根据偏移量将未同步的进行同步
Redis cluster没有用一致性hash, 而是引入了哈希槽的概念。Redis 集群有16384个哈希槽,
每个key通过CRC16循环校验算法与上16383来决定位置放哪个槽,集群的每个节点负责一部分hash槽
SET lock_key unique_value NX PX 10000
加锁过程就是给一个键设置值,setnx 在lock_key不存在时才能占到位
占锁的时候,值设置为UUID, 每个人只能删除自己上的锁
为了避免死锁,一定要设置锁自动过期。而且设置过期时间和占位必须是原子操作用,lua脚本确保原子操作
Redis思维导图:https://www.processon.com/view/link/6274dfa5e0b34d07585eb845
如果发现有错误的地方,欢迎大家提出批评指正
致力于分享记录各种知识干货,关注我,让我们一起进步,互相学习,不断创作更优秀的文章。
希望大家能多多支持,你们的支持是我最大的动力!不要忘了三连哦 ⭐️
下篇:【MySQL数据库】2022年MySQL必知必会,基础内容与常见面试题
后期预告:Spring全家桶