【问题标题】:Cassandra data model for application logs (billions of operations!)用于应用程序日志的 Cassandra 数据模型(数十亿次操作!)
【发布时间】:2014-08-15 04:17:28
【问题描述】:

假设,我想从一个每秒产生 1000-5000 条记录的大型应用程序集群中收集日志。将来,这个数字可能会达到每秒 100000 条记录,从 10000 个强大的数据中心聚合而成。

CREATE TABLE operation_log (
       -- Seconds will be used as row keys, thus each row will
       -- contain 1000-5000 log messages.
       time_s bigint,
       time_ms int, -- Microseconds (to sort data within one row).
       uuid uuid, -- Monotonous UUID (NOT time-based UUID1)

       host text,
       username text,
       accountno bigint,
       remoteaddr inet,
       op_type text,
       -- For future filters — renaming a column must be faster
       -- than adding a column?
       reserved1 text,
       reserved2 text,
       reserved3 text,
       reserved4 text,
       reserved5 text,

       -- 16*n bytes of UUIDs of connected messages, usually 0,
       -- sometimes up to 100.
       submessages blob,
       request text,
       PRIMARY KEY ((time_s), time_ms, uuid)) -- Partition on time_s
-- Because queries will be "from current time into the past"
WITH CLUSTERING ORDER BY (time_ms DESC)

CREATE INDEX oplog_remoteaddr ON operation_log (remoteaddr);
...
(secondary indices on host, username, accountno, op_type);
...
CREATE TABLE uuid_lookup (
       uuid uuid,
       time_s bigint,
       time_ms int,
       PRIMARY KEY (uuid));

我想使用 OrderedPartitioner,它将通过其time_s(秒)将数据分布在整个集群中。随着更多应用程序日志聚合器添加到应用程序集群,它还必须扩展到数十个并发数据写入器(唯一性和一致性由 PK 的uuid 部分保证)。

分析师必须通过执行这些类型的查询来查看这些数据:

  • 范围查询time_s,过滤任何数据字段 (SELECT * FROM operation_log WHERE time_s < $time1 AND time_s > $time2 AND $filters),
  • 从上一个结果中分页查询(SELECT * FROM operation_log WHERE time_s < $time1 AND time_s > $time2 AND token(uuid) < token($uuid) AND $filters),
  • 计数在一个时间范围内由任何数据字段过滤的消息 (SELECT COUNT(*) FROM operation_log WHERE time_s < $time1 AND time_s > $time2 AND $filters),
  • 按某个范围内的任何数据字段对所有数据进行分组(将由应用程序代码执行),
  • 通过uuid(数百条SELECT * FROM uuid_lookup WHERE uuid IN [00000005-3ecd-0c92-fae3-1f48, ...])请求数十或数百条日志消息。

我的问题是:

  • 这是一个健全的数据模型吗?
  • 是使用OrderedPartitioner 去这里的方式吗?
  • 为潜在过滤器配置几列是否有意义?或者每隔一段时间添加一个列是否足够便宜,可以在具有一些预留空间的 Cassandra 集群上运行?
  • 如果并发查询器的数量永远不会超过 10,是否有任何东西阻止它从数百个聚合器扩展到每秒 100000 个插入行并存储 PB 或 2 个可查询数据?

【问题讨论】:

    标签: cassandra data-modeling


    【解决方案1】:

    这个数据模型接近一个健全的模型,有几个重要的修改/警告:

    • 不要不要使用 ByteOrderedPartitioner,尤其是不要以时间为关键。这样做会导致集群上出现严重的热点,因为您将只对数据范围的一部分(以及集群的一小部分)进行大部分读取和所有写入。 使用 Murmur3Partitioner

    • 要启用您的范围查询,您需要一个标记键--您可以提前知道的键。对于日志数据,这可能是一个时间桶 + 一些其他不基于时间的已知值(因此您的写入是均匀分布的)。

    • 您的索引可能没问题,但如果不知道您的数据就很难判断。 确保您的值的基数较低,否则索引将无法很好地扩展。

    • 确保任何潜在的过滤列都遵守低基数规则。更好的是,如果您不需要实时查询,使用 Spark 进行分析。您应该根据需要创建新列,因为这没什么大不了的。 Cassandra 很少存储它们。更好的是,如果您使用 Spark,您可以将这些值存储在地图中

    • 如果您遵循这些准则,您可以随意扩展。否则,您的性能将非常差,并且可能会获得与单个节点相当的性能。

    【讨论】:

    • 非常感谢!是否不推荐使用 BOP,因为它会将密钥空间分成两半(因此,对于两个节点,一个节点始终获取当前写入并将一些“旧”数据排放到另一个节点)?是否可以制作一个可以均匀分布数据的分片键,但仍然允许我对我的 PK 的前两个组件(秒和毫秒)进行范围查询?
    • 另外,能否请您详细说明哨兵密钥?有时原始日志必须逐页浏览,因此唯一的范围查询键是时间,而时间具有可怕的基数。
    • 您的密钥必须产生均匀分布的哈希以避免热点。所以它应该类似于 [time_bucket]:[origin_host],所以它分布良好并且在查询时是可知的。不推荐使用 BOP,因为它会导致负载不均匀(每个节点拥有一系列键,这些键与 BOP 顺序排列)。提到两个节点让我很困扰,因为三个是绝对最小值,即使这样在生产中也不是很合理。这是因为 RF=3 在大多数情况下非常理想。
    • origin_host在key中起什么作用?是否必须在范围查询中的选择中明确提及?
    • 是的,它必须明确命名。这只是一个例子;您可以选择任何不基于您在查询时可以知道的时间的内容。
    猜你喜欢
    • 2011-11-29
    • 2018-02-18
    • 2015-12-03
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    • 2012-09-24
    相关资源
    最近更新 更多