我要解决的问题
我有一个工作进程,它通过从工作人员收到的一些 JSON 消息中累积值来更改资源的属性(比如说 MyResource)。我正在尝试提出一种避免重复累积的最佳方法,即使工作进程收到两次或更多次相同的 JSON 消息也是如此。
这是我试过的
方案一
每条 JSON 消息都有一个唯一的时间戳,这取决于 JSON 消息的创建时间,我将该时间戳保存在 MyResource 上,如果 JSON 消息的时间戳值低于 MyResource 上的值,我将拒绝该消息。
问题
由于整个架构是异步的,因此消息可能以任何顺序接收,不一定与创建时的顺序相同。
解决方案2
我在 MyResource 上创建了一个新属性(比如 added_ids)。每条 JSON 消息都有一个唯一的 ID,我将该 ID 附加到 MyResource.added_ids。并且每次都为已处理的 JSON 消息累积使用的 added_ids。
问题
我正在使用 mongo 来存储 MyResource。由于每个 MyResource 的 JSON 消息很多,因此每个 MyResource 文档都开始因这个 id 数组而爆炸。在数组中查找也是一项昂贵的操作。
我在找
我正在寻找一个可以处理异步性质并且不会破坏我的 mongo 文档的答案。另外我不是在寻找一个确切的解决方案,是否有用于解决类似问题的算法/模式?我尝试使用谷歌搜索,但我不知道如何称呼这个问题来获得相关结果。
最佳答案
我认为您的第二个解决方案是正确的,但是如果您将每个 added_id 存储为自己的键值而不是数组,性能可能会更好。
逻辑非常简单:每次从队列中获取输入时,在缓存中查找是否存在该消息 ID 的条目。如果有条目,则不要累积该输入。否则,累积输入并将 key 存储在缓存中。
正如您所提到的,这种方法存在可扩展性问题,因为缓存会无限增长。要解决此问题,您可以使用具有过期和逐出功能的缓存。解决此问题的最简单方法是明确设置您编写的每个 key 的“过期时间”。这是由 Mongo、Memcached 和 Redis 支持的。
问题是,即使你在每个点都设置了“expires at”,如果负载足够大,你的缓存仍然会耗尽内存。所以你需要一个回退——当缓存内存不足时要做的事情。为此,您可以使用具有“自动驱逐”功能的缓存,这意味着它有一种算法可以在必要时删除内容。
看起来 Mongo 不支持这样的东西(它是一个具有缓存功能的数据库,而不是适当的缓存)。 Memcache 使用 LRU 算法(参见 https://github.com/memcached/memcached/wiki/UserInternals#when-are-items-evicted )。 Redis 有多种算法供您选择(请参阅 https://redis.io/topics/lru-cache )。
我要记住的另一件事是,在分布式或多线程应用程序上执行整个过程会引入竞争条件。假设您有 20 台工作机器,无论出于何种原因,它们几乎都在同一时间收到相同的消息。他们每个人都会检查缓存中的条目,但什么也找不到,因此没有一个被标记为重复。
要解决此问题,您可以对在同一台机器上运行的多个线程使用互斥锁/信号量(垂直缩放),或者如果您有多个机器(水平缩放),则可以使用“分布式锁”。参见 https://redis.io/topics/distlock
编辑
我收到一条提示,Mongo 可以使用 Capped Collections 进行自动驱逐.它仅支持 FIFO 逐出(总是首先使最旧的数据过期),这无论如何都可以满足您的需求。
关于ruby - 如何避免重复添加?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55755792/