数据类型
高级的数据结构
BitMap存储的是连续的二进制数字(0 和 1)可以看做是一个只存储二进制数的数组,下标叫做offerset,只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身。8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。可以用来统计DAU日活跃用户。
HyperLogLog占用空间非常非常小,Redis 对 HyperLogLog 的存储结构做了优化,采用两种方式计数: 计数较少的时候,占用空间很小。计数达到某个阈值的时候,占用 12k 的空间。
基数计数概率算法为了节省内存并不会直接存储元数据,而是通过一定的概率统计方法预估基数值(集合中包含元素的个数)。因此, HyperLogLog 的计数结果并不是一个精确值,存在一定的误差(标准误差为 0.81% 。)可以用来统计UA独立访问用户。
数据库和缓存不一致
缓存的来源是数据库,而数据库是会变化的,如果数据库发生变化而缓存没有同步,就会有一致性问题。
应该先删除缓存还是先操作数据库?
应该先更新数据库再删除缓存
原因是:如果先删缓存再删数据库,线程1先来更新缓存,将缓存删除后,此时线程2来查询,发现缓存为空, 查询数据库并写入缓存后,线程1才更新数据库。则此时缓存中的数据是未更新的旧数据。
缓存穿透
缓存穿透是指客户端请求的数据在缓存和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
解决方案:
缓存空对象:优点:实现简单,维护方便 缺点:额外的内存消耗,可能造成短期的不一致。
分析:客户端访问不存在的,先访问redis,redis中没有访问数据库,数据库能承载的并发不如redis那么高, 如果大量请求访问不存在数据,造成数据库压力巨大。简单解决是,即使数据库没有该数据,也将该数据存入到redis中。
布隆过滤器
优点:内存占用少,没有多余key 缺点:实现复杂,存在误判可能,因为可能存在哈希冲突
其实是采用哈希的思想解决这个问题的,通过一个巨大的二进制数组,走哈希思想判断当前要查询的这个数据是否存在。如果布隆过滤器判断存在,则放行,这个请求访问redis,哪怕此时redis中的数据过期了,但是数据库中一定存在这个数据,
在数据库中查询出来这个数据后,再将其放入到redis中。假设布隆过滤器判断不存在,则直接返回。
缓存雪崩
缓存击穿
Redis持久化机制
Redis内存管理
给数据设置过期时间有什么用?
如何判断数据是否过期?
通过过期字典,可以看做是hash表,键指向Redis数据库中的某个key值,
值是一个long long类型的整数,该整数保存了key所指向数据库键的过期时间,过期字典存在redsiDb这个结构中
过期数据删除策略:
内存淘汰策略
为了保证redis中都是热点数据,并优化删除策略的问题
volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
Redis为什么快?
一、纯内存操作
二、基于非阻塞的IO多路复用模型
三、单线程反而避免了多线程的死锁和线程上下文切换,性能好
Redis线程模型
Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型 ,这个模型对应的是文件事件处理器,以单线程运行,所以说Redis是单线程模型。
它采用IO多路复用机制来同时监听多个套接字,并根据套接字当前执行的任务选择对应的事件处理器。
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关 闭(close)等操作时, 与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
通过使用IO复用程序监听多个套接字,既实现了高性能的网络通信模型,又能更好的与Redis中其他同样以单线程方式运行的模板进行对接,保持了Redis单线程设计的简单性。
Redis哨兵
如何检测结点是否下线?
Redis1.6之前为什么不使用多线程?
Redis1.6之后为什么使用多线程?
为了提高网络IO的读写性能
Redis如何保证数据不丢失
一、快照方式(RDB)将某一时刻的内存数据,以二进制的方式写入磁盘
二、文件追加(AOF)记录所有的操作命令,以文本的形式追加到文件中
三、混合持久化,4.0之后新增的方式,结合两种优点,在写入时先将当前数据RDB,后续的操作命令使用AOF的形式存入文件。既保证了Redis的重启速度,又能降低数据丢失的风险。
RDB和AOF区别
一、写入方式
二、数据恢复,RDB快
三、数据完整度,
四、文件大小,RDB只保存一个时间点的数据快照,AOF保存所有的写操作,大。
五、性能,AOF可能会降低Redis的写性能,但保证数据安全性,而RDB在进行快照可能阻塞Redis的服务
过期删除策略
一、定期删除策略
二、惰性删除策略
定期删除的过程
取20个键,删除过期键,如果过期比例超过25%,再取
什么情况下会触发内存淘汰策略
一、写操作超过配置
二、启动AOF重写
三、主动释放内存
已设置过期时间,最近最少使用,使用次数最少,随机,没有设置过期时间
禁止写入
Redis集群
一、主从同步,主节点奔溃人为干预
二、哨兵模式,故障自动转移和恢复
三、集群模式
为啥快
缓存击穿
也叫热点key问题,在高并发下某个key的缓存过期或不存在,导致大量请求直接访问数据库,造成数据库压力过大,甚至宕机。
以下是可能有用的解决方案:
-
设置热点数据永不过期:对于一些热点数据,可以设置永不过期,保证数据始终存在于缓存中,避免了缓存失效的问题。
-
延长缓存过期时间:对于一些不是热点数据但访问量较高的数据,可以适当延长缓存过期时间,减少缓存失效的可能。
-
加锁:在缓存失效的瞬间,加锁,只允许一个请求访问数据库,其他请求等待缓存更新后再返回数据。
-
缓存穿透检测:在缓存失效的瞬间,检测请求的 key 是否合法,如果不合法直接返回,避免了无效请求直接访问数据库。
-
增加缓存:在高访问量的情况下,增加缓存节点,提高缓存的命中率,减少对数据库的访问。
-
使用布隆过滤器:布隆过滤器是一种高效的数据结构,可以快速判断一个 key 是否存在于缓存中,从而避免了无效请求直接访问数据库。
-
预加载:在系统启动时,预先将一些热点数据加载到缓存中,避免了缓存失效时的大量请求。
-
使用异步更新缓存:将缓存更新操作异步化,避免了缓存失效时的大量请求堆积。
-
使用分布式锁:将锁的控制分布到多个节点上,提高系统的并发性能和可靠性。
-
使用缓存雪崩保护机制:在缓存失效时,采用一些防止缓存雪崩的机制,如随机过期时间、限流等。
缓存穿透
是指客户端请求的数据在数据库和缓存都不存在,因为数据库查询无数据不会将结果保存在缓存中,这样每次请求都会查询数据库,缓存永远不会生效,这种情况叫缓存穿透。
应对方法:
缓存空对象:即使数据库中没有该数据,也将该数据存入到redis中。
布隆过滤器:请求过来布隆过滤器先进行判断数据库中是否有数据,没有数据直接返回,由于底层是哈希算法,因为哈希冲突存在误判的可能
缓存预热:在系统启动时,将常用数据先加载到缓存,避免缓存穿透
限制请求频率:对于频繁请求的接口,可以限制每个ip访问的频率
缓存雪崩?
是指缓存系统中大量的缓存数据同时失效或过期,导致大量请求到达数据库,导致数据库压力过大甚至宕机。
应对:
设置key随机过期时间:避免大量缓存数据同时过期。
设置缓存数据过期时间不同
多级缓存:将缓存数据分散到不同的缓存服务器中
利用Redis集群提高服务可用性
给缓存业务添加降级限流策略
数据库层面:对于访问频率较高的数据,建立索引,分库分表