Cassandra 读取性能随时间缓慢下降
Cassandra read perfomance slowly decreases over time
我们有一个 Cassandra 集群,它由六个节点组成,每个节点有 4 个 CPU 和 16 Gb RAM 以及底层共享存储 (SSD)。我知道共享存储被认为对 Cassandra 来说是一种不好的做法,但我们的读取级别限制在 3 Gb/s 并且似乎可以可靠地满足紧急磁盘要求。
Cassandra 用作连续流处理的操作数据库。
最初 Cassandra 在 ~1,700 rps
处理请求,它看起来不错:
初始proxyhistograms
:
但几分钟后性能开始下降,在接下来的两个小时内性能下降了三倍多。
同时我们观察到IOWait
时间增加:
而proxyhistograms
显示如下图:
我们无法理解这种行为背后的原因。感谢任何帮助。
已编辑:
Table 定义:
CREATE TABLE IF NOT EXISTS subject.record(
subject_id UUID,
package_id text,
type text,
status text,
ch text,
creation_ts timestamp,
PRIMARY KEY((subject_id, status), creation_ts)
) WITH CLUSTERING ORDER BY (creation_ts DESC);
CREATE TABLE IF NOT EXISTS subject.c_record(
c_id UUID,
s_id UUID,
creation_ts timestamp,
ch text,
PRIMARY KEY(c_id, creation_ts, s_id)
) WITH CLUSTERING ORDER BY (creation_ts DESC);
CREATE TABLE IF NOT EXISTS subject.s_by_a(
s int,
number text,
hold_number int,
hold_type text,
s_id UUID,
PRIMARY KEY(
(s, number),
hold_type,
hold_number,
s_id
)
);
far from 100 Mb
虽然有些人对此有不同的看法,但将分区保持在 1MB 到 2MB 的范围内是最佳的。 Cassandra 在返回大型结果集时通常表现不佳。保持分区大小较小,有助于查询更好地执行。
不知道查询是什么 运行,我 可以 说查询会随着时间的推移而恶化...... time 通常是问题所在。以这个 PRIMARY KEY 定义为例:
PRIMARY KEY((subject_id, status), creation_ts)
这是告诉 Cassandra 将数据存储在一个分区中(从 subject_id
和 status
的串联散列),然后按 creation_ts
排序并强制执行唯一性。这里可能发生的是,似乎没有一种固有的方法来限制 分区的大小。由于集群键是时间戳,每个新条目(到特定分区)都会导致它随着时间的推移变得越来越大。
此外,status
根据定义是临时的,可能会发生变化。为此,必须在每次状态更新时删除并重新创建分区。当像这样建模系统时,我通常建议 status
列作为具有二级索引的非键列。虽然 Cassandra 中的二级索引也不是一个很好的解决方案,但如果结果集不是太大,它可以工作。
对于这种情况,采用“分桶”方法会有所帮助。本质上,选择一个时间组件进行分区,从而确保分区不会无限增长。
PRIMARY KEY((subject_id, month_bucket), creation_ts)
在这种情况下,应用程序写入时间戳 (creation_ts
) 和当前月份 (month_bucket
)。这有助于确保您永远不会在单个分区中放置超过一个月的数据。
现在这只是一个例子。就您而言,整整一个月可能太多了。它可能需要更小,具体取决于您的要求。根据所需的粒度,按周、天甚至小时对时间驱动的数据进行分区的情况并不少见。
我们有一个 Cassandra 集群,它由六个节点组成,每个节点有 4 个 CPU 和 16 Gb RAM 以及底层共享存储 (SSD)。我知道共享存储被认为对 Cassandra 来说是一种不好的做法,但我们的读取级别限制在 3 Gb/s 并且似乎可以可靠地满足紧急磁盘要求。
Cassandra 用作连续流处理的操作数据库。
最初 Cassandra 在 ~1,700 rps
处理请求,它看起来不错:
初始proxyhistograms
:
但几分钟后性能开始下降,在接下来的两个小时内性能下降了三倍多。
同时我们观察到IOWait
时间增加:
而proxyhistograms
显示如下图:
我们无法理解这种行为背后的原因。感谢任何帮助。
已编辑:
Table 定义:
CREATE TABLE IF NOT EXISTS subject.record(
subject_id UUID,
package_id text,
type text,
status text,
ch text,
creation_ts timestamp,
PRIMARY KEY((subject_id, status), creation_ts)
) WITH CLUSTERING ORDER BY (creation_ts DESC);
CREATE TABLE IF NOT EXISTS subject.c_record(
c_id UUID,
s_id UUID,
creation_ts timestamp,
ch text,
PRIMARY KEY(c_id, creation_ts, s_id)
) WITH CLUSTERING ORDER BY (creation_ts DESC);
CREATE TABLE IF NOT EXISTS subject.s_by_a(
s int,
number text,
hold_number int,
hold_type text,
s_id UUID,
PRIMARY KEY(
(s, number),
hold_type,
hold_number,
s_id
)
);
far from 100 Mb
虽然有些人对此有不同的看法,但将分区保持在 1MB 到 2MB 的范围内是最佳的。 Cassandra 在返回大型结果集时通常表现不佳。保持分区大小较小,有助于查询更好地执行。
不知道查询是什么 运行,我 可以 说查询会随着时间的推移而恶化...... time 通常是问题所在。以这个 PRIMARY KEY 定义为例:
PRIMARY KEY((subject_id, status), creation_ts)
这是告诉 Cassandra 将数据存储在一个分区中(从 subject_id
和 status
的串联散列),然后按 creation_ts
排序并强制执行唯一性。这里可能发生的是,似乎没有一种固有的方法来限制 分区的大小。由于集群键是时间戳,每个新条目(到特定分区)都会导致它随着时间的推移变得越来越大。
此外,status
根据定义是临时的,可能会发生变化。为此,必须在每次状态更新时删除并重新创建分区。当像这样建模系统时,我通常建议 status
列作为具有二级索引的非键列。虽然 Cassandra 中的二级索引也不是一个很好的解决方案,但如果结果集不是太大,它可以工作。
对于这种情况,采用“分桶”方法会有所帮助。本质上,选择一个时间组件进行分区,从而确保分区不会无限增长。
PRIMARY KEY((subject_id, month_bucket), creation_ts)
在这种情况下,应用程序写入时间戳 (creation_ts
) 和当前月份 (month_bucket
)。这有助于确保您永远不会在单个分区中放置超过一个月的数据。
现在这只是一个例子。就您而言,整整一个月可能太多了。它可能需要更小,具体取决于您的要求。根据所需的粒度,按周、天甚至小时对时间驱动的数据进行分区的情况并不少见。