Cassandra 时间序列建模
Cassandra timeseries modelling
我正在尝试设计一个基于 Cassandra 的时间序列服务,它将跟踪一些日志信息。
数据库将看到相对较高的写入量(预计约 5 亿次插入/天)和不太频繁但大量的读取(想想一天的数据或一个月的数据)。
一个日志条目的简化数据模型如下所示(实际上它有 50 列左右):
log_datetime date
log_some_field text
log_some_other_field text
大多数读取查询将围绕从特定日期范围内选择数据展开,始终按日期降序排列。 (例如 SELECT * FROM logs WHERE log_datetime >= 2012-01-01 and log_datetime <= 2012-02-01 ORDER BY log_datetime DESC
)。这通常会花费大量时间,因此我想尽可能地对其进行优化。
只要写入不是太糟糕,按日期排序和过滤是最重要的功能,第一个想法是定义这样的东西(其中 log_day 是一年中的第几天):
CREATE TABLE logs(
log_day tinyint
log_datetime timeuuid
log_some_field text
log_some_other_field text
PRIMARY KEY (log_day, log_datetime)
WITH CLUSTERING ORDER BY (log_datetime DESC)
)
据我了解,这将使检索尽可能好,因为数据是有序的,并且需要一个分区来检索一天(我可以在客户端处理选择几天的情况)。
但是,这会使写入转到单个服务器,从而显着影响写入性能。另一种选择是选择一些随机集用作分区键,并以循环方式从客户端分配给每个随机集,这将使写入速度更快和可扩展,但会导致更差的读取性能,尤其是当我们必须重新排序时数据。我见过的大多数示例通常在数据集中都有自然分区键,例如 user_id 或 post_id,这不是我的情况。
这里有人有类似的用例吗?如果是这样,您进行了哪些权衡以获得良好的性能?您知道在此类用例中性能更好的数据库吗?
正如您所注意到的,使用天作为分区键意味着一整天都将写入到单个主节点。根据复制因子(通常为 3)在 Cassandra 中复制数据。因此,在任何一天都会写入三个节点。
如果数据量小,这可能是可以接受的。通常不是,人们会使用某种时间段,例如在应用程序中计算的 5 或 10 分钟间隔。
CREATE TABLE logs(
log_day tinyint
timebucket tinyint
log_datetime timeuuid
log_some_field text
log_some_other_field text
PRIMARY KEY ((log_day, timebucket) log_datetime)
WITH CLUSTERING ORDER BY (log_datetime DESC)
)
选择合适的bucket时间间隔与你预期的数据量有关。每天写入 500M,即每秒约 6K。您的时间桶可以按小时循环,因此您只有 6 个(使用 10 分钟),或者跨越一整天有 144 个独特的桶。读取结果时,您的应用程序必须读取给定日期的所有存储桶并合并(但不排序)结果。
在 syslog 类型的应用程序中,在分区键中使用 severity plus day 可以帮助使用自然键在集群中分配负载。它仍然是块状的,因为信息消息的数量比警告、错误或致命消息要多得多。
我正在尝试设计一个基于 Cassandra 的时间序列服务,它将跟踪一些日志信息。 数据库将看到相对较高的写入量(预计约 5 亿次插入/天)和不太频繁但大量的读取(想想一天的数据或一个月的数据)。
一个日志条目的简化数据模型如下所示(实际上它有 50 列左右):
log_datetime date
log_some_field text
log_some_other_field text
大多数读取查询将围绕从特定日期范围内选择数据展开,始终按日期降序排列。 (例如 SELECT * FROM logs WHERE log_datetime >= 2012-01-01 and log_datetime <= 2012-02-01 ORDER BY log_datetime DESC
)。这通常会花费大量时间,因此我想尽可能地对其进行优化。
只要写入不是太糟糕,按日期排序和过滤是最重要的功能,第一个想法是定义这样的东西(其中 log_day 是一年中的第几天):
CREATE TABLE logs(
log_day tinyint
log_datetime timeuuid
log_some_field text
log_some_other_field text
PRIMARY KEY (log_day, log_datetime)
WITH CLUSTERING ORDER BY (log_datetime DESC)
)
据我了解,这将使检索尽可能好,因为数据是有序的,并且需要一个分区来检索一天(我可以在客户端处理选择几天的情况)。 但是,这会使写入转到单个服务器,从而显着影响写入性能。另一种选择是选择一些随机集用作分区键,并以循环方式从客户端分配给每个随机集,这将使写入速度更快和可扩展,但会导致更差的读取性能,尤其是当我们必须重新排序时数据。我见过的大多数示例通常在数据集中都有自然分区键,例如 user_id 或 post_id,这不是我的情况。
这里有人有类似的用例吗?如果是这样,您进行了哪些权衡以获得良好的性能?您知道在此类用例中性能更好的数据库吗?
正如您所注意到的,使用天作为分区键意味着一整天都将写入到单个主节点。根据复制因子(通常为 3)在 Cassandra 中复制数据。因此,在任何一天都会写入三个节点。
如果数据量小,这可能是可以接受的。通常不是,人们会使用某种时间段,例如在应用程序中计算的 5 或 10 分钟间隔。
CREATE TABLE logs(
log_day tinyint
timebucket tinyint
log_datetime timeuuid
log_some_field text
log_some_other_field text
PRIMARY KEY ((log_day, timebucket) log_datetime)
WITH CLUSTERING ORDER BY (log_datetime DESC)
)
选择合适的bucket时间间隔与你预期的数据量有关。每天写入 500M,即每秒约 6K。您的时间桶可以按小时循环,因此您只有 6 个(使用 10 分钟),或者跨越一整天有 144 个独特的桶。读取结果时,您的应用程序必须读取给定日期的所有存储桶并合并(但不排序)结果。
在 syslog 类型的应用程序中,在分区键中使用 severity plus day 可以帮助使用自然键在集群中分配负载。它仍然是块状的,因为信息消息的数量比警告、错误或致命消息要多得多。