本地缓存 + 分布式缓存
本地缓存:Guava、Ehcache、Caffeine
分布式缓存:MemCached、Redis
本地缓存一般存储更新频率低,访问频率高数据,分布式缓存一般存储更新频率很高的数据
本地缓存作为一级缓存,分布式缓存作为二级缓存;当用户获取数据时,先从一级缓存中获取数据,如果一级缓存有数据则返回数据,否则从二级缓存中获取数据,如果二级缓存中有数据则更新一级缓存,然后将数据返回客户端,如果二级缓存没有数据则去数据库查询数据,然后更新二级缓存,接着再更新一级缓存,最后将数据返回给客户端
本地缓存在分布式系统中会存在不一致的问题,通过 Redis 的消息发布/订阅(Pub/Sub)机制,可以有效地解决本地缓存的一致性问题,当多个实例的本地缓存存在数据一致性问题时,Redis Pub/Sub 机制可以通过实时通知系统中的其他节点缓存更新,从而确保缓存数据的同步。
解决方案思路
-
数据变更时发布消息
- 当某个节点的数据发生变化时,它会通过 Redis 发布一个消息,通知所有其他节点更新或失效相关的缓存。这可以通过 Redis 的
PUBLISH命令实现。 - 消息通常包含缓存的键(key)和操作类型(例如,更新、删除等)。
- 当某个节点的数据发生变化时,它会通过 Redis 发布一个消息,通知所有其他节点更新或失效相关的缓存。这可以通过 Redis 的
-
其他节点订阅相关消息
- 其他所有缓存实例通过 Redis 的
SUBSCRIBE命令订阅相关的频道(Channel)。当某个节点发布消息时,所有订阅该频道的节点都会收到通知。 - 一旦接收到数据更新消息,订阅的节点可以根据消息内容去更新或删除本地缓存。
- 其他所有缓存实例通过 Redis 的
-
缓存更新或删除
- 在接收到数据更新的通知后,订阅的节点根据消息内容执行相应的缓存操作,确保本地缓存的数据与数据源保持一致。例如,如果消息表示某个数据被修改了,订阅者会删除或更新本地缓存中相应的条目。
具体流程
-
数据变更节点(发布者):
PUBLISH cache-update "user:123"当某个节点(比如,进行数据修改操作的服务)更新了数据库中的数据时,它会通过 Redis 的
PUBLISH命令向一个特定的频道发布消息。例如,可以发布一个包含缓存 key 的消息,或者直接发布数据更新的详细信息。在这个例子中,cache-update是频道名,消息内容user:123表示某个用户数据的缓存需要更新。 -
缓存更新节点(订阅者):
SUBSCRIBE cache-update其他节点(缓存持有者)通过 Redis 的
SUBSCRIBE命令订阅cache-update频道,以接收消息。这些节点会监听消息,当接收到user:123这样的更新通知时,它们会根据自己的业务逻辑更新本地缓存,删除或更新与该键相关的数据。 -
缓存更新操作:
当订阅者接收到更新消息后,执行相应的缓存操作(例如,删除缓存条目,重新加载数据或更新缓存)。
redis_client.delete("user:123") # 删除缓存 # 或者 redis_client.set("user:123", new_data) # 更新缓存
优势
-
实时同步:
使用 Redis Pub/Sub 机制,能够在多个节点之间实现几乎实时的缓存同步,确保缓存更新的一致性。 -
减少缓存不一致的概率:
即使数据在多个节点之间有多个副本,通过 Pub/Sub 可以避免由于缓存不及时失效或更新导致的一致性问题。 -
解耦缓存更新逻辑:
发布者和订阅者之间是解耦的,发布者只负责发布消息,不需要关心谁在接收和处理该消息,增加了系统的灵活性。 -
支持分布式系统:
在多实例或多数据中心的分布式环境中,Redis Pub/Sub 机制可以有效地广播消息,实现跨节点的缓存一致性。
注意事项
-
消息丢失问题:
Redis 的 Pub/Sub 是基于发布-订阅的模型,消息一旦发布,如果订阅者没有及时收到,消息会丢失。如果对消息的可靠性要求较高,可以考虑使用 Redis Streams 或结合消息队列(如 Kafka)来进行消息持久化。 -
缓存一致性延迟:
在极高并发或复杂场景下,消息可能存在延迟。可以考虑使用 Redis 的 事务机制 或 Lua 脚本 来确保操作的原子性。 -
订阅者性能:
如果订阅的消息量过大或订阅者处理不及时,可能会导致系统性能下降。因此,订阅者需要进行合适的优化,如批量处理等。
1015

被折叠的 条评论
为什么被折叠?



