【发布时间】:2016-07-02 00:41:56
【问题描述】:
我需要处理队列中的多条记录。但由于一些外部问题,这些项目可能会偶尔出现多次。 我只需要处理一次物品
我计划使用 PFADD 到 redis 每条记录(作为 md5sum),然后查看是否返回成功。如果这显示没有增量,则记录是重复的,否则处理记录。
这看起来很简单,但我在使用 PFADD 时误报太多了
有没有更好的方法来做到这一点?
【问题讨论】:
标签: redis
我需要处理队列中的多条记录。但由于一些外部问题,这些项目可能会偶尔出现多次。 我只需要处理一次物品
我计划使用 PFADD 到 redis 每条记录(作为 md5sum),然后查看是否返回成功。如果这显示没有增量,则记录是重复的,否则处理记录。
这看起来很简单,但我在使用 PFADD 时误报太多了
有没有更好的方法来做到这一点?
【问题讨论】:
标签: redis
作为概率数据结构,Redis 的 HyperLogLog 表现出 0.81% 的标准误差。您可以通过使用多个 HLL 来减少(但永远不会消除)误报的可能性,每个 HLL 都会计算您记录中不同哈希函数的值。
另请注意,如果您使用的是单个 HLL,则无需对记录进行哈希处理 - 只需 PFADD 原样即可。
或者,使用 Redis 集来保留所有标识符/哈希/记录,并使用 SISMEMBER 进行 100% 准确的成员资格测试。当您存储每个已处理的元素时,这种方法需要更多 (RAM) 资源,但除非您的队列真的很大,否则对于适度的 Redis 实例来说应该不是问题。为了控制内存消耗,请根据日期在 Set 之间切换并在 Set 键上设置到期时间(另一种方法是使用单个 Sorted Set 并通过将旧项目保留在分数中来手动从中删除旧项目)。
【讨论】:
SADD 将成员添加到集合中,SISMEMBER 只是一个成员测试。是的,所有值都将保存在 RAM 中 - 7000 万个 md5 值应该是大约 2GB 的原始数据。
通常在分布式系统中,您必须在处理项目之间进行选择:
只处理一次会很方便,但这通常是不可能的。
话虽如此,对于您的特定用例可能存在可接受的解决方法,并且正如您建议的那样,存储已处理的项目可能是可接受的解决方案。
请注意,尽管PFADD 使用 HyperLogLog,它速度很快,scales but is approximate 关于项目的数量,所以在这种情况下,我认为这不是你想要的。 但是,如果您认为错误概率很小,那么这里最合适的数据结构是Bloom filter(如here for Redis 所述),它可以以非常节省内存的方式实现。
一个简单、高效且 recommended 的解决方案是使用一个简单的 redis 键(例如哈希)来存储类似布尔值(“0”、“1”或“true”、“false”)例如使用HSET 或SET with the NX 选项指令。如果您愿意,也可以将其放在namespace 下。它还具有能够使密钥过期的额外好处。
它会避免你使用一个集合(不是SET 命令,而是SINTER、SUNION 命令),如果你想扩展到更多,它不一定适用于Redis cluster不止一个节点。 SISMEMBER 仍然很好(但缺少一些哈希函数,例如生存时间)。
如果您使用散列,我还建议您选择collisions than md5 机会较少的散列函数(冲突意味着两个不同的对象最终具有相同的散列)。
哈希的另一种方法是在将每个项目放入队列时为其分配一个 uuid(如果您想获得一些时间信息,则为 squuid)。
【讨论】: