核心作用
内存存储比硬盘存储极大地提高了读写速度。分布式系统提高了 Redis 的高可用性,集群部署、主从复制突破单机模式的性能瓶颈。
基本数据类型
- 字符串(String):Redis 中的字符串是二进制安全的,可以存储任何类型的数据,如文本、数字、图片(以 base64 编码或路径形式)以及序列化后的对象。支持高效的增减操作和过期时间设置。
- 列表(List):基于双向链表实现,支持按序插入和删除元素。在 Redis 3.2 之后,引入了 QuickList,结合了 LinkedList 和 ZipList 的优势,提高了性能。
- 集合(Set):基于哈希表实现的无序集合,支持自动去重和交集、并集、差集等操作。
- 哈希(Hash):键值对集合,可以存储多个字段和值,类似于编程语言中的 map 对象。底层实现可以是 ziplist(Redis 7.0 之前)或 listpack(Redis 7.0 及之后)和 hashtable。
- 有序集合(Sorted Set,ZSet):基于跳表(Skip List)和哈希表实现,支持按分数排序和范围查询。
- 位图(Bitmap):基于位数组实现,支持位标志操作,空间占用小,高效操作。
- HyperLogLog:基于近似计数算法实现,用于统计大规模唯一元素的基数,极低的内存消耗,但结果是近似值,可能存在误差。
Redis 应用场景
- 分布式锁
- 会话状态管理:缓存用户Session、Token、登录状态
- 排行榜/计数器
- 消息队列(发布/订阅)
- 附近位置服务
缓存问题
- 缓存击穿
- 缓存雪崩
- 缓存预热
缓存击穿
指查询一个不存在的数据,由于缓存中也没有,导致每次都去数据库中查询,而数据库也没有该数据,这样每次都进行了无用的数据库查询,增加了数据库压力。
解决方案:
- 空值缓存:当数据库查询不到数据时,仍然将键与空值(如null)放入缓存,并设置一个较短的过期时间。这样,后续的相同查询可以直接从缓存中获取空值,避免了对数据库的频繁无效查询。
- 布隆过滤器:使用布隆过滤器等数据结构预先判断数据是否存在,从而避免对不存在的数据进行查询。
- 屏蔽IP:记录并分析访问不存在的数据请求,获取其IP地址,如果在规定时间内此IP超过某个设定值,就将它加入黑名单,在系统中进行拦截。
缓存雪崩
指当大量缓存同时过期,或者缓存服务宕机时,所有请求都会直接打到数据库上,导致数据库压力过大甚至宕机。
解决方案:
- 缓存过期时间随机化:避免大量缓存同时过期,可以将缓存的过期时间设置为一个范围内的随机值。
- 使用高可用缓存集群:如Redis Cluster或Sentinel,确保缓存服务的高可用性。
- 降级和熔断:在检测到数据库压力过大时,通过降级策略返回默认数据或错误信息,并通过熔断机制防止进一步的压力传递。
- 缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存。
缓存预热
指在系统启动时或缓存清空后,大量请求同时到达,由于缓存中无数据,导致大量请求直接访问数据库,造成数据库压力骤增。
解决方案:
- 预加载缓存:在系统启动时或定期地,预先将热点数据加载到缓存中。
- 懒加载与异步更新:在缓存未命中时,不仅从数据库中加载数据,还触发异步任务更新其他相关缓存项。
- 根据历史数据访问模式:预测哪些数据可能被频繁访问,然后有选择性地加载这些数据到缓存中。
- 根据特定事件触发:例如数据更新、系统启动等,在事件发生时,执行缓存加载操作。