在Apache Cassandra 4.1.0中,我们引入了一个名为Guardrails的新框架。该框架帮助操作者避免错误的配置和使用,这些误操作会降低Apache Cassandra集群的性能和可用性。
例如,在schema方面,用户创建太多的表或二级索引,导致资源的过度使用。在查询方面,用户可以运行扫描太多分区的查询,可能涉及集群中的所有节点。更糟糕的是,他们可以使用代价很高的replica-side filtering来运行查询,可能会将所有的表内容读入整个集群中所有节点的内存中。这些都是熟知的Cassandra反模式,管理员必须保持警惕,防止用户使用这些反模式。即使一个人完全了解正确的使用模式,也很容易忘记对非冻结集合的数量的跟踪。
新框架限制了操作者使用Cassandra的方式:
- 关闭特定的特性。
- 不允许一些特定的值。
- 定义数据库量级的软、硬限制。
配置Guardrails
Guardrails 被定义为 Cassandra 配置文件 cassandra.yaml 中的正常属性。看起来是这样:
tables_warn_threshold: -1
tables_fail_threshold: -1
secondary_indexes_per_table_warn_threshold: -1
secondary_indexes_per_table_fail_threshold: -1
allow_filtering_enabled: true
partition_keys_in_select_warn_threshold: -1
partition_keys_in_select_fail_threshold: -1
collection_size_warn_threshold:
collection_size_fail_threshold:
注意不是所有配置都能用guardrails列表。还有很多新的guardrails正在开发中,但这样让你对潜在的选项有所了解。还需要注意,所有guardrails在默认情况下都是关闭的。当启用时,guardrails的配置如下:
tables_warn_threshold: 5
tables_fail_threshold: 10
secondary_indexes_per_table_warn_threshold: 5
secondary_indexes_per_table_fail_threshold: 10
allow_filtering_enabled: false
partition_keys_in_select_warn_threshold: 10
partition_keys_in_select_fail_threshold: 20
collection_size_warn_threshold: 10MiB
collection_size_fail_threshold: 20MiB
cassandra.yaml中定义的guardrails会在节点启动时生效。也可以在运行时通过 JMX 动态更新 guardrails 配置。所有的guardrails被纳入org.apache.cassandra.db.Guardrails的MBean中。会有计划也支持通过virtual table动态更新guardrails,尽管这个选项还不能用。
实战Guardrails
大多数guardrails是在CQL层校验的,不涉及存储引擎或复制。布尔类型guardrails的禁用功能像allow_filtering_enabled,会试图中止使用禁用功能的操作。例如,如果使用带过滤的查询,但布尔类型guardrails被禁用(allow_filtering_enabled: false),我们每次试图运行这些查询时都会报错,而且查询不会运行:
cqlsh> SELECT * FROM k.t1 WHERE v=0 ALLOW FILTERING;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail allow_filtering violated: Querying with ALLOW FILTERING is not allowed"
一些guardrails同时具有软限制和硬限制。当guardrails的软限制被触发时,它会引发一个CQL客户端警告并记录服务器端的警告信息,但不会中止操作。例如,如果我们建立了五个表的软限制(tables_warn_threshold: 5),当我们试图创建第6张表时会得到警告,但表仍然会被创建:
cqlsh> CREATE TABLE k.t6 (k int PRIMARY KEY, v int);
Warnings :
Guardrail tables violated: Creating table t6, current number of tables 6 exceeds warning threshold of 5.
然而,如果达到了硬限制,用户操作会被中止,出现GuardrailViolatedException异常,防止可能的糟糕操作发生。继续前面的例子,如果我们有10张表的硬限制(tables_warn_threshold: 10),我们试图创建第11张表会有报错,第11张表不会被创建:
cqlsh> CREATE TABLE k.t11 (k int PRIMARY KEY, v int);
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail tables violated: Cannot have more than 10 tables, aborting the creation of table t11"
guardrails的触发总是产生GuardrailEvent类型的诊断事件。因此,任何订阅该类型诊断事件的人将能够监控guardrails的违规行为,并触发动作。一些动作如存储指标和联系违规的用户等。
用户和可扩展性
Guardrails只适用于普通用户的操作,他们不会检验超管的查询,也不会检查内部查询。默认情况下,所有普通用户都受制于cassandra.yaml中定义的相同guardrails配置值。然而,guardrails的配置是一个可扩展的API,由接口GuardrailsConfig和GuardrailsConfigProvider定义。这些接口提供每个guardrails的配置,作为用户运行guardrails操作的函数。第三方替代实现可以根据用户或其他一些因素提供不同的guardrails配置。自定义实现可以通过JVM系统属性cassandra.custom_guardrails_config_provider_class来提供。但这个API还没有得到官方的支持,在任何一个次要版本中都可能有破坏向后兼容性。
后台的Guardrails
一般来说,guardrails与一个特定的CQL查询相关联。然而,由于技术上的限制,一些guardrails是在后台检查的,没有与任何查询相关联。例如,对于非冻结集合的大小或数量的guardrails就是这种情况。尽管我们可以在写入一个新的集合时做一些检查,但我们不知道在SSTables上是否存储了之前集合的片段。当然,我们可以对SSTables进行检查,但会涉及一个昂贵的先读后写操作。相反,guardrails在每次SSTable写入磁盘时,例如在memtable flush或 compaction期间,都会检查所有集合的大小。如果检测到一个大的集合,guardrails会被触发并记录日志信息和诊断事件。然而,与普通guardrails不同,这不会中止任何操作。原因是SSTable的写入并不与任何特定的CQL查询相关。相反,它们是过去多次CQL写入的结果,这些写入发生了很久。未来对类似事情的防护措施,如分区大小,可能会以同样的方式工作。
另一个在后台运行guardrails的另一个例子是针对磁盘使用。它的默认配置是:
data_disk_usage_percentage_warn_threshold: -1
data_disk_usage_percentage_fail_threshold: -1
data_disk_usage_max_disk_size:
这个guardrails由一个后台任务定期检查磁盘空间的使用情况。如果磁盘使用量超过了配置中指定的百分比,guardrails将记录日志信息和诊断事件,尽管这不会与任何查询相关联。然而,周期性任务计算出的磁盘使用状态是通过Gossip跟踪和传播的,因此每个节点都知道其其余节点的磁盘使用情况。这些信息将被用来检查写操作的guardrails,并根据目标副本上的磁盘何时接近满的情况来警告或中止查询:
cqlsh> INSERT INTO k.t (k, v) VALUES (1, 10);
InvalidRequest: Error from server: code=2200 [Invalid query] message="Guardrail replica_disk_usage violated: Write request failed because disk usage exceeds failure threshold"
期待更多的Guardrails
向Cassandra添加新的guardrails是比较容易的,因为该框架为几种类型的guardrails提供了基类,以及用于解析配置和测试的实用工具。更重要的是,以guardrails的形式添加新的安全检查应该保证它们具有同构和一致的行为,并且可以从每个新加guardrails特性中受益。
当下的guardrails有:
- 用户keyspaces的数量。
- 用户tables的数量。
- 每张表列的数量。
- 每张表二级索引的数量。
- 每张表物化表的数量。
- UDF的字段数量。
- 集合中元素的数量。
- 所选分区键在IN中的数量。
- 由多个IN限制的笛卡尔乘积选择的分区键的数量。
- 允许的表属性。
- 允许的读一致性级别。
- 允许的写一致性级别。
- 集合个数。
- 查询页数。
- 最小复制因子数。
- 数据磁盘使用量,定义为百分比或绝对大小。
- 是否允许用户定义的时间戳。
- 是否允许GROUP BY查询。
- 是否允许创建二级索引。
- 是否允许创建未压缩的表。
- 是否允许用ALLOW FILTERING查询。
- 是否允许drop或trancate一张表。
值得一提的是,这些guardrails有许多是在最近几个月中新加的,其中一些是由项目的新成员添加的。在我看来,说明了添加新的guardrails很容易,我们预计在未来会看到更多的护栏。
如果你有关于新guardrails的想法,可以提出提议,我们将很乐意看到。
原文标题:Apache Cassandra 4.1 Features: Guardrails Framework
原文作者:Andrés de la Peña
原文地址:https://cassandra.apache.org/_/blog/Apache-Cassandra-4.1-Features-Guardrails-Framework.html




