Cassandra 吃光了所有磁盘 space
Cassandra eats up all the disk space
我有一个单节点 cassandra 集群,我使用当前分钟作为分区键并插入 TTL 为 12 小时的行。
我看到几个无法解释的问题
/var/lib/cassandra/data/<key_space>/<table_name>
包含多个文件,其中很多都非常旧(比 12 小时还早,大约 2 天)
- 当我尝试在 cqlsh 中执行查询时,我得到很多日志,这些日志似乎表明我的 table 包含很多墓碑
日志:
WARN [SharedPool-Worker-2] 2015-01-26 10:51:39,376 SliceQueryFilter.java:236 - Read 0 live and 1571042 tombstoned cells in <table_name>_name (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:40,472 SliceQueryFilter.java:236 - Read 0 live and 1557919 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:41,630 SliceQueryFilter.java:236 - Read 0 live and 1589764 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:42,877 SliceQueryFilter.java:236 - Read 0 live and 1582163 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:44,081 SliceQueryFilter.java:236 - Read 0 live and 1550989 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:44,869 SliceQueryFilter.java:236 - Read 0 live and 1566246 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:45,582 SliceQueryFilter.java:236 - Read 0 live and 1577906 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:46,443 SliceQueryFilter.java:236 - Read 0 live and 1571493 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:47,701 SliceQueryFilter.java:236 - Read 0 live and 1559448 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:49,255 SliceQueryFilter.java:236 - Read 0 live and 1574936 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
我尝试过多种压缩策略,多线程压缩,我尝试过 运行 使用 nodetool 手动压缩,我也尝试过使用 jmx 强制垃圾收集。
我的一个猜测是压缩不会删除逻辑删除文件
关于如何避免磁盘 space 变得太大的任何想法,我最关心的是 space 中的 运行,我宁愿存储更少(通过使 ttl 更小但目前这没有帮助)
逻辑删除将使用默认配置保留 10 天。这样做的原因是为了确保离线节点在再次加入集群时能够赶上删除。您可以通过设置 gc_grace_seconds 设置来配置此值。
我有一个类似的问题,只是在我的情况下只有一个 table 拒绝收缩(旧文件没有被删除,它们的存储空间 space 不断增长)。我使用 nodetool compactionstats
并看到有很多待处理的压缩任务。
另一个有趣的事情是,我在 nodetool compactionstats 中看到,对于有问题的 table,总是显示 Compaction 类型的压缩,但不是 Tombstone Compaction[=15 类型的压缩=],与表现良好的 tables 相反。
会不会是问题所在?
当您说您使用分钟作为分区键时,我假设您使用时间戳作为每个分区中的聚类列,并且在执行插入时使用 12 小时的 TTL。这将在每个分区中建立墓碑,因为您永远不会删除整行(即一整分钟的分区)。
假设您的密钥空间称为 k1,而您的 table 称为 t2,那么您可以 运行:
nodetool flush k1 t2
nodetool compact k1 t2
sstable2json /var/lib/cassandra/data/k1/t2/k1-t2-jb-<last version>-Data.db
然后你会看到所有这样的墓碑(标有 "d" 表示已删除):
{"key": "00000003","columns": [["4:","54c7b514",1422374164512000,"d"], ["5:","54c7b518",1422374168501000,"d"], ["6:","54c7b51b",1422374171987000,"d"]]}
现在,如果您删除该行(即从 k1.t2 中删除 key=3;),然后再次执行刷新、压缩和 sstable2json,您会看到它发生了变化至:
{"key": "00000003","metadata": {"deletionInfo": {"markedForDeleteAt":1422374340312000,"localDeletionTime":1422374340}},"columns": []}
所以你看到所有的墓碑都不见了,Cassandra 只需要记住整行在特定时间被删除,而不是在特定时间删除该行的一点点。
另一种消除墓碑的方法是 运行对整个 table 进行分类。当你这样做时,Cassandra 只需要记住整个 table 在某个时间被 t运行 处理,因此不再需要保留那个时间之前的墓碑(因为墓碑用于告诉某些数据被删除的其他节点,如果你可以说整个 table 在时间 x 被清空,那么之前的细节不再重要)。
那么你如何在你所问的情况下应用它。那么,您可以使用小时和分钟作为分区键,然后每小时 运行 一个 cron 作业删除 13 小时前的所有行。然后在下一次压缩时,该分区的所有墓碑都将被删除。
或者为每个小时保留一个单独的 table,然后使用 cron 作业每小时 运行 对 13 小时前的 table 进行分类。
另一个有时有用的策略是 "re-use" 集群键。例如,如果您每秒插入一次数据,而不是将高分辨率时间戳作为聚类键,您可以使用时间模 60 秒作为聚类键,并将更独特的时间戳保留为数据字段。因此,在每一分钟的分区内,您会将昨天的墓碑(或过时的信息)更改回今天的活动行,然后您就不会在很多天里积累墓碑。
希望这能为您提供一些尝试的想法。通常当您 运行 遇到墓碑问题时,这表明您需要稍微重新考虑您的模式。
我有一个单节点 cassandra 集群,我使用当前分钟作为分区键并插入 TTL 为 12 小时的行。
我看到几个无法解释的问题
/var/lib/cassandra/data/<key_space>/<table_name>
包含多个文件,其中很多都非常旧(比 12 小时还早,大约 2 天)- 当我尝试在 cqlsh 中执行查询时,我得到很多日志,这些日志似乎表明我的 table 包含很多墓碑
日志:
WARN [SharedPool-Worker-2] 2015-01-26 10:51:39,376 SliceQueryFilter.java:236 - Read 0 live and 1571042 tombstoned cells in <table_name>_name (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:40,472 SliceQueryFilter.java:236 - Read 0 live and 1557919 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:41,630 SliceQueryFilter.java:236 - Read 0 live and 1589764 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:42,877 SliceQueryFilter.java:236 - Read 0 live and 1582163 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:44,081 SliceQueryFilter.java:236 - Read 0 live and 1550989 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:44,869 SliceQueryFilter.java:236 - Read 0 live and 1566246 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:45,582 SliceQueryFilter.java:236 - Read 0 live and 1577906 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:46,443 SliceQueryFilter.java:236 - Read 0 live and 1571493 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:47,701 SliceQueryFilter.java:236 - Read 0 live and 1559448 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
WARN [SharedPool-Worker-2] 2015-01-26 10:51:49,255 SliceQueryFilter.java:236 - Read 0 live and 1574936 tombstoned cells in <table_name> (see tombstone_warn_threshold). 100 columns was requested, slices=[-], delInfo={deletedAt=-9223372036854775808, localDeletion=2147483647}
我尝试过多种压缩策略,多线程压缩,我尝试过 运行 使用 nodetool 手动压缩,我也尝试过使用 jmx 强制垃圾收集。
我的一个猜测是压缩不会删除逻辑删除文件
关于如何避免磁盘 space 变得太大的任何想法,我最关心的是 space 中的 运行,我宁愿存储更少(通过使 ttl 更小但目前这没有帮助)
逻辑删除将使用默认配置保留 10 天。这样做的原因是为了确保离线节点在再次加入集群时能够赶上删除。您可以通过设置 gc_grace_seconds 设置来配置此值。
我有一个类似的问题,只是在我的情况下只有一个 table 拒绝收缩(旧文件没有被删除,它们的存储空间 space 不断增长)。我使用 nodetool compactionstats
并看到有很多待处理的压缩任务。
另一个有趣的事情是,我在 nodetool compactionstats 中看到,对于有问题的 table,总是显示 Compaction 类型的压缩,但不是 Tombstone Compaction[=15 类型的压缩=],与表现良好的 tables 相反。
会不会是问题所在?
当您说您使用分钟作为分区键时,我假设您使用时间戳作为每个分区中的聚类列,并且在执行插入时使用 12 小时的 TTL。这将在每个分区中建立墓碑,因为您永远不会删除整行(即一整分钟的分区)。
假设您的密钥空间称为 k1,而您的 table 称为 t2,那么您可以 运行:
nodetool flush k1 t2
nodetool compact k1 t2
sstable2json /var/lib/cassandra/data/k1/t2/k1-t2-jb-<last version>-Data.db
然后你会看到所有这样的墓碑(标有 "d" 表示已删除):
{"key": "00000003","columns": [["4:","54c7b514",1422374164512000,"d"], ["5:","54c7b518",1422374168501000,"d"], ["6:","54c7b51b",1422374171987000,"d"]]}
现在,如果您删除该行(即从 k1.t2 中删除 key=3;),然后再次执行刷新、压缩和 sstable2json,您会看到它发生了变化至:
{"key": "00000003","metadata": {"deletionInfo": {"markedForDeleteAt":1422374340312000,"localDeletionTime":1422374340}},"columns": []}
所以你看到所有的墓碑都不见了,Cassandra 只需要记住整行在特定时间被删除,而不是在特定时间删除该行的一点点。
另一种消除墓碑的方法是 运行对整个 table 进行分类。当你这样做时,Cassandra 只需要记住整个 table 在某个时间被 t运行 处理,因此不再需要保留那个时间之前的墓碑(因为墓碑用于告诉某些数据被删除的其他节点,如果你可以说整个 table 在时间 x 被清空,那么之前的细节不再重要)。
那么你如何在你所问的情况下应用它。那么,您可以使用小时和分钟作为分区键,然后每小时 运行 一个 cron 作业删除 13 小时前的所有行。然后在下一次压缩时,该分区的所有墓碑都将被删除。
或者为每个小时保留一个单独的 table,然后使用 cron 作业每小时 运行 对 13 小时前的 table 进行分类。
另一个有时有用的策略是 "re-use" 集群键。例如,如果您每秒插入一次数据,而不是将高分辨率时间戳作为聚类键,您可以使用时间模 60 秒作为聚类键,并将更独特的时间戳保留为数据字段。因此,在每一分钟的分区内,您会将昨天的墓碑(或过时的信息)更改回今天的活动行,然后您就不会在很多天里积累墓碑。
希望这能为您提供一些尝试的想法。通常当您 运行 遇到墓碑问题时,这表明您需要稍微重新考虑您的模式。