完整查询日志
Apache Cassandra 4.0 添加了一个新的高性能功能,支持实时查询日志记录 (CASSANDRA-13983)。FQL 适用于生产环境,具有可配置的堆内存和磁盘空间限制,以防止内存不足错误。此功能对于实时流量捕获以及流量回放非常有用。提供的工具可用于调试查询流量和迁移。还添加了新的 nodetool
选项来启用、禁用或重置 FQL,以及一个用于读取和回放二进制日志的新工具。完整查询日志记录 (FQL) 功能使用 Chronicle-Queue 来轮换查询日志。在本文档的剩余部分中,完整查询日志将被称为 **日志**。
FQL 的一些功能包括:
-
通过异步单线程日志条目写入磁盘,减少了对查询延迟的影响。
-
堆内存使用量受加权队列限制,可配置的最大权重位于日志记录线程之前。
-
如果加权队列已满,则生产者可能会被阻塞或样本可能会被丢弃。
-
磁盘利用率受可配置的大小限制,一旦达到限制,就会删除旧的日志段。
-
灵活的模式二进制格式,Chronicle-Wire,用于磁盘上的序列化,可以跳过无法识别的字段,添加新的字段并省略旧的字段。
-
可以使用 JMX 工具
nodetool
启用、禁用或重置(删除磁盘上的数据)。 -
可以在
cassandra.yaml
文件中或使用nodetool
配置设置。 -
引入了新的
fqltool
,目前可以将二进制日志Dump
到可读格式。其他选项包括Replay
和Compare
。
FQL 记录所有成功的 Cassandra 查询语言 (CQL) 请求,包括修改数据的事件和查询数据的事件。虽然审计日志也包含 CQL 请求,但 FQL 日志只记录 CQL 请求。这种差异意味着 FQL 可用于回放或比较日志,而审计日志则不能。FQL 对于调试、性能基准测试、测试和审计 CQL 查询很有用,而审计日志则对于合规性很有用。
在性能测试中,FQL 在仅 WRITE
的工作负载中似乎没有或几乎没有开销,而在 MIXED
工作负载中则只有很小的开销。
记录的查询信息
查询日志包含:
-
所有调用的查询
-
它们被调用的近似时间
-
绑定通配符值所需的任何参数
-
所有查询选项
记录器在查询完成后写入单个或批处理的 CQL 查询,因此只记录成功完成的查询。失败或超时查询不会被记录。记录的不同数据取决于查询的类型。
单个 CQL 查询日志条目包含:
-
query - CQL 查询文本
-
queryOptions - 与查询调用相关的选项
-
queryState - 与查询调用相关的时间戳状态
-
queryTimeMillis - 自查询被调用以来,自纪元以来的近似时间(以毫秒为单位)
批处理 CQL 查询日志条目包含:
-
queries - 查询的 CQL 文本
-
queryOptions - 与查询调用相关的选项
-
queryState - 与查询调用相关的时间戳状态
-
batchTimeMillis - 自批处理被调用以来,自纪元以来的近似时间(以毫秒为单位)
-
type - 批处理的类型
-
values - 要绑定为查询参数的值
由于 FQL 由 Binlog
支持,因此性能和占用空间是可预测的,对日志记录记录生产者影响最小。性能安全措施可防止生产者过载日志,使用加权队列在日志记录落后时丢弃记录。单线程异步写入生成日志。Chronicle-Queue 提供了一种轻松的日志滚动方法。
记录的日志信息
FQL 还跟踪有关存储的日志文件的信息:
-
添加的存储日志文件及其存储影响。如果超过存储限制,则删除它们。
-
已滚动的 Chronicle-Queue 中的日志文件
-
已滚动的日志文件中的字节数
日志记录顺序
记录器遵循一个定义明确的事件顺序:
-
启动写入日志记录的消费者线程。此操作只能执行一次。
-
消费者线程向日志提供记录。如果内存中队列已满,则记录将被丢弃,并且提供将返回
false
值。 -
如果接受,则记录将被输入日志。如果内存中队列已满,则放置线程将被阻塞,直到有空间或被中断。
-
在线程退出时清理缓冲区。最终确定将再次检查,以确保队列中没有滞留者。
-
停止消费者线程。它可以被多次调用。
使用 FQL
要使用 FQL,必须完成两个操作。必须使用 cassandra.yaml
文件或 nodetool
配置 FQL,并且必须使用 nodetool enablefullquerylog
启用日志记录。使用任一方法,至少必须指定日志目录的路径。这两个操作都在每个节点的基础上完成。每个启用的节点都会生成完整的查询日志,因此每个节点上的日志将包含该节点的查询。
在 cassandra.yaml 中配置 FQL
cassandra.yaml
文件可用于在使用 nodetool
启用该功能之前配置 FQL。
该文件包含以下选项,可以取消注释以供使用:
# default options for full query logging - these can be overridden from command line
# when executing nodetool enablefullquerylog
#full_query_logging_options:
# log_dir:
# roll_cycle: HOURLY
# block: true
# max_queue_weight: 268435456 # 256 MiB
# max_log_size: 17179869184 # 16 GiB
# archive command is "/path/to/script.sh %path" where %path is replaced with the file being rolled:
# archive_command:
# max_archive_retries: 10
log_dir
要写入日志,必须在 log_dir
中设置一个现有目录。
该目录必须设置适当的权限,以允许读取、写入和执行。日志记录将根据需要递归地删除目录内容。不要在此目录中放置指向文件系统其他部分的链接。例如,log_dir: /tmp/cassandrafullquerylog
。
max_queue_weight
max_queue_weight
选项设置等待写入文件的记录的内存中队列的最大权重,在阻塞或丢弃之前。该选项必须设置为正值。默认值为 268435456,即 256 MiB。例如,要更改默认值:max_queue_weight: 134217728 # 128 MiB
max_log_size
max_log_size
选项设置在删除最旧的文件之前,在磁盘上保留的滚动文件的最大大小。该选项必须设置为正值。默认值为 17179869184,即 16 GiB。例如,要更改默认值:max_log_size: 34359738368 # 32 GiB
启用 FQL
使用nodetool enablefullquerylog
命令在每个节点上启用 FQL。至少,必须定义日志目录的路径,如果cassandra.yaml
文件中未设置log_dir
。
nodetool enablefullquerylog
命令的语法具有与cassandra.yaml
文件中可以设置的选项相同的选项。此外,nodetool
还具有选项来设置运行命令的主机和端口,以及命令需要身份验证时的用户名和密码。
nodetool [(-h <host> | --host <host>)] [(-p <port> | --port <port>)]
[(-pp | --print-port)] [(-pw <password> | --password <password>)]
[(-pwf <passwordFilePath> | --password-file <passwordFilePath>)]
[(-u <username> | --username <username>)] enablefullquerylog
[--archive-command <archive_command>] [--blocking]
[--max-archive-retries <archive_retries>]
[--max-log-size <max_log_size>] [--max-queue-weight <max_queue_weight>]
[--path <path>] [--roll-cycle <roll_cycle>]
OPTIONS
--archive-command <archive_command>
Command that will handle archiving rolled full query log files.
Format is "/path/to/script.sh %path" where %path will be replaced
with the file to archive
--blocking
If the queue is full whether to block producers or drop samples.
-h <host>, --host <host>
Node hostname or ip address
--max-archive-retries <archive_retries>
Max number of archive retries.
--max-log-size <max_log_size>
How many bytes of log data to store before dropping segments. Might
not be respected if a log file hasn't rolled so it can be deleted.
--max-queue-weight <max_queue_weight>
Maximum number of bytes of query data to queue to disk before
blocking or dropping samples.
-p <port>, --port <port>
Remote jmx agent port number
--path <path>
Path to store the full query log at. Will have it's contents
recursively deleted.
-pp, --print-port
Operate in 4.0 mode with hosts disambiguated by port number
-pw <password>, --password <password>
Remote jmx agent password
-pwf <passwordFilePath>, --password-file <passwordFilePath>
Path to the JMX password file
--roll-cycle <roll_cycle>
How often to roll the log file (MINUTELY, HOURLY, DAILY).
-u <username>, --username <username>
Remote jmx agent username
要启用 FQL,请在要启用日志记录的集群中的每个节点上运行以下命令
$ nodetool enablefullquerylog --path /tmp/cassandrafullquerylog
禁用或重置 FQL
使用nodetool disablefullquerylog
禁用日志记录。使用nodetool resetfullquerylog
停止 FQL 并清除配置目录中的日志文件。重要提示:使用nodetool resetfullquerylog
将删除日志文件!除非需要删除所有日志文件,否则请勿使用此命令。
fqltool
fqltool
命令用于查看(转储)、重放或比较日志。fqltool dump
将二进制日志文件转换为人类可读的格式;只需要提供日志目录作为命令行选项。
fqltool replay
(CASSANDRA-14618) 允许重放日志。该命令可以从不同的机器或集群运行,用于测试、调试或性能基准测试。该命令还可用于重新创建已删除的数据库对象。使用fqltool replay
记录和比较不同版本的 Cassandra 或不同集群对生产流量的不同运行。另一个用途是从多台机器收集日志,并按记录的时间戳“顺序”重放它们。
fqltool replay
的语法为
fqltool replay [--keyspace <keyspace>] [--results <results>]
[--store-queries <store_queries>] --target <target>... [--] <path1>
[<path2>...<pathN>]
OPTIONS
--keyspace <keyspace>
Only replay queries against this keyspace and queries without
keyspace set.
--results <results>
Where to store the results of the queries, this should be a
directory. Leave this option out to avoid storing results.
--store-queries <store_queries>
Path to store the queries executed. Stores queries in the same order
as the result sets are in the result files. Requires --results
--target <target>
Hosts to replay the logs to, can be repeated to replay to more
hosts.
--
This option can be used to separate command-line options from the
list of argument, (useful when arguments might be mistaken for
command-line options
<path1> [<path2>...<pathN>]
Paths containing the FQ logs to replay.
fqltool compare
(CASSANDRA-14619) 比较由fqltool replay
生成的結果文件。该命令使用fqltool replay
中记录的运行并比较日志,输出任何差异(可能是所有查询)。它还将每行存储为单独的编年史文档,以避免在比较时从内存中读取整个结果。
fqltool compare
的语法为
fqltool compare --queries <queries> [--] <path1> [<path2>...<pathN>]
OPTIONS
--queries <queries>
Directory to read the queries from. It is produced by the fqltool
replay --store-queries option.
--
This option can be used to separate command-line options from the
list of argument, (useful when arguments might be mistaken for
command-line options
<path1> [<path2>...<pathN>]
Directories containing result files to compare.
比较设置以下标记
-
标记查询集的开始
version: int16
type: column_definitions
column_count: int32;
column_definition: text, text
column_definition: text, text
....
-
标记失败的查询集
version: int16
type: query_failed
message: text
-
标记行集
version: int16
type: row
row_column_count: int32
column: bytes
-
标记结果集的结束
version: int16
type: end_resultset
示例
-
为了演示 FQL,首先在集群中的一个节点上配置并启用 FQL
$ nodetool enablefullquerylog --path /tmp/cassandrafullquerylog
-
现在使用
cqlsh
创建一个演示键空间和表,并插入一些数据
cqlsh> CREATE KEYSPACE querylogkeyspace
... WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};
cqlsh> USE querylogkeyspace;
cqlsh:querylogkeyspace> CREATE TABLE t (
...id int,
...k int,
...v text,
...PRIMARY KEY (id)
... );
cqlsh:querylogkeyspace> INSERT INTO t (id, k, v) VALUES (0, 0, 'val0');
cqlsh:querylogkeyspace> INSERT INTO t (id, k, v) VALUES (0, 1, 'val1');
-
然后检查数据是否已插入
cqlsh:querylogkeyspace> SELECT * FROM t;
id | k | v
----+---+------
0 | 1 | val1
(1 rows)
-
使用
fqltool dump
命令查看日志。
$ fqltool dump /tmp/cassandrafullquerylog
此命令将返回日志的可读版本。以下是此演示中命令的日志部分示例
WARN [main] 2019-08-02 03:07:53,635 Slf4jExceptionHandler.java:42 - Using Pauser.sleepy() as not enough processors, have 2, needs 8+
Type: single-query
Query start time: 1564708322030
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system.peers
Values:
Type: single-query
Query start time: 1564708322054
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system.local WHERE key='local'
Values:
Type: single-query
Query start time: 1564708322109
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.keyspaces
Values:
Type: single-query
Query start time: 1564708322116
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.tables
Values:
Type: single-query
Query start time: 1564708322139
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.columns
Values:
Type: single-query
Query start time: 1564708322142
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.functions
Values:
Type: single-query
Query start time: 1564708322141
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.aggregates
Values:
Type: single-query
Query start time: 1564708322143
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.types
Values:
Type: single-query
Query start time: 1564708322144
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.indexes
Values:
Type: single-query
Query start time: 1564708322145
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708322
Query: SELECT * FROM system_schema.views
Values:
Type: single-query
Query start time: 1564708345408
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:-2147483648
Query: CREATE KEYSPACE querylogkeyspace
WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};
Values:
Type: single-query
Query start time: 1564708360873
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:-2147483648
Query: USE querylogkeyspace;
Values:
Type: single-query
Query start time: 1564708360874
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:-2147483648
Query: USE "querylogkeyspace"
Values:
Type: single-query
Query start time: 1564708378837
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:-2147483648
Query: CREATE TABLE t (
id int,
k int,
v text,
PRIMARY KEY (id)
);
Values:
Type: single-query
Query start time: 1564708379247
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708379
Query: SELECT * FROM system_schema.tables WHERE keyspace_name = 'querylogkeyspace' AND table_name = 't'
Values:
Type: single-query
Query start time: 1564708397144
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708397
Query: INSERT INTO t (id, k, v) VALUES (0, 0, 'val0');
Values:
Type: single-query
Query start time: 1564708434782
Protocol version: 4
Generated timestamp:-9223372036854775808
Generated nowInSeconds:1564708434
Query: SELECT * FROM t;
Values:
-
为了演示
fqltool replay
,首先删除键空间。
cqlsh:querylogkeyspace> DROP KEYSPACE querylogkeyspace;
-
现在运行
fqltool replay
,分别在--results
和--store-queries
中指定存储查询结果的目录和运行的查询列表
$ fqltool replay \
--keyspace querylogkeyspace --results /cassandra/fql/logs/results/replay \
--store-queries /cassandra/fql/logs/queries/replay \
-- target 3.91.56.164 \
/tmp/cassandrafullquerylog
--results
和--store-queries
目录是可选的,但如果设置了--store-queries
,则也必须设置--results
。--target
指定要重放日志的节点。
-
使用
DESCRIBE KEYSPACES
命令检查键空间是否已重放并再次存在
cqlsh:querylogkeyspace> DESC KEYSPACES;
system_schema system system_distributed system_virtual_schema
system_auth querylogkeyspace system_traces system_views