缓存失效是一个超级难题。但是,有很多解决方案。保持缓存对象和可能更新的关联域对象的集合(在Redis或其他地方)是一种合理的方法。
对于复杂的相互依赖缓存,有很多方法,包括俄罗斯娃娃缓存和key-based caching。
基于密钥缓存的基本概念是拥有一个复杂的缓存键,其中包含一个固定标识符和一个动态缓存键。
例如,如果您想为用户#123名称为“user_navigation_bar”的对象/片段进行缓存,则需要将缓存写入像user_nav_bar:123:201705071122
这样的密钥。最后一节是用户更新时的时间戳。这是动态的一部分,每当用户做出改变时都会改变。要读取缓存,您只需要用户标识和更新时间戳。对于您示例中的用户列表,您可以为所有用户使用最新创建/更新的时间戳,或者创建/更新用户时使用UserList对象更新时间戳。
使用这种方法,您永远不会更新或删除任何东西。所有写入缓存的内容都是全新的密钥。
你不应该自己删除缓存项目。如果使用最大内存大小和LRU eviction policy(最近最少使用)配置redis,它将自动清除最长未访问的缓存项。当像“user_navigation_bar”这样的项目被更新并且用新的时间戳写入新对象时,旧的将不再被访问并且最终被清除。
如果您使用redis作为缓存对象之外的其他对象,则可能需要运行多个实例。一个配置为具有固定的最大内存大小和可能没有持久性的LRU缓存。另一个更像是一个默认的redis安装,没有永久对象的最大内存和持久性。
如果您使用单个redis实例,则可以为缓存对象设置长期到期,并使用驱逐策略,以便redis仅清除已设置过期的密钥。如果您使用这种方法,请确保将最大内存设置得足够高,以便为您的所有永久数据提供足够的空间。
你的问题非常广泛,但希望这有助于。
缓存是数据一致性和性能之间的折衷。你**不能**实现两者。 –
如果您的应用程序非常繁重,则每次更新相关对象时都可以承受较大的写入损失并刷新所有相关缓存。这种重新执行@ for_stack的观点,因为你放弃了性能的一致性,但只有写操作。对于阅读操作,您的应用将具有一致性和增强的性能。这表明,如果您优先考虑用例并在系统中的其他地方进行权衡,则可以实现这两者。 –