我有一个表来存储处理失败的消息,我每5分钟通过调度程序重新处理一次消息。
当消息被成功处理时,表中相应的行被删除,因此相同的消息不应该再次被处理。
从表查询中获取行是SELECT * FROM <table_name>
,因此如果大量的行被删除,我们将面临墓碑问题。表使用时间戳作为分区键,message_name(TEXT)作为集群键,TTL为7天,gc_grace_second为2天
根据我的要求,我需要删除记录,否则重复的记录将被处理。有什么办法可以避免墓碑问题吗?
我看到了两个问题。
- Cassandra被用作排队机制,这是一种已建立的反模式。
- 所有分区都用
SELECT * FROM <table_name>
查询,因为没有WHERE
子句
所以在Cassandra中,一些数据模型和用例将生成墓碑。此时,除了设计数据模型使不查询它们之外,没有太多要做的事情。
所以我的想法是用不同的方式划分表。
CREATE TABLE messages (
day TEXT,
message_time TIMESTAMP,
message_text TEXT,
PRIMARY KEY ((day),message_time))
WITH CLUSTERING ORDER BY (message_time DESC);
使用此模型,您可以查询特定day
的所有消息。还可以在day
和message_time
上运行范围查询。例:
SELECT * FROM messages
WHERE day='20210827'
AND message_time > '2021-08-27 04:00';
这将构建自2021-08-27 04:00
以来所有消息的结果集。在请求的时间范围之外(在本例中为04:00之前)生成的任何墓碑都不会被查询。
注意(基于删除模式)在给定的时间范围内仍然可以有墓碑。但这里的想法是,WHERE
条款限制了"爆炸半径",因此,查询较少数量的墓碑应该不是问题。
不幸的是,没有快速解决您的问题的方法。
你面临的挑战是,你正在使用Cassandra作为队列,这不是一个好主意,因为你正好进入了墓碑地狱。我相信你现在已经看到了这篇关于队列和类队列数据集是Cassandra的反模式的博客文章。
如果您在桶中对数据进行不同的建模,每个桶映射到一个表,则可以避免生成大量的墓碑。当您处理完bucket中的所有项后,TRUNCATE
表。这个想法来自Ryan Svihla在他的博客文章"理解删除"中,他在其中介绍了"分区表"的概念。干杯!