使用Cassandra进行重复数据删除

时间:2015-07-29 15:04:34

标签: cassandra cql cassandra-2.0

我正在寻找使用Cassandra去除事件的最佳方法。

我有很多客户收到活动ID(每秒数千)。我需要确保每个事件id只处理一次且只有一次具有高可靠性和高可用性。

到目前为止,我尝试了两种方法:

  1. 使用事件ID作为分区键,并执行" INSERT ... IF NOT EXISTS"。如果失败,则该事件是重复的,可以删除。这是一个很好的干净方法,但由于Paxos的吞吐量不是很大,特别是对于更高的复制因素,例如3.它也很脆弱,因为IF NOT EXISTS总是需要法定人数才能工作。如果法定人数不可用,则无法退回到较低的一致性。因此,一些关闭节点将完全阻止某些事件ID被处理。

  2. 允许客户端在同一事件ID上发生冲突,然后使用群集列检测冲突。因此,使用事件id作为分区键插入,并将客户端生成的timeuuid作为集群列插入。然后,客户端将等待一段时间(如果其他客户端正在插入相同的分区键),然后读取具有限制1的事件ID,以返回最早的聚簇行。如果它回读的timeuuid与它所插入的匹配,那么它就是"胜利者"并处理该事件。如果timeuuid不匹配,则它是重复的,可以删除。

  3. 碰撞(面包师算法)方法比使用IF NOT EXISTS具有更好的吞吐量和可用性,但它更复杂并且感觉风险更大。例如,如果客户端上的系统时钟不成功,则重复事件看起来像不重复。我的所有客户端和Cass节点都使用NTP,但在同步时钟方面并不总是完美的。

    有人建议使用哪种方法?还有另一种方法吗?

    另请注意,我的群集将设置三个数据中心,DC之间的延迟时间约为100毫秒。

    感谢。

3 个答案:

答案 0 :(得分:3)

如果不是EXISTS不能和库存Cassandra一样扩展(因为协调很慢,但你知道),但可能是“正式,正确”的方式。还有另外两种“有效”的方法:

1)使用外部锁定系统(zookeeper,memcached CAS等),它允许您处理cassandra的协调OUTSIDE。

2)使用反向时间戳技巧的丑陋黑客,以便第一次写入获胜。使用MAX_LONG - (挂起时间)=时间戳,而不是使用客户端提供的与实际挂起时间相对应的时间戳。这样,第一次写入具有最高的“时间戳”,并且将优先于后续写入。这种方法有效,虽然它可以玩DTCS之类的东西(如果你正在做时间序列并且想要使用DTCS,不要使用这种方法,DTCS会非常混乱)和删除一般(如果你想要实际上)使用REAL墓碑删除一行,您还必须使用人工时间戳来编写该墓碑。

值得注意的是,有人试图解决cassandra的“最后写永远胜利”性质 - 例如,CASSANDRA-6412(我曾经在某一点上工作过,并且可能会再次在下个月左右)。

答案 1 :(得分:1)

如果您的负载太高,可能会转移到此处,但是您尝试使用基于event_id的分片redis锁http://redis.io/topics/distlock使用Twemproxy作为redis的代理进行分片。

答案 2 :(得分:1)

我认为,从所有提出的解决方案中,您的第二个解决方案是最好的。但是,只存储聚集列中最旧的值,我会存储所有事件,以保持历史从最旧到最新排序(当插入时你不必检查是否已存在且是最旧的等等,那么你可以选择一个具有最早的写时间属性)。然后我会在你写的时候选择最老的处理。由于cassandra看到插入或插入之间没有区别,我没有看到任何替代方法用cassandra或有人说 - 在外面这样做。