缓存失效策略
Cache invalidation strategy
在我当前的应用程序中,我们正在处理一些很少更改的信息。
为了性能优化,我们希望将它们存储在缓存中。
但问题在于 每当更新这些对象时都使这些对象失效。
我们还没有最终确定缓存产品。
当我们在 Azure 上构建此应用程序时,我们可能会使用 Azure Redis cache
.
一种策略是在 Update API
中添加代码,这将使缓存中的对象无效。
我不确定这是否是一种干净的方式?
我们不想使用基于时间 (TTL) 的缓存过期。
您能否建议一些其他用于缓存失效的策略?
在 Update 阶段使缓存失效是一种可行的方法,过去被广泛使用。
更新发生时,您有两个选择:
- 您可以尝试在更新操作期间设置新值,或者
- 只需删除旧的并在读取操作期间更新。
如果你想要一个LRU cache,那么UPDATE可能只是删除旧值,并且第一次获取对象时,你将再次创建它从实际数据库读取后。但是,如果您知道您的缓存非常小并且出于与数据大小不同的考虑而正在使用另一个主数据库,则可以在 UPDATE 期间直接更新。
然而,这一切还不足以完全一致。
例如,当您写入数据库时,Redis
缓存可能有几秒钟不可用,因此数据在两者之间保持不同步。
在这种情况下你会怎么做?
您可以同时使用多个选项。
- 无论如何都要设置一个 TTL,以便刷新最终损坏的数据。
- 使用懒读修复。当您从数据库中读取时,如果值匹配,请不时检查主数据库。如果没有更新缓存项(或删除它)。
- 使用时代或类似的方式来访问您的数据。并非总是可能,但有时您会访问有关给定对象的缓存数据。如果可能,您可以在每次修改对象时更改对象 ID/handle,这样您就不可能访问缓存中的陈旧数据:每个键名都引用一个 特定的 版本你的对象。
所以 del-cache-on-update 和 write-cache-on-read 是基本策略,但您可以使用其他附加系统最终修复不一致。
其实还有一个选项可以代替上面的选项,就是有一个后台进程使用Redis SCAN
来逐个key验证是否存在不一致。此过程可能很慢,并且可以 运行 针对您的数据库的副本。
正如您在此处看到的,主要思想始终是相同的:如果对缓存的更新失败,请不要将其作为可能永远存在的永久性问题,让它有机会在某个时候自行修复稍后。
我认为 lambda(ish) 架构适用于您的用例。
- 即时业务使用的实时更新
- 批量数据加载以修复任何失败的记录
- 批量数据加载以删除 invalid/archived 条记录中的任何一条。
对于实时更新,您必须在应用程序的代码库上工作,以将数据写入数据库和缓存。
对于批量数据加载,您可以查看数据摄取工具,例如 logstash/fluentd 到 "pull" 数据库中的最新数据,并将它们推送到缓存中。这可以基于始终递增的列(ID 号或时间戳)来完成。
我这边有 Oracle 数据库。 Logstash JDBC 插件在提取最新记录方面做得不错。 logstash 输出可以格式化并打印到 Redis 可以使用的文件中。我写了一个小 bash 脚本来协调这个。测试了 300 万条记录并且工作正常。
在我当前的应用程序中,我们正在处理一些很少更改的信息。
为了性能优化,我们希望将它们存储在缓存中。
但问题在于 每当更新这些对象时都使这些对象失效。
我们还没有最终确定缓存产品。
当我们在 Azure 上构建此应用程序时,我们可能会使用 Azure Redis cache
.
一种策略是在 Update API
中添加代码,这将使缓存中的对象无效。
我不确定这是否是一种干净的方式?
我们不想使用基于时间 (TTL) 的缓存过期。
您能否建议一些其他用于缓存失效的策略?
在 Update 阶段使缓存失效是一种可行的方法,过去被广泛使用。
更新发生时,您有两个选择:
- 您可以尝试在更新操作期间设置新值,或者
- 只需删除旧的并在读取操作期间更新。
如果你想要一个LRU cache,那么UPDATE可能只是删除旧值,并且第一次获取对象时,你将再次创建它从实际数据库读取后。但是,如果您知道您的缓存非常小并且出于与数据大小不同的考虑而正在使用另一个主数据库,则可以在 UPDATE 期间直接更新。
然而,这一切还不足以完全一致。
例如,当您写入数据库时,Redis
缓存可能有几秒钟不可用,因此数据在两者之间保持不同步。
在这种情况下你会怎么做?
您可以同时使用多个选项。
- 无论如何都要设置一个 TTL,以便刷新最终损坏的数据。
- 使用懒读修复。当您从数据库中读取时,如果值匹配,请不时检查主数据库。如果没有更新缓存项(或删除它)。
- 使用时代或类似的方式来访问您的数据。并非总是可能,但有时您会访问有关给定对象的缓存数据。如果可能,您可以在每次修改对象时更改对象 ID/handle,这样您就不可能访问缓存中的陈旧数据:每个键名都引用一个 特定的 版本你的对象。
所以 del-cache-on-update 和 write-cache-on-read 是基本策略,但您可以使用其他附加系统最终修复不一致。
其实还有一个选项可以代替上面的选项,就是有一个后台进程使用Redis SCAN
来逐个key验证是否存在不一致。此过程可能很慢,并且可以 运行 针对您的数据库的副本。
正如您在此处看到的,主要思想始终是相同的:如果对缓存的更新失败,请不要将其作为可能永远存在的永久性问题,让它有机会在某个时候自行修复稍后。
我认为 lambda(ish) 架构适用于您的用例。
- 即时业务使用的实时更新
- 批量数据加载以修复任何失败的记录
- 批量数据加载以删除 invalid/archived 条记录中的任何一条。
对于实时更新,您必须在应用程序的代码库上工作,以将数据写入数据库和缓存。
对于批量数据加载,您可以查看数据摄取工具,例如 logstash/fluentd 到 "pull" 数据库中的最新数据,并将它们推送到缓存中。这可以基于始终递增的列(ID 号或时间戳)来完成。
我这边有 Oracle 数据库。 Logstash JDBC 插件在提取最新记录方面做得不错。 logstash 输出可以格式化并打印到 Redis 可以使用的文件中。我写了一个小 bash 脚本来协调这个。测试了 300 万条记录并且工作正常。