审计日志插件

Doris 的审计日志插件是在 FE 的插件框架基础上开发的。是一个可选插件。用户可以在运行时安装或卸载这个插件。

该插件可以将 FE 的审计日志定期的导入到指定的系统表中,以方便用户通过 SQL 对审计日志进行查看和分析。

使用审计日志插件

从 Doris 2.1 版本开始,审计日志插件作为内置插件,直接集成到了 Doris 内核中。用户无需在额外安装插件。

集群启动后,会在 __internal_schema 库下创建名为 audit_log 的系统表,用于存储审计日志。

  1. 如果是从老版本升级上来的用户,可以继续使用之前的方式。也可以卸载之前的插件,使用内置插件。但注意内置插件会将新的审计日志写入到新的表中,而不是原有的审计日志表中。

  2. 如果是 Doris 2.1 之前的版本,请参阅之后的 编译、配置和部署 章节。

开启插件

通过全局变量 enable_audit_plugin 可以随时开启或关闭审计日志插件(默认为关闭状态),如:

set global enable_audit_plugin = true;

开启后,Doris 会将开启后的审计日志写入 audit_log 表。

可以随时关闭审计日志插件:

set global enable_audit_plugin = false;

关闭后,Doris 将会停止 audit_log 表的写入。已写入的审计日志不会变化。

相关配置

审计日志表是一张动态分区表,按天分区,默认保留最近 30 天的数据。

以下 3 个全局变量可以控制审计日志表的一些写入行为:

  • audit_plugin_max_batch_interval_sec:审计日志表的最大写入间隔。默认 60 秒。
  • audit_plugin_max_batch_bytes:审计日志表每批次最大写入数据量。默认 50MB。
  • audit_plugin_max_sql_length:审计日志表里记录的语句的最大长度。默认 4096。
  • audit_plugin_load_timeout: 审计日志导入作业的默认超时时间。默认 600 秒。

可以通过 set global xxx=yyy 进行设置。

FE 配置项:

  • skip_audit_user_list (自 3.0.1 支持)

    如果不希望某些用户的操作被审计日志记录,可以通过这个配置修改。

    1. skip_audit_user_list=root
    2. -- or
    3. skip_audit_user_list=user1,user2

编译、配置和部署

Doris 2.1 版本之前的用户,请参阅如下方式使用审计日志插件。

FE 配置

审计日志插件框架在 Doris 中是默认开启的的,由 FE 的配置 plugin_enable 控制

AuditLoader 配置

  1. 下载 Audit Loader 插件

    Audit Loader 插件在 Doris 的发行版中默认提供,通过 DOWNLOAD 下载 Doris 安装包解压并进入目录后即可在 extensions/audit_loader 子目录下找到 auditloader.zip 文件。

  2. 解压安装包

    1. unzip auditloader.zip

    解压生成以下文件:

    • auditloader.jar:插件代码包。
    • plugin.properties:插件属性文件。
    • plugin.conf:插件配置文件。

您可以将这个文件放置在一个 http 服务器上,或者拷贝auditloader.zip(或者解压auditloader.zip) 到所有 FE 的指定目录下。这里我们使用后者。
该插件的安装可以参阅 INSTALL
执行 install 后会自动生成 AuditLoader 目录

  1. 修改 plugin.conf

    以下配置可供修改:

    • frontend_host_port:FE 节点 IP 地址和 HTTP 端口,格式为 <fe_ip>:<fe_http_port>。默认值为 127.0.0.1:8030。
    • database:审计日志库名。
    • audit_log_table:审计日志表名。
    • slow_log_table:慢查询日志表名。
    • enable_slow_log:是否开启慢查询日志导入功能。默认值为 false。可以在 FE 配置项中配置慢查询的阈值,参数为 qe_slow_log_ms,默认 5s。
    • user:集群用户名。该用户必须具有对应表的 INSERT 权限。
    • password:集群用户密码。
  2. 重新打包 Audit Loader 插件

    1. zip -r -q -m auditloader.zip auditloader.jar plugin.properties plugin.conf

创建库表

在 Doris 中,需要创建审计日志的库和表,表结构如下:

若需开启慢查询日志导入功能,还需要额外创建慢表 doris_slow_log_tbl__,其表结构与 doris_audit_log_tbl__ 一致。

其中 dynamic_partition 属性根据自己的需要,选择审计日志保留的天数。

  1. create database doris_audit_db__;
  2. create table doris_audit_db__.doris_audit_log_tbl__
  3. (
  4. query_id varchar(48) comment "Unique query id",
  5. `time` datetime not null comment "Query start time",
  6. client_ip varchar(32) comment "Client IP",
  7. user varchar(64) comment "User name",
  8. db varchar(96) comment "Database of this query",
  9. state varchar(8) comment "Query result state. EOF, ERR, OK",
  10. error_code int comment "Error code of failing query.",
  11. error_message string comment "Error message of failing query.",
  12. query_time bigint comment "Query execution time in millisecond",
  13. scan_bytes bigint comment "Total scan bytes of this query",
  14. scan_rows bigint comment "Total scan rows of this query",
  15. return_rows bigint comment "Returned rows of this query",
  16. stmt_id int comment "An incremental id of statement",
  17. is_query tinyint comment "Is this statemt a query. 1 or 0",
  18. frontend_ip varchar(32) comment "Frontend ip of executing this statement",
  19. cpu_time_ms bigint comment "Total scan cpu time in millisecond of this query",
  20. sql_hash varchar(48) comment "Hash value for this query",
  21. sql_digest varchar(48) comment "Sql digest of this query, will be empty if not a slow query",
  22. peak_memory_bytes bigint comment "Peak memory bytes used on all backends of this query",
  23. stmt string comment "The original statement, trimed if longer than 2G"
  24. ) engine=OLAP
  25. duplicate key(query_id, `time`, client_ip)
  26. partition by range(`time`) ()
  27. distributed by hash(query_id) buckets 1
  28. properties(
  29. "dynamic_partition.time_unit" = "DAY",
  30. "dynamic_partition.start" = "-30",
  31. "dynamic_partition.end" = "3",
  32. "dynamic_partition.prefix" = "p",
  33. "dynamic_partition.buckets" = "1",
  34. "dynamic_partition.enable" = "true",
  35. "replication_num" = "3"
  36. );
  37. create table doris_audit_db__.doris_slow_log_tbl__
  38. (
  39. query_id varchar(48) comment "Unique query id",
  40. `time` datetime not null comment "Query start time",
  41. client_ip varchar(32) comment "Client IP",
  42. user varchar(64) comment "User name",
  43. db varchar(96) comment "Database of this query",
  44. state varchar(8) comment "Query result state. EOF, ERR, OK",
  45. error_code int comment "Error code of failing query.",
  46. error_message string comment "Error message of failing query.",
  47. query_time bigint comment "Query execution time in millisecond",
  48. scan_bytes bigint comment "Total scan bytes of this query",
  49. scan_rows bigint comment "Total scan rows of this query",
  50. return_rows bigint comment "Returned rows of this query",
  51. stmt_id int comment "An incremental id of statement",
  52. is_query tinyint comment "Is this statemt a query. 1 or 0",
  53. frontend_ip varchar(32) comment "Frontend ip of executing this statement",
  54. cpu_time_ms bigint comment "Total scan cpu time in millisecond of this query",
  55. sql_hash varchar(48) comment "Hash value for this query",
  56. sql_digest varchar(48) comment "Sql digest of a slow query",
  57. peak_memory_bytes bigint comment "Peak memory bytes used on all backends of this query",
  58. stmt string comment "The original statement, trimed if longer than 2G "
  59. ) engine=OLAP
  60. duplicate key(query_id, `time`, client_ip)
  61. partition by range(`time`) ()
  62. distributed by hash(query_id) buckets 1
  63. properties(
  64. "dynamic_partition.time_unit" = "DAY",
  65. "dynamic_partition.start" = "-30",
  66. "dynamic_partition.end" = "3",
  67. "dynamic_partition.prefix" = "p",
  68. "dynamic_partition.buckets" = "1",
  69. "dynamic_partition.enable" = "true",
  70. "replication_num" = "3"
  71. );

注意

上面表结构中:stmt string,这个只能在 0.15 及之后版本中使用,之前版本,字段类型使用 varchar

部署

您可以将打包好的 auditloader.zip 放置在一个 http 服务器上,或者拷贝 auditloader.zip 到所有 FE 的相同指定目录下。

安装

通过以下语句安装 Audit Loader 插件:

  1. INSTALL PLUGIN FROM [source] [PROPERTIES ("key"="value", ...)]

详细命令参考:INSTALL-PLUGIN

安装成功后,可以通过 SHOW PLUGINS 看到已经安装的插件,并且状态为 INSTALLED

完成后,插件会不断的以指定的时间间隔将审计日志插入到这个表中。

FAQ

  1. 审计日志表中没有数据,或运行一段时间后,不再进入新的数据

    可以通过以下步骤排查:

    • 检查分区是否被正常创建

      审计日志表是一张按天分区的动态分区表,默认会创建未来 3 天的分区,并保留历史 30 天的分区。只有分区被正确创建后,才能正常写入审计日志。

      可以通过 show dynamic partition tables from __internal_schema 查看动态分区的调度情况,并根据错误原因排查。可能得错误原因包括:

      • 节点数小于所需副本数:审计日志表默认 3 副本,所以至少需要 3 台 BE 节点。或者通过 alter table 语句修改副本数,如:

        alter table __internal_schema.audit_log set ("dynamic_partition.replication_num" = "2")

      • 没有合适的存储介质:可以通过 show create table __internal_schema.audit_log 查看 storage_medium 属性,如果 BE 没有对应的存储介质,则分区可能创建失败。

      • 没有合适的资源组:审计日志表默认在 default 资源组。可以通过 show backends 命令查看该资源自是否有足够的节点资源。

    • 在 Master FE 的 fe.log 中搜索 AuditLoad 字样,查看是否有相关错误日志

      审计日志是通过内部的 stream load 操作导入到表中的,有可能是导入流程出现了问题,这些问题会在 fe.log 中打印错误日志。