【发布时间】:2017-01-26 21:44:22
【问题描述】:
我构建了一个自制数据实体存储库,其中包含一个按类型定义保留策略(例如绝对或滑动到期)的工厂。该策略还将缓存类型指定为 httpcontext 请求、会话或应用程序。 MemoryCache 由所有 3 种缓存类型中的缓存代理维护。无论如何,我有一个与存储库绑定的数据实体服务,它为我们的主数据实体加载和保存。这个想法是您使用实体存储库,并且不需要关心实体是否被缓存或从其数据源(在本例中为 db)检索。
一个明显的假设是您需要同步加载/保存事件,因为您需要在从数据源加载实体之前保存缓存的实体。
所以我今天正在调查生产中的数据完整性问题... :)
今天我读到,从 MemoryCache 中删除的实体与 CacheItemRemovedCallback 事件触发之间可能存在很长的间隔(默认为 20 秒)。我对加载和保存数据操作的简单锁定是不够的。此外,CacheItemRemovedCallback 位于 HttpContext 之外的它自己的上下文中,这让事情变得有趣。这意味着我需要将回调函数设为静态,因为我可能会将已处置的实例分配给事件。
因此,一旦我意识到可能存在差距,即我的数据实体不再存在于缓存中,但可能没有保存到它的数据源中,这可能会解释 5000 个中的 3 个损坏订单。在填写长表格时在主数据实体上执行超出策略 20 分钟滑动到期的工作将很容易。这意味着如果他们碰巧在到期的同一时刻提交了加载(通过请求上下文)和保存(通过缓存过期回调)之间的有趣竞争条件。
使用简单的锁就是掷骰子,保存或加载会赢吗?显然,我们需要在下一次从数据源 (db) 加载之前进行保存。理想情况下,当一个项目从缓存中过期时,它会自动写入它的数据源。当实体从缓存中消失但过期的回调尚未触发时,加载操作可能会进入。在这种情况下,将无法在缓存中找到实体,因此将默认从数据源加载。但是,由于保存操作可能尚未开始,从而导致数据完整性损坏,并且可能会破坏您现在保存的缓存数据。
为了完成同步,我需要一个命名的信号锁,所以我选择了 EventWaitHandle。每个用户创建一个
我还有一个冗余,它超时并通过保存操作记录每 10 秒块。正如我所说,默认值意味着从 MemoryCache 中删除实体之间的 20 秒和意识到触发事件进而保存实体之间的时间。
感谢所有跟随我的漫谈的人。鉴于同步要求的性质,EventWaitHandle 锁是最佳解决方案吗?
【问题讨论】:
-
可能使用MemoryCache这种方式不是很好的设计。
-
在复杂程度达到一定程度后,人们总是倾向于将某项设计称为糟糕的设计。但是,我认为跨线程处理缓存并不是不合理的,需要同步所述线程也不是不合理的。关于 MemoryCache,我怀疑是否值得尝试发明一个更好的。我很想听听相反的论点,或者替代方案,或者关于更好的同步机制。
-
也许redis 可以帮助你。
标签: multithreading repository signals memorycache event-wait-handle