面试专题--Redis体系
2025-02-21 10:49:26 0 举报
Redis,作为高性能的键值存储数据库,以其简单的数据结构和卓越的读写性能,在分布式存储系统领域赢得了广泛的应用。它支持多种数据类型,如字符串、哈希、列表、集合、有序集合等,同时提供了发布/订阅、事务、Lua脚本和持久化等多种功能。Redis的极致速度得益于其内存中的数据处理方式,以及通过快照和AOF(Append Only File)日志实现的两种持久化策略。此外,它的复制(Replication)机制保证了高可用性,而哨兵(Sentinel)系统则为集群管理提供了自动化故障转移。Redis还能够通过模块化扩展其核心功能,支持如地理位置索引、位图操作等高级特性。它不仅是缓存解决方案,还经常用作消息队列系统。总体来说,Redis为开发者提供了一个功能全面、性能优秀的数据存储和处理平台。
作者其他创作
大纲/内容
Redis Client Socket
Redis Server Socket
String
解析querybuf成redis命令
buf
font color=\"#e74f4c\
Redis事务
querybuf
aeApiCreate(aeEventLoop *)创建实例
dictRedis 中的 dict 是其核心数据结构之一,用于存储和管理 哈希表(hash table) 类型的键值对。Redis 的字典实现非常高效,支持 O(1) 时间复杂度的插入、删除和查找操作。Redis 中的字典是基于 哈希表(hash table) 实现的,其中包含一系列键值对。字典的实现方式是通过哈希映射(HashMap)存储数据,底层使用 数组 来存储哈希桶,并通过哈希函数将键映射到不同的桶中。每个桶中可以存储一个或多个键值对。
Sort Set
数据类型
可以存储的值
操作
应用场景
字符串、整数或者浮点数
对整个字符串或者字符串的其中一部分执行操作对整数和浮点数执行自增或者自减操作
做简单的键值对缓存、Token、计数器、验证码等
List
列表
从两端压入或者弹出元素对单个或者多个元素进行修剪,只保留一个范围内的元素
存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的数据
Set
无序集合
添加、获取、移除单个元素检查一个元素是否存在于集合中计算交集、并集、差集从集合里面随机获取元素
交集、并集、差集的操作,比如交集,可以把两个人的粉丝列表整一个交集
Hash
包含键值对的无序散列表
添加、获取、移除单个键值对获取所有键值对检查某个键是否存在
结构化的数据,比如一个对象
ZSet
有序集合
添加、获取、删除元素根据分值范围或者成员来获取元素计算一个键的排名
去重但可以排序,如获取排名前几名的用户
skipList跳表的基本思想是通过多级链表加速查找过程。每一层链表都包含了下一层链表的元素,从而使得在查询时,可以跳过大量的元素,从而提高查询效率。跳表通常用于实现需要排序和快速查找的数据结构,如 Redis 的 有序集合(Sorted Set)。跳表的每一层第一层:包含所有的元素,是最基本的链表。第二层:包含部分元素,它的元素比第一层少,每个元素都跳过一定数量的元素(通常是 2)。第三层:包含更少的元素,每个元素跳过更多的元素,以此类推。跳表的优势空间效率:跳表的空间复杂度为 O(N),其中 N 是集合中的元素数目。每一层的元素数目远少于上一层,且元素的分布是随机的,因此跳表非常节省空间。查询效率:跳表的查询效率较高,查找、插入、删除等操作的平均时间复杂度都是 O(log N),这与平衡树相似,但实现上更加简单。实现简单:相比于红黑树等自平衡二叉搜索树,跳表的实现要简单得多,且由于跳表的节点指针较少,性能开销也较小。索引提拔采用随机提拔。
否
3
aeApiPoll
Redis底层数据结构
lock
连接应答处理器acceptTcpHandler
7
5
client
Redis异常处理
读写
1
slave1
slave2
master1
reply
6.0多线程
RDB优点:1、只有一个文件 dump.rdb,方便持久化。2、容灾性好,一个文件可以保存到安全的磁盘。3、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能4.相对于数据集大时,比 AOF 的启动效率更高。缺点:1、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)2、AOF(Append-only file)持久化方式: 是指所有的命令行记录以 redis 命令请 求协议的格式完全持久化存储)保存为 aof 文件
1级索引
while循环,一直尝试加锁(如果使用trylock,则自动跳过任务)
读
事件处理器
master
开源框架Redission,这个框架提供了很好的方法支持Redis锁的实现RLock lock = redission.getLoock(\"myLock\
遍历队列中的client,监听FD写事件绑定写处理器sendReplyToClient
始终单线程
主从不能解决故障自动恢复问题,哨兵已经可以解决故障自动恢复了,那到底为啥还要集群模式呢?主从和哨兵都还有另外一些问题没有解决,单个节点的存储能力是有上限,访问能力是有上限的。Redis Cluster 集群模式具有 高可用、可扩展性、分布式、容错 等特性。集群的键空间被分割为16384个slots(即hash槽),通过hash的方式将数据分到不同的分片上的数据分片后的水平拓展:master节点可以做扩充,数据迁移redis内部自动完成。当你新增一个master节点,需要做数据迁移,redis服务不需要下线。为什么Redis集群有16384个槽(1)、如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。如上所述,在消息头中,最占空间的是 myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:65536÷8÷1024=8kb,因为每秒钟redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。(2)、redis的集群主节点数量基本不可能超过1000个。如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此不建议redis cluster节点数量超过1000个。对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。(3)、槽位越小,节点少的情况下,压缩比高,Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
Redis大Key问题
BeforeSleep
server.cfont color=\"#e74f4c\
4
Redisson
后台线程(watch Dog)
缓存降级当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。缓存降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:1:一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;:2:警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;3:错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;4:严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。
Redis事务Redis 事务的本质是通过MULTI、EXEC、WATCH等一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。Redis事务的三个阶段1:事务开始 MULTI2:命令入队3:事务执行 EXECRedis会将一个事务中的所有命令序列化,然后按顺序执行。1:redis 不支持回滚,“Redis 在事务失败时不进行回滚,而是继续执行余下的命令”, 所以 Redis 的内部可以保持简单且快速。2: 如果在一个事务中的命令出现错误,那么所有的命令都不会执行;3: 如果在一个事务中出现运行错误,那么正确的命令会被执行。Redis事务其他实现基于Lua脚本,Redis可以保证脚本内的命令一次性、按顺序地执行,其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的命令还是会继续运行完
将请求数据写入querybug
other
linkedList(双向链表)特点:结构:每个节点由指向前后节点的指针和数据组成(双向链表)。内存开销:由于需要存储前后指针,内存使用较高。查询性能:顺序查找,时间复杂度为 O(n)。修改性能:增删节点无需移动其他元素,时间复杂度为 O(1)。顺序访问:支持从任一节点快速向前或向后遍历。优点适用于频繁的插入和删除操作。方便从两端操作(LPUSH/RPUSH 和 LPOP/RPOP)。缺点占用内存较多,效率相对较低。查询速度慢,不适合随机访问。使用场景数据量较大且对频繁增删有需求的列表。ziplist(压缩列表)特点结构:连续的内存块,存储紧凑,节省内存。内存开销:低,适合小数据量场景。查询性能:需要遍历整个列表,时间复杂度为O(n)。修改性能:增删节点需要移动后续元素,时间复杂度为O(n)。顺序访问:支持顺序遍历,但不支持随机访问。优点节省内存,适合小规模数据。数据在内存中连续存储,缓存性能较好(更符合 CPU 缓存局部性原理)。缺点插入、删除和查询的性能会随着数据量增加而变差。适用于简单、较小的数据集合。使用场景数据量较小且操作相对简单的场景。quickList特点是一个双向链表,每个节点存储一个 ziplist。节点之间通过指针相连(如 linkedlist)。结合了 ziplist 和 linkedlist 优点的结构,既能节省内存,又支持高效的插入和删除操作。从 Redis 3.2 开始,成为 list 数据类型的默认实现。
线程2
加锁成功(默认加锁30s)
unlock
Redis与数据库一致性
8
6
skipList
每隔10秒检查一下,如果客户端还持有锁key,那么就会不断的延长锁key的生存时间
copy
什么是Redis持久化?持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制,当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。RDB:是Redis DataBase缩写快照RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。AOFAOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。
ae.cvoid aeMain(aeEventLoop *eventLoop) { eventLoop->stop = 0; while (!eventLoop->stop) { if (eventLoop->beforesleep != NULL) eventLoop->beforesleep(eventLoop); font color=\"#e74f4c\
LinkedList
Redis通过I0多路复用来提高网络性能,并且支持各种不同的多路复用实现,并且将这些实现进行封装,提供了统一的高性能事件库API库 AE:#ifdef HAVE_EVPORT#include \"ae_evport.c\"#else #ifdef HAVE_EPOLL #include \"ae_epoll.c\" #else #ifdef HAVE_KQUEUE #include \"ae_kqueue.c\" #else #include \"ae_select.c\" #endif #endif#endif
主从模式,当主节点宕机之后,从节点是可以作为主节点顶上来,继续提供服务的。但是有一个问题,主节点的IP已经变动了,此时应用服务还是拿着原主节点的地址去访问,此时就需要人工干预进行修改。哨兵恰恰就可以解决这个问题。访问redis集群的数据都是通过哨兵集群的,哨兵监控整个redis集群。一旦发现redis集群出现了问题,比如主节点挂了,从节点会顶上来。但是主节点地址变了,这时候应用服务无感知,也不用更改访问地址,因为哨兵才是和应用服务做交互的。Sentinel 很好的解决了故障转移,在高可用方面又上升了一个台阶,当然Sentinel还有其他功能。比如 主节点存活检测、主从运行情况检测、主从切换。哨兵模式监控的原理1:每个Sentinel以每秒钟一次的频率,向它所有的主服务器、从服务器 以及其他Sentinel实例 发送一个PING 命令。2:如果一个实例(instance)距离最后一次有效回复PING命令的时间超过down-after-milliseconds 所指定的值,那么这个实例会被 Sentinel标记为 主观下线。3:如果一个主服务器 被标记为主观下线,那么正在监视这个主服务器的所有 Sentinel 节点,要以每秒一次的频率确认该主服务器是否的确进入了主观下线 状态。4:如果一个 主服务器 被标记为 主观下线,并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个该主服务器被标记为 客观下线。 一主两从三哨兵模式中的脑裂Redis 脑裂问题可以在一主两从三哨兵的模式中发生,尤其是在出现网络分区或通信异常时。这种配置结构虽然具备基本的高可用性,但在特定情况下仍有可能导致脑裂。以下是该模式下容易导致脑裂的情景:1:网络分区或通信中断●当主节点与部分或全部哨兵节点失去连接时,哨兵可能会误判主节点已经下线。●如果剩余的哨兵节点可以达成一致(满足 quorum 数量,通常为 2),则会认为主节点不可用,并发起主从切换,选举一个新的主节点。●如果原主节点仍然在处理客户端请求,但已经被切换为从节点,这时便会出现两个主节点的情况,导致脑裂。2:短暂的网络抖动:●在一主两从三哨兵模式中,如果网络短暂抖动使主节点与哨兵间的连接暂时中断,也可能引发误判。●Redis Sentinel 会尝试重新选举主节点,此时新旧主节点都可能短时间内接受写请求,从而造成数据不一致。哨兵故障或不一致:●如果哨兵本身出现故障,或存在部分哨兵无法正常检测主节点状态(例如某个哨兵卡顿),也可能导致哨兵之间的通信不一致。●在这种情况下,集群可能会出现部分哨兵认为主节点不可用,从而误触发主从切换,导致脑裂。 解决或缓解方案1:提高 quorum 设置设置合理的 quorum 值,确保哨兵在出现网络分区时不会轻易误判主节点下线。对于三哨兵配置,可以设置 quorum=2,以确保至少有 2 个哨兵一致认为主节点不可用时才发起故障转移。2:延长 down-after-milliseconds 参数:down-after-milliseconds 是 Redis Sentinel 中的一个配置参数,用于指定哨兵判断一个主节点是否“下线”的时间阈值,单位毫秒
sds
命令请求处理器readQueryFromClient
Redis常用数据类型
缓存击穿缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。解决方案1:设置热点数据永远不过期。2:加互斥锁,读写锁
networking.cfont color=\"#e74f4c\
sentinel1
AOF优点:1、数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次 命令操作就记录到 aof 文件中一次。2、通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。3、AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令 进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))缺点:1、AOF 文件比 RDB 文件大,且恢复速度慢。2、数据集大的时候,比 rdb 启动效率低。
Client Socket 有readable事件
集群
intset
能否加锁成功
zipList
1:在高并发应用场景下,如果是对数据一致性要求高的情况下,要定位好导致数据和缓存不一致的原因。2:解决高并发场景下数据一致性的方案有两种,分别是延时双删策略和异步更新缓存两种方案。3:另外,设置缓存的过期时间是保证数据保持一致性的关键操作,需要结合业务进行合理的设置。4:数据库和缓存本来就是两种不同的插件,没法保证数据的强一致性,只能保证数据的最终一致性。如果需要强一致性不建议使用redis
监控
Server Socket 有readable事件
Redis集群方案(Redis集群目前无法做数据库选择,默认在0数据库。)
sentinel2
缓存预热缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!解决方案1:直接写个缓存刷新页面,上线时手工操作一下;2:数据量不大,可以在项目启动的时候自动进行加载;3:定时刷新缓存;
哨兵
事件分发器
IO多路复用+事件分发
IO多路复用
quickList
Client Socket 有writeable事件
缓存雪崩缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。解决方案:1:缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。2:一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。3:给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。
server.cint main(){ // 初始化服务 initServer();// 开始监听事件循环 aeMain(server.el);}
原链表
主从
Redis持久化
Redis Slave
SDS字符串是Redis中最为常见的数据存储类型,其底层实现是简单动态字符串sds(simple dynamic string),是可以修改的字符串。它类似于Java中的ArrayList,它采用预分配冗余空间的方式来减少内存的频繁分配。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。(字符串最大长度为 512M)动态字符串优点1:避免了 C 字符串的重复计算。在 C 字符串中,长度是通过遍历整个字符串直到 \\0 来计算的,效率较低。而 SDS 中将字符串的长度信息保存在结构体中(len 字段),每次访问字符串时可以直接获取,避免了重复计算字符串的长度。2:可动态扩展内存。在传统的 C 字符串中,扩展字符串的大小通常需要重新分配内存并拷贝数据,效率较低。SDS 结构则支持动态扩展,当需要增加字符串大小时,它会自动调整分配的内存空间,且避免了频繁的重新分配。3:安全性。sds在Redis中是实现字符串对象的工具,并且完全取代char*,sds是二进制安全的,它可以存储任意二进制数据,不像C语言字符串那样以‘\\0’来标识字符串结束, 因为传统C字符串符合ASCII编码,这种编码的操作的特点就是:遇零则止 。即,当读一个字符串时,只要遇到’\\0’结尾,就认为到达末尾,就忽略’\\0’结尾以后的所有字符。因此,如果传统字符串保存图片,视频等二进制文件,操作文件时就被截断了。这意味着它可以存放任何二进制的数据和文本数据,包括’\\0’4:时间复杂度。SDS 和传统的 C 字符串获得的做法不同,传统的C字符串遍历字符串的长度,遇零则止,复杂度为O(n)。而SDS表头的len成员就保存着字符串长度,所以获得字符串长度的操作复杂度为O(1)。
命令回复处理器sendReplyToClient
主从模式就是N个redis实例,可以是1主N从,也可以N主N从(N主N从则不是严格意义上的主从模式了,后续的集群模式会说到,N主N从就是N+N个redis实例。)主从模式的一个作用是备份数据,这样当一个节点损坏(指不可恢复的硬件损坏)时,数据因为有备份,可以方便恢复。另一个作用是负载均衡,所有客户端都访问一个节点肯定会影响Redis工作效率,有了主从以后,查询操作就可以通过查询从节点来完成。主从的优点1:一旦 主节点宕机,从节点 作为 主节点 的 备份 可以随时顶上来。2:扩展 主节点 的 读能力,分担主节点读压力。:3:高可用基石:除了上述作用以外,主从复制还是哨兵模式和集群模式能够实施的基础,因此说主从复制是Redis高可用的基石。主从的缺点:1:一旦 主节点宕机,从节点晋升成主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。2:主节点的写能力受到单机的限制。3:主节点的存储能力受到单机的限制。
线程1
2
dict
为什么Redis要选择单线程1:抛开持久化不谈,Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,因此多线程并不会带来巨大的性能提升。2: 多线程会导致过多的上下文切换,带来不必要的开销3: 引入多线程会面临线程安全问题,必然要引入线程锁这样的安全手段,实现复杂度增高,而且性能也会大打折扣
大key场景1、热门话题下评论、答案排序场景。2、大V的粉丝列表。3、使用不恰当,或者对业务预估不准确、不及时进行处理垃圾数据等。大key问题由于Redis主线程为单线程模型,大key也会带来一些问题,如:1、集群模式在slot分片均匀情况下,会出现数据和查询倾斜情况,部分有大key的Redis节点占用内存多,QPS高。2、大key相关的删除或者自动过期时,会出现qps突降或者突升的情况,极端情况下,会造成主从复制异常,Redis服务阻塞无法响应请求。大key的体积与删除耗时可参考下表:font color=\"#e74f4c\
sentinel3
执行命令写入到buf或reply
Redis线程模型
具体步骤1、先删除缓存2、再写数据库3、休眠500毫秒4、再次删除缓存这个500毫秒怎么确定的,具体该休眠多久时间呢?设置缓存过期时间是关键点1、从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案2、所有的写操作以数据库为准,只要到达缓存过期时间,缓存删除3、如果后面还有读请求的话,就会从数据库中读取新值然后回填缓存方案缺点结合双删策略+缓存超时设置,这样最差的情况就是:1、在缓存过期时间内发生数据存在不一致2、同时又增加了写请求的耗时。
先删除缓存1、如果先删除Redis缓存数据,然而还没有来得及写入MySQL,另一个线程就来读取2、这个时候发现缓存为空,则去Mysql数据库中读取旧数据写入缓存,此时缓存中为脏数据。3、然后数据库更新后发现Redis和Mysql出现了数据不一致的问题
解决方案
是
master2
master3
如何选择合适的持久化方式1: 一般来说, 如果想达到足以媲美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当 Redis 重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。2: 如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。3: 有很多用户都只使用AOF持久化,但并不推荐这种方式,因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以避免AOF程序的bug。4:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
2级索引
intset在 Redis 中,SET 是一种用于存储唯一元素的集合类型,它是一个无序的集合。Redis 为 SET 提供了高效的存储和操作支持,底层实现主要有两种数据结构:哈希表(hash table)和 整数集合(intset)。根据 SET 中存储的元素类型,Redis 会选择不同的底层数据结构。哈希表(Hash Table)Redis 使用哈希表来存储 SET 元素。当 SET 中的元素数量较多或包含非整数类型的数据时,Redis 会使用哈希表来存储元素。哈希表是通过哈希函数将元素的键映射到桶(buckets)中。每个桶可能存储多个键值对,哈希表使用开放地址法(open addressing)来解决哈希冲突。整数集合(Intset)当 SET 中的元素只有整数时,Redis 会使用 整数集合(intset) 作为底层数据结构。整数集合是一种高效的数据结构,能够在元素都是整数时减少内存使用,并提供快速的插入和查找操作。intset 是一种压缩的有序集合,它是根据整数的大小进行排序的(但在 SET 中,intset 本身并不保证元素的顺序)。它采用类似于数组的方式存储元素,但是使用了特殊的内存优化技术来存储整数。
缓存穿透缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。解决方案1:接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;2:从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击3:采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力
Redis Master
0 条评论
下一页