本文共 1534 字,大约阅读时间需要 5 分钟。
为了提高系统吞吐量,业务架构中常引入缓存层。Redis 和 Memcached 等高性能内存缓存被广泛用于缓存实现,但在实际应用中也面临诸多问题。本文以 Redis 为例,探讨缓存应用中常见问题及解决方案。
在缓存中避免存储不存在的数据时,可能会引发缓存穿透问题。当用户尝试查询一个从未存在过的数据时,由于缓存中没有该数据,按照常规逻辑,请求会直接访问数据库。这种现象被称为缓存穿透。
为了减少无意义的数据库访问,可以在缓存中存储表示数据不存在的占位符。与访问从未存在的数据相比,访问已删除数据的概率较高,因此删除数据时应在缓存中放置表示已被删除的占位符。
Redis 提供了 List、Hash、Set 和 SortedSet 等数据结构,称为集合式缓存。集合式缓存的更新逻辑通常较为复杂,但重建逻辑相对简单。然而,重建缓存时可能对数据库造成较大压力。
以文章评论列表为例,当 Redis 缓存为空时,可能有以下两种原因:
在发布评论后更新缓存时,如果发现缓存为空,需区分是因缓存失效还是确实没有评论。不要直接使用 LPUSH 或 ZADD 插入评论。
集合式缓存中的元素应为不可变的对象或对象 ID。例如,若存储评论列表,直接序列化评论对象难以定位修改,且需要在多个集合中存储会增加内存占用。建议使用 ID 作为存储单位,以节省内存。
热点数据的并发读取量大,一旦缓存失效可能导致大量线程访问数据库,引发严重后果。处理热点数据缓存失效问题需谨慎。
在处理复杂操作时,可以使用 Redis 的 RENAME 命令实现原子性操作。例如,若无法保证重建操作的原子性,可以在临时键上完成操作后,使用 RENAME 将临时键替换为正式键。
在使用临时键前,需尝试设置占位符锁,避免冲突。更新或重建缓存时优先使用加随机值方法,遍历时使用加计数器方法。
SortedSet 是 Redis 中唯一支持排序和范围查询的数据结构,可用于灵活场景。
以消息系统为例,可以将消息内容作为 member,预定执行时间作为 score,存储于 SortedSet 中。定期调用 ZRANGEBYSCORE 找出预定执行时间早于当前时间的消息,发送给消费者处理。
类似地,可将关键词作为 member,发生时间作为 score,支持快速查询过去一小时内热搜关键词。使用 ZRANGEBYSCORE 和 ZREMRANGEBYSCORE 命令进行异步更新。
转载地址:http://gtqzz.baihongyu.com/