MySQL8-中文参考-十-

MySQL8 中文参考(十)

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

7.1.19 服务器关闭过程

原文:dev.mysql.com/doc/refman/8.0/en/server-shutdown.html

服务器关闭过程如下进行:

  1. 关闭过程被启动。

    这可以通过多种方式来启动。例如,具有SHUTDOWN权限的用户可以执行mysqladmin shutdown命令。mysqladmin可以在 MySQL 支持的任何平台上使用。还有其他特定于操作系统的关闭启动方法:Unix 上的服务器在接收到SIGTERM信号时关闭。在 Windows 上作为服务运行的服务器在服务管理器告知时关闭。

  2. 如果需要,服务器会创建一个关闭线程。

    根据关闭是如何启动的,服务器可能会创建一个线程来处理关闭过程。如果关闭是由客户端请求的,将创建一个关闭线程。如果关闭是由接收到SIGTERM信号导致的,信号线程可能会自行处理关闭,或者可能会创建一个单独的线程来处理。如果服务器尝试创建关闭线程但无法(例如,内存耗尽),它会发出出现在错误日志中的诊断消息:

    Error: Can't create thread to kill server
    
  3. 服务器停止接受新连接。

    为了在关闭过程中防止启动新活动,服务器通过关闭通常用于接受连接的网络接口的处理程序来停止接受新的客户端连接:TCP/IP 端口,Unix 套接字文件,Windows 命名管道以及 Windows 上的共享内存。

  4. 服务器终止当前活动。

    对于与客户端连接相关的每个线程,服务器会断开与客户端的连接并将线程标记为已终止。线程在注意到自己被标记后会终止。空闲连接的线程会迅速终止。当前正在处理语句的线程会定期检查其状态并需要更长时间才能终止。有关线程终止的更多信息,请参见 Section 15.7.8.4, “KILL Statement”,特别是关于在MyISAM表上执行被终止的REPAIR TABLEOPTIMIZE TABLE操作的说明。

    对于具有未完成事务的线程,事务将被回滚。如果一个线程正在更新一个非事务表,例如多行UPDATEINSERT操作可能会导致表部分更新,因为操作可能在完成之前终止。

    如果服务器是一个复制源服务器,它会像对待其他客户端线程一样对待与当前连接的复制品相关的线程。也就是说,每个线程都被标记为已杀死,并在下次检查其状态时退出。

    如果服务器是一个复制服务器,在标记客户端线程为已杀死之前,它会停止复制 I/O 和 SQL 线程(如果它们是活动的)。SQL 线程被允许完成当前的语句(以避免引起复制问题),然后停止。如果此时 SQL 线程正在事务中,服务器会等到当前的复制事件组(如果有的话)执行完毕,或者直到用户发出KILL QUERYKILL CONNECTION语句。另请参阅第 15.4.2.9 节,“STOP SLAVE Statement”。由于非事务性语句无法回滚,为了保证崩溃安全的复制,只能使用事务性表。

    注意

    为了保证复制品的崩溃安全性,必须使用--relay-log-recovery参数运行复制品。

    另请参阅第 19.2.4 节,“中继日志和复制元数据存储库”。

  5. 服务器关闭或关闭存储引擎。

    在此阶段,服务器刷新表缓存并关闭所有打开的表。

    每个存储引擎执行其管理的表所需的任何操作。InnoDB将其缓冲池刷新到磁盘(除非innodb_fast_shutdown为 2),将当前 LSN 写入表空间,并终止其自己的内部线程。MyISAM刷新任何待处理的表的索引写入。

  6. 服务器退出。

为了向管理进程提供信息,服务器返回以下列表中描述的退出代码之一。括号中的短语指示 systemd 对代码的响应动作,对于使用 systemd 管理服务器的平台。

  • 0 = 成功的终止(未重启)

  • 1 = 不成功的终止(未重启)

  • 2 = 不成功的终止(已重启)

7.2 MySQL 数据目录

原文:dev.mysql.com/doc/refman/8.0/en/data-directory.html

MySQL 服务器管理的信息存储在一个称为数据目录的目录下。以下列表简要描述了通常在数据目录中找到的项目,并提供了额外信息的交叉引用:

  • 数据目录子目录。数据目录的每个子目录都是一个数据库目录,对应于服务器管理的数据库。所有 MySQL 安装都有一些标准数据库:

    • mysql 目录对应于 mysql 系统模式,其中包含 MySQL 服务器运行所需的信息。该数据库包含数据字典表和系统表。参见 第 7.3 节,“mysql 系统模式”。

    • performance_schema 目录对应于性能模式,提供用于在运行时检查服务器内部执行的信息。参见 第二十九章,“MySQL 性能模式”。

    • sys 目录对应于 sys 模式,提供了一组对象,以帮助更轻松地解释性能模式信息。参见 第三十章,“MySQL sys 模式”。

    • ndbinfo 目录对应于存储特定于 NDB Cluster 的信息的 ndbinfo 数据库(仅适用于构建时包含 NDB Cluster 的安装)。参见 第 25.6.16 节,“ndbinfo: NDB Cluster 信息数据库”。

    其他子目录对应于用户或应用程序创建的数据库。

    注意

    INFORMATION_SCHEMA 是一个标准数据库,但其实现不使用相应的数据库目录。

  • 服务器写入的日志文件。参见 第 7.4 节,“MySQL 服务器日志”。

  • InnoDB 表空间和日志文件。参见 第十七章,“InnoDB 存储引擎”。

  • 默认/自动生成的 SSL 和 RSA 证书和密钥文件。参见 第 8.3.3 节,“创建 SSL 和 RSA 证书和密钥”。

  • 服务器进程 ID 文件(服务器运行时)。

  • 存储持久化全局系统变量设置的 mysqld-auto.cnf 文件。参见 第 15.7.6.1 节,“变量赋值的 SET 语法”。

先前列表中的某些项目可以通过重新配置服务器来重新定位。此外,--datadir 选项允许更改数据目录本身的位置。对于给定的 MySQL 安装,请检查服务器配置以确定是否已移动项目。

7.3 mysql 系统模式

原文:dev.mysql.com/doc/refman/8.0/en/system-schema.html

mysql模式是系统模式。它包含存储 MySQL 服务器运行所需信息的表。一个广泛的分类是,mysql模式包含存储数据库对象元数据的数据字典表,以及用于其他操作目的的系统表。以下讨论将系统表集进一步细分为更小的类别。

  • 数据字典表

  • 授权系统表

  • 对象信息系统表

  • 日志系统表

  • 服务器端帮助系统表

  • 时区系统表

  • 复制系统表

  • 优化器系统表

  • 杂项系统表

本节的其余部分列举了每个类别中的表,附带了额外信息的交叉引用。数据字典表和系统表使用InnoDB存储引擎,除非另有说明。

mysql系统表和数据字典表存储在 MySQL 数据目录中名为mysql.ibd的单个InnoDB表空间文件中。以前,这些表是在mysql数据库目录中的单独表空间文件中创建的。

可以为mysql系统模式表空间启用数据静态加密。有关更多信息,请参见第 17.13 节,“InnoDB 数据静态加密”。

数据字典表

这些表包括数据字典,其中包含有关数据库对象的元数据。有关更多信息,请参见第十六章,MySQL 数据字典

重要

数据字典是 MySQL 8.0 中的新功能。启用数据字典的服务器与之前的 MySQL 版本相比存在一些一般操作上的差异。有关详细信息,请参阅第 16.7 节,“数据字典使用差异”。此外,从 MySQL 5.7 升级到 MySQL 8.0,升级过程与之前的 MySQL 版本有所不同,并且需要您通过检查特定先决条件来验证安装的升级准备情况。有关更多信息,请参阅第三章,“升级 MySQL”,特别是第 3.6 节,“准备安装以进行升级”。

  • catalogs: 目录信息。

  • character_sets: 可用字符集的信息。

  • check_constraints: 在表上定义的CHECK约束的信息。请参阅第 15.1.20.6 节,“CHECK 约束”。

  • collations: 每个字符集的排序规则信息。

  • column_statistics: 列值的直方图统计信息。请参阅第 10.9.6 节,“优化器统计信息”。

  • column_type_elements: 列使用的类型信息。

  • columns: 表中列的信息。

  • dd_properties: 用于标识数据字典属性的表,例如其版本。服务器使用此信息来确定数据字典是否必须升级到更新版本。

  • events: 事件调度器事件的信息。请参阅第 27.4 节,“使用事件调度器”。如果服务器使用--skip-grant-tables选项启动,则事件调度器将被禁用,并且在表中注册的事件不会运行。请参阅第 27.4.2 节,“事件调度器配置”。

  • foreign_keys, foreign_key_column_usage: 外键信息。

  • index_column_usage: 索引使用的列的信息。

  • index_partitions: 索引使用的分区信息。

  • index_stats: 用于存储执行ANALYZE TABLE时生成的动态索引统计信息。

  • indexes: 表索引的信息。

  • innodb_ddl_log: 存储崩溃安全的 DDL 操作的 DDL 日志。

  • parameter_type_elements: 存储过程和函数参数以及存储函数返回值的信息。

  • parameters: 存储过程和函数的信息。请参阅第 27.2 节,“使用存储过程”。

  • resource_groups: 资源组的信息。请参阅第 7.1.16 节,“资源组”。

  • routines: 关于存储过程和函数的信息。参见 Section 27.2, “Using Stored Routines”。

  • schemata: 关于模式的信息。在 MySQL 中,模式是数据库,因此该表提供有关数据库的信息。

  • st_spatial_reference_systems: 空间数据可用的空间参考系统信息。

  • table_partition_values: 关于表分区使用的数值信息。

  • table_partitions: 表使用的分区信息。

  • table_stats: 当执行ANALYZE TABLE时生成的动态表统计信息。

  • tables: 数据库中表的信息。

  • tablespace_files: 表空间使用的文件信息。

  • tablespaces: 活动表空间的信息。

  • triggers: 触发器的信息。

  • view_routine_usage: 视图和使用它们的存储函数之间的依赖关系信息。

  • view_table_usage: 用于跟踪视图和其基础表之间的依赖关系。

数据字典表是不可见的。它们不能通过SELECT读取,不会出现在SHOW TABLES的输出中,不会在INFORMATION_SCHEMA.TABLES表中列出等等。然而,在大多数情况下,可以查询相应的INFORMATION_SCHEMA表。从概念上讲,INFORMATION_SCHEMA提供了 MySQL 公开数据字典元数据的视图。例如,您不能直接从mysql.schemata表中选择:

mysql> SELECT * FROM mysql.schemata;
ERROR 3554 (HY000): Access to data dictionary table 'mysql.schemata' is rejected.

相反,从相应的INFORMATION_SCHEMA表中选择该信息:

mysql> SELECT * FROM INFORMATION_SCHEMA.SCHEMATA\G
*************************** 1\. row ***************************
              CATALOG_NAME: def
               SCHEMA_NAME: mysql
DEFAULT_CHARACTER_SET_NAME: utf8mb4
    DEFAULT_COLLATION_NAME: utf8mb4_0900_ai_ci
                  SQL_PATH: NULL
        DEFAULT_ENCRYPTION: NO
*************************** 2\. row ***************************
              CATALOG_NAME: def
               SCHEMA_NAME: information_schema
DEFAULT_CHARACTER_SET_NAME: utf8mb3
    DEFAULT_COLLATION_NAME: utf8mb3_general_ci
                  SQL_PATH: NULL
        DEFAULT_ENCRYPTION: NO
*************************** 3\. row ***************************
              CATALOG_NAME: def
               SCHEMA_NAME: performance_schema
DEFAULT_CHARACTER_SET_NAME: utf8mb4
    DEFAULT_COLLATION_NAME: utf8mb4_0900_ai_ci
                  SQL_PATH: NULL
        DEFAULT_ENCRYPTION: NO
...

没有与mysql.indexes完全对应的信息模式表,但INFORMATION_SCHEMA.STATISTICS包含了大部分相同的信息。

到目前为止,还没有与mysql.foreign_keysmysql.foreign_key_column_usage完全对应的INFORMATION_SCHEMA表。获取外键信息的标准 SQL 方法是使用INFORMATION_SCHEMAREFERENTIAL_CONSTRAINTSKEY_COLUMN_USAGE表;这些表现在作为foreign_keysforeign_key_column_usage和其他数据字典表的视图实现。

MySQL 8.0 之前的一些系统表已被数据字典表取代,不再存在于mysql系统模式中:

  • events数据字典表取代了 MySQL 8.0 之前的event表。

  • parametersroutines数据字典表共同取代了 MySQL 8.0 之前的proc表。

授权系统表

这些系统表包含有关用户帐户和其持有的权限的授权信息。有关这些表的结构、内容和目的的其他信息,请参见第 8.2.3 节,“授权表”。

从 MySQL 8.0 开始,授权表是InnoDB(事务性)表。以前,这些是MyISAM(非事务性)表。授权表存储引擎的更改伴随着 MySQL 8.0 中帐户管理语句行为的变化,例如CREATE USERGRANT。以前,命名多个用户的帐户管理语句可能对某些用户成功,对其他用户失败。这些语句现在是事务性的,如果发生任何错误,则对所有命名用户成功或回滚并且不产生任何效果。

注意

如果 MySQL 从旧版本升级,但授权表未从MyISAM升级到InnoDB,服务器会将其视为只读,并且帐户管理语句会产生错误。有关升级说明,请参见第三章,升级 MySQL

  • user: 用户账户、全局权限和其他非权限列。

  • global_grants: 将动态全局权限分配给用户;请参见静态权限与动态权限。

  • db: 数据库级别的权限。

  • tables_priv: 表级别的权限。

  • columns_priv: 列级别的权限。

  • procs_priv: 存储过程和函数权限。

  • proxies_priv: 代理用户权限。

  • default_roles: 此表列出了用户连接和认证后要激活的默认角色,或执行SET ROLE DEFAULT

  • role_edges: 此表列出了角色子图的边缘。

    给定的user表行可能指向用户帐户或角色。服务器可以通过查询role_edges表来区分行是表示用户帐户、角色还是两者之间的关系的信息。

  • password_history: 关于密码更改的信息。

对象信息系统表

这些系统表包含有关组件、可加载函数和服务器端插件的信息:

  • component: 使用INSTALL COMPONENT安装的服务器组件的注册表。在此表中列出的任何组件都将由加载程序在服务器启动序列期间安装。请参见第 7.5.1 节,“安装和卸载组件”。

  • func: 通过CREATE FUNCTION安装的可加载函数的注册表。在正常启动序列期间,服务器会加载在此表中注册的函数。如果服务器使用--skip-grant-tables选项启动,则表中注册的函数不会被加载,也无法使用。参见 Section 7.7.1, “Installing and Uninstalling Loadable Functions”。

    注意

    类似于mysql.func系统表,性能模式user_defined_functions表列出使用CREATE FUNCTION安装的可加载函数。与mysql.func表不同,user_defined_functions表还列出了由服务器组件或插件自动安装的函数。这种差异使得user_defined_functionsmysql.func更适合用于检查已安装的函数。参见 Section 29.12.21.10, “The user_defined_functions Table”。

  • plugin: 通过INSTALL PLUGIN安装的服务器端插件的注册表。在正常启动序列期间,服务器会加载在此表中注册的插件。如果服务器使用--skip-grant-tables选项启动,则表中注册的插件不会被加载,也无法使用。参见 Section 7.6.1, “Installing and Uninstalling Plugins”。

日志系统表

服务器使用这些系统表进行日志记录:

  • general_log: 一般查询日志表。

  • slow_log: 慢查询日志表。

日志表使用CSV存储引擎。

更多信息,请参见 Section 7.4, “MySQL Server Logs”。

服务器端帮助系统表

这些系统表包含服务器端帮助信息:

  • help_category: 关于帮助类别的信息。

  • help_keyword: 与帮助主题相关联的关键词。

  • help_relation: 帮助关键词和主题之间的映射。

  • help_topic: 帮助主题内容。

更多信息,请参见 Section 7.1.17, “Server-Side Help Support”。

时区系统表

这些系统表包含时区信息:

  • time_zone: 时区 ID 以及它们是否使用闰秒。

  • time_zone_leap_second: 当闰秒发生时。

  • time_zone_name: 时区 ID 和名称之间的映射。

  • time_zone_transition, time_zone_transition_type: 时区描述。

更多信息,请参阅第 7.1.15 节,“MySQL 服务器时区支持”。

复制系统表

服务器使用这些系统表来支持复制:

  • gtid_executed: 用于存储 GTID 值的表。请参阅 mysql.gtid_executed 表。

  • ndb_binlog_index: NDB 集群复制的二进制日志信息。只有在服务器构建时使用NDBCLUSTER支持时才会创建此表。请参阅第 25.7.4 节,“NDB 集群复制模式和表”。

  • slave_master_info, slave_relay_log_info, slave_worker_info: 用于在副本服务器上存储复制信息。请参阅第 19.2.4 节,“中继日志和复制元数据存储库”。

所有列出的表格都使用InnoDB存储引擎。

优化器系统表

这些系统表供优化器使用:

  • innodb_index_stats, innodb_table_stats: 用于InnoDB持久性优化器统计信息。请参阅第 17.8.10.1 节,“配置持久性优化器统计参数”。

  • server_cost, engine_cost: 优化器成本模型使用包含有关查询执行过程中发生的操作的成本估算信息的表格。server_cost包含一般服务器操作的优化器成本估算。engine_cost包含特定存储引擎的操作的估算。请参阅第 10.9.5 节,“优化器成本模型”。

其他系统表

其他系统表不适用于前述类别:

  • audit_log_filter, audit_log_user: 如果安装了 MySQL 企业审计,这些表提供审计日志过滤器定义和用户帐户的持久性存储。请参阅审计日志表。

  • firewall_group_allowlist, firewall_groups, firewall_memebership, firewall_users, firewall_whitelist: 如果安装了 MySQL 企业防火墙,这些表提供防火墙使用的信息的持久性存储。请参阅第 8.4.7 节,“MySQL 企业防火墙”。

  • servers: 用于FEDERATED存储引擎。参见 Section 18.8.2.2, “使用 CREATE SERVER 创建 FEDERATED 表”。

  • innodb_dynamic_metadata: 由InnoDB存储引擎使用,用于存储快速变化的表元数据,如自增计数器值和索引树损坏标志。取代了存放在InnoDB系统表空间中的数据字典缓冲表。

7.4 MySQL 服务器日志

原文:dev.mysql.com/doc/refman/8.0/en/server-logs.html

7.4.1 选择通用查询日志和慢查询日志输出目的地

7.4.2 错误日志

7.4.3 通用查询日志

7.4.4 二进制日志

7.4.5 慢查询日志

7.4.6 服务器日志维护

MySQL 服务器有几个日志可以帮助您查找正在发生的活动。

日志类型 写入日志的信息
错误日志 启动、运行或停止时遇到的问题mysqld
通用查询日志 来自客户端的已建立的客户端连接和语句
二进制日志 更改数据的语句(也用于复制)
中继日志 来自复制源服务器的数据更改
慢查询日志 执行时间超过long_query_time秒的查询
DDL 日志(元数据日志) 由 DDL 语句执行的元数据操作

默认情况下,除了 Windows 上的错误日志之外,没有启用任何日志。(DDL 日志在需要时始终创建,并且没有用户可配置的选项;请参阅 DDL 日志。)以下特定于日志的部分提供有关启用日志记录的服务器选项的信息。

默认情况下,服务器在数据目录中为所有启用的日志编写文件。您可以通过刷新日志来强制服务器关闭并重新打开日志文件(或在某些情况下切换到新的日志文件)。当您发出FLUSH LOGS语句时,日志刷新会发生;使用flush-logsrefresh参数执行mysqladmin;或使用--flush-logs--master-data选项执行mysqldump。请参阅 Section 15.7.8.3, “FLUSH Statement”,Section 6.5.2, “mysqladmin — A MySQL Server Administration Program”和 Section 6.5.4, “mysqldump — A Database Backup Program”。此外,当二进制日志的大小达到max_binlog_size系统变量的值时,二进制日志会被刷新。

您可以在运行时控制一般查询和慢查询日志。您可以启用或禁用日志记录,或更改日志文件名。您可以告诉服务器将一般查询和慢查询条目写入日志表、日志文件或两者。有关详细信息,请参阅第 7.4.1 节,“选择一般查询日志和慢查询日志输出目的地”,第 7.4.3 节,“一般查询日志”和第 7.4.5 节,“慢查询日志”。

中继日志仅在副本上使用,用于保存来自复制源服务器的数据更改,这些更改也必须在副本上进行。有关中继日志内容和配置的讨论,请参阅第 19.2.4.1 节,“中继日志”。

有关日志维护操作(如旧日志文件的过期)的信息,请参阅第 7.4.6 节,“服务器日志维护”。

关于保护日志安全的信息,请参阅第 8.1.2.3 节,“密码和日志记录”。

7.4.1 选择一般查询日志和慢查询日志输出目的地

原文:dev.mysql.com/doc/refman/8.0/en/log-destinations.html

MySQL 服务器可以灵活控制写入一般查询日志和慢查询日志的输出目的地,如果这些日志已启用。日志条目的可能目的地是日志文件或mysql系统数据库中的general_logslow_log表。可以选择文件输出、表输出或两者。

  • 服务器启动时的日志控制

  • 运行时的日志控制

  • 日志表的优势和特点

服务器启动时的日志控制

log_output系统变量指定日志输出的目的地。设置此变量本身不会启用日志;它们必须单独启用。

  • 如果在启动时未指定log_output,则默认的日志记录目的地是FILE

  • 如果在启动时指定了log_output,其值是从TABLE(记录到表)、FILE(记录到文件)或NONE(不记录到表或文件)中选择的一个或多个逗号分隔的单词列表。如果存在NONE,则优先于任何其他指定项。

general_log系统变量控制所选日志目的地的一般查询日志的记录。如果在服务器启动时指定,general_log接受一个可选参数 1 或 0 来启用或禁用日志。要为文件记录指定除默认文件名以外的文件名,请设置general_log_file变量。类似地,slow_query_log变量控制所选目的地的慢查询日志的记录,并设置slow_query_log_file指定文件记录的文件名。如果启用了任一日志,则服务器会打开相应的日志文件并将启动消息写入其中。但是,除非选择了FILE日志目的地,否则不会进一步记录查询到文件中。

示例:

  • 要将一般查询日志条目写入日志表和日志文件,请使用--log_output=TABLE,FILE选择两个日志目的地,并使用--general_log启用一般查询日志。

  • 仅将一般和慢查询日志条目写入日志表,使用--log_output=TABLE选择表格作为日志目的地,并使用--general_log--slow_query_log启用两个日志。

  • 仅将慢查询日志条目写入日志文件,使用--log_output=FILE选择文件作为日志目的地,并使用--slow_query_log启用慢查询日志。在这种情况下,因为默认的日志目的地是FILE,您可以省略log_output设置。

运行时日志控制

与日志表和文件相关的系统变量使得可以在运行时控制日志记录:

  • log_output变量指示当前的日志输出目的地。可以在运行时修改以更改目的地。

  • general_logslow_query_log变量指示一般查询日志和慢查询日志是否已启用(ON)或已禁用(OFF)。您可以在运行时设置这些变量以控制日志是否已启用。

  • general_log_fileslow_query_log_file变量指示一般查询日志和慢查询日志文件的名称。您可以在服务器启动时或在运行时设置这些变量以更改日志文件的名称。

  • 要为当前会话禁用或启用一般查询日志记录,请将会话sql_log_off变量设置为ONOFF。(假设一般查询日志本身已启用。)

日志表的优点和特点

使用表格进行日志输出具有以下优点:

  • 日志条目具有标准格式。要显示日志表的当前结构,请使用以下语句:

    SHOW CREATE TABLE mysql.general_log;
    SHOW CREATE TABLE mysql.slow_log;
    
  • 日志内容可通过 SQL 语句访问。这使得可以使用仅选择满足特定条件的日志条目的查询。例如,要选择与特定客户关联的日志内容(这对于识别来自该客户的问题查询很有用),使用日志表比使用日志文件更容易。

  • 日志可通过任何能连接到服务器并发出查询的客户端远程访问(如果客户端具有适当的日志表权限)。无需登录到服务器主机并直接访问文件系统。

日志表实现具有以下特点:

  • 一般来说,日志表的主要目的是为用户提供一个接口来观察服务器的运行时执行情况,而不是干预其运行时执行。

  • CREATE TABLEALTER TABLEDROP TABLE 是对日志表的有效操作。对于ALTER TABLEDROP TABLE,日志表不能在使用中,必须被禁用,如后面所述。

  • 默认情况下,日志表使用将数据以逗号分隔值格式写入的CSV存储引擎。对于可以访问包含日志表数据的.CSV文件的用户,这些文件易于导入到其他程序中,如可以处理 CSV 输入的电子表格程序。

    可以修改日志表以使用MyISAM存储引擎。不能使用ALTER TABLE来修改正在使用的日志表。必须先禁用日志。日志表只能使用CSVMyISAM引擎,其他引擎不合法。

    日志表和“打开文件过多”错误。 如果将TABLE作为日志目的地,并且日志表使用CSV存储引擎,您可能会发现在运行时反复禁用和启用常规查询日志或慢查询日志会导致.CSV文件的打开文件描述符数量增加,可能导致“打开文件过多”错误。为解决此问题,执行FLUSH TABLES或确保open_files_limit的值大于table_open_cache_instances的值。

  • 要禁用日志记录以便修改(或删除)日志表,可以使用以下策略。示例使用常规查询日志;慢查询日志的过程类似,但使用slow_log表和slow_query_log系统变量。

    SET @old_log_state = @@GLOBAL.general_log;
    SET GLOBAL general_log = 'OFF';
    ALTER TABLE mysql.general_log ENGINE = MyISAM;
    SET GLOBAL general_log = @old_log_state;
    
  • TRUNCATE TABLE 是对日志表的有效操作。可用于清除日志条目。

  • RENAME TABLE 是对日志表的有效操作。可以使用以下策略来原子地重命名日志表(例如执行日志轮换):

    USE mysql;
    DROP TABLE IF EXISTS general_log2;
    CREATE TABLE general_log2 LIKE general_log;
    RENAME TABLE general_log TO general_log_backup, general_log2 TO general_log;
    
  • CHECK TABLE 是对日志表的有效操作。

  • LOCK TABLES 不能用于日志表。

  • INSERTDELETEUPDATE不能用于日志表。这些操作仅在服务器内部允许。

  • FLUSH TABLES WITH READ LOCKread_only系统变量的状态对日志表没有影响。服务器始终可以写入日志表。

  • 写入日志表的条目不会写入二进制日志,因此不会被复制到副本。

  • 要刷新日志表或日志文件,请分别使用FLUSH TABLESFLUSH LOGS

  • 不允许对日志表进行分区。

  • mysqldump转储包括重新创建这些表的语句,以便在重新加载转储文件后它们不会丢失。日志表内容不会被转储。

7.4.2 错误日志

原文:dev.mysql.com/doc/refman/8.0/en/error-log.html

7.4.2.1 错误日志配置

7.4.2.2 默认错误日志目标配置

7.4.2.3 错误事件字段

7.4.2.4 错误日志过滤类型

7.4.2.5 基于优先级的错误日志过滤 (log_filter_internal)

7.4.2.6 基于规则的错误日志过滤 (log_filter_dragnet)

7.4.2.7 以 JSON 格式记录错误日志

7.4.2.8 记录错误日志到系统日志

7.4.2.9 错误日志输出格式

7.4.2.10 错误日志文件刷新和重命名

本节讨论如何配置 MySQL 服务器以将诊断消息记录到错误日志中。有关选择错误消息字符集和语言的信息,请参见 Section 12.6, “Error Message Character Set”,以及 Section 12.12, “Setting the Error Message Language”。

错误日志包含mysqld启动和关闭时间的记录。它还包含在服务器启动和关闭期间以及服务器运行时发生的错误、警告和注释的诊断消息。例如,如果mysqld注意到需要自动检查或修复表,它会向错误日志写入一条消息。

根据错误日志配置,错误消息也可能填充到性能模式error_log表中,以提供对日志的 SQL 接口,并使其内容可以被查询。参见 Section 29.12.21.2, “The error_log Table”。

在某些操作系统上,如果mysqld异常退出,错误日志中会包含堆栈跟踪。该跟踪可用于确定mysqld退出的位置。参见 Section 7.9, “Debugging MySQL”。

如果用于启动mysqldmysqld_safe可能会向错误日志写入消息。例如,当mysqld_safe注意到异常的mysqld退出时,它会重新启动mysqld并向错误日志写入mysqld restarted消息。

以下部分讨论配置错误日志的方面。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-configuration.html

7.4.2.1 错误日志配置

在 MySQL 8.0 中,错误日志记录使用了在第 7.5 节,“MySQL 组件”中描述的 MySQL 组件架构。错误日志子系统由执行日志事件过滤和写入的组件以及配置哪些组件加载和启用以实现所需日志记录结果的系统变量组成。

本节讨论了如何加载和启用错误日志记录的组件。有关特定于日志过滤器的说明,请参阅第 7.4.2.4 节,“错误日志过滤类型”。有关特定于 JSON 和系统日志接收器的说明,请参阅第 7.4.2.7 节,“以 JSON 格式记录错误日志”和第 7.4.2.8 节,“将错误日志记录到系统日志”。有关所有可用日志组件的更多详细信息,请参阅第 7.5.3 节,“错误日志组件”。

基于组件的错误日志记录提供了以下功能:

  • 可由过滤组件过滤的日志事件,以影响可用于写入的信息。

  • 由接收器(写入器)组件输出的日志事件。可以启用多个接收器组件,将错误日志输出写入多个目的地。

  • 实现默认错误日志格式的内置过滤器和接收器组件。

  • 一个可加载的接收器,可启用以 JSON 格式记录日志。

  • 一个可加载的接收器,可启用将日志记录到系统日志中。

  • 控制加载和启用哪些日志组件以及每个组件如何运行的系统变量。

错误日志配置在本节中描述如下主题:

  • 默认错误日志配置

  • 错误日志配置方法

  • 隐式错误日志配置

  • 显式错误日志配置

  • 更改错误日志配置方法

  • 故障排除配置问题

  • 配置多个日志接收器

  • 日志汇流性能模式支持

默认错误日志配置

log_error_services系统变量控制要加载的可加载日志组件(从 MySQL 8.0.30 开始)以及要为错误日志记录启用的日志组件。默认情况下,log_error_services具有以下值:

mysql> SELECT @@GLOBAL.log_error_services;
+----------------------------------------+
| @@GLOBAL.log_error_services            |
+----------------------------------------+
| log_filter_internal; log_sink_internal |
+----------------------------------------+

该值表示日志事件首先通过log_filter_internal过滤组件,然后通过log_sink_internal汇流组件,这两个都是内置组件。过滤器修改后续命名的组件看到的日志事件。汇流是日志事件的目的地。通常,汇流将日志事件处理为具有特定格式的日志消息,并将这些消息写入其关联的输出,例如文件或系统日志。

log_filter_internallog_sink_internal的组合实现了默认的错误日志过滤和输出行为。这些组件的操作受其他服务器选项和系统变量的影响:

  • 输出目的地由--log-error选项确定(在 Windows 上,还有--pid-file--console)。这些选项确定是否将错误消息写入控制台或文件,如果写入文件,则确定错误日志文件名。参见 Section 7.4.2.2, “Default Error Log Destination Configuration”。

  • log_error_verbositylog_error_suppression_list系统变量影响log_filter_internal允许或抑制哪些类型的日志事件。参见 Section 7.4.2.5, “Priority-Based Error Log Filtering (log_filter_internal)”")。

在配置log_error_services时,请注意以下特性:

  • 日志组件列表可以用分号或(从 MySQL 8.0.12 开始)逗号分隔,可选地跟随空格。给定设置不能同时使用分号和逗号分隔符。组件顺序很重要,因为服务器按照列出的顺序执行组件。

  • log_error_services值中的最终组件不能是过滤器。这是一个错误,因为它对事件的任何更改都不会对输出产生影响:

    mysql> SET GLOBAL log_error_services = 'log_filter_internal';
    ERROR 1231 (42000): Variable 'log_error_services' can't be set to the value
    of 'log_filter_internal'
    

    要纠正问题,请在值的末尾包含一个 sink:

    mysql> SET GLOBAL log_error_services = 'log_filter_internal; log_sink_internal';
    
  • log_error_services 中命名的组件顺序很重要,特别是与过滤器和接收器的相对顺序有关。考虑这个 log_error_services 值:

    log_filter_internal; log_sink_1; log_sink_2
    

    在这种情况下,日志事件经过内置过滤器,然后传递到第一个接收器,再传递到第二个接收器。两个接收器都会接收到经过过滤的日志事件。

    将其与此 log_error_services 值进行比较:

    log_sink_1; log_filter_internal; log_sink_2
    

    在这种情况下,日志事件经过第一个接收器,然后经过内置过滤器,再传递到第二个接收器。第一个接收器接收未经过滤的事件。第二个接收器接收经过过滤的事件。如果您希望一个日志包含所有日志事件的消息,另一个日志仅包含部分日志事件的消息,您可以以这种方式配置错误日志记录。

错误日志配置方法

错误日志配置涉及根据需要加载和启用错误日志组件,并执行特定于组件的配置。

有两种错误日志配置方法,隐式显式。建议选择一种配置方法并专门使用。同时使用两种方法可能会导致启动时出现警告。有关更多信息,请参阅 故障排除配置问题。

  • 隐式错误日志配置(MySQL 8.0.30 中引入)

    此配置方法加载并启用由 log_error_services 变量定义的日志组件。在启动时,尚未加载的可加载组件会在InnoDB存储引擎完全可用之前隐式加载。此配置方法具有以下优点:

    • 日志组件在启动序列的早期加载,早于InnoDB存储引擎,使得记录的信息更早可用。

    • 它避免了在启动过程中发生故障时丢失缓冲的日志信息。

    • 使用 INSTALL COMPONENT 安装错误日志组件并不是必需的,简化了错误日志配置。

    要使用这种方法,请参阅 隐式错误日志配置。

  • 显式错误日志配置

    注意

    此配置方法支持向后兼容。推荐使用 MySQL 8.0.30 中引入的隐式配置方法。

    这种配置方法需要使用INSTALL COMPONENT加载错误日志组件,然后配置log_error_services以启用日志组件。INSTALL COMPONENT将组件添加到mysql.component表(一个InnoDB表),启动时要加载的组件从该表中读取,该表只有在InnoDB初始化后才能访问。

    InnoDB存储引擎初始化期间,启动序列期间缓冲记录的信息,这有时会因为InnoDB启动序列期间发生的恢复和数据字典升级等操作而延长。

    要使用此方法,请参阅显式错误日志配置。

隐式错误日志配置

本过程描述了如何使用log_error_services隐式加载和启用错误日志组件。有关错误日志配置方法的讨论,请参见错误日志配置方法。

隐式加载和启用错误日志组件:

  1. log_error_services值中列出错误日志组件。

    要在服务器启动时加载和启用错误日志组件,请在选项文件中设置log_error_services。以下示例配置了使用 JSON 日志接收器(log_sink_json)以及内置日志过滤器和接收器(log_filter_internallog_sink_internal)。

    [mysqld]
    log_error_services='log_filter_internal; log_sink_internal; log_sink_json'
    

    注意

    要使用 JSON 日志接收器(log_sink_syseventlog)而不是默认接收器(log_sink_internal),您应该将log_sink_internal替换为log_sink_json

    要立即加载和启用组件并用于后续重新启动,请使用SET PERSIST设置log_error_services

    SET PERSIST log_error_services = 'log_filter_internal; log_sink_internal; log_sink_json';
    
  2. 如果错误日志组件公开任何必须设置的系统变量以使组件初始化成功,请为这些变量分配适当的值。您可以在选项文件中设置这些变量,也可以使用SET PERSIST

    重要

    在实现隐式配置时,首先设置log_error_services以加载组件并公开其系统变量,然后设置组件系统变量。无论是在命令行、选项文件还是使用SET PERSIST进行变量赋值,都需要按照此配置顺序进行。

要禁用日志组件,请从log_error_services值中移除它。同时移除您定义的任何相关组件变量设置。

注意

使用log_error_services隐式加载日志组件不会影响mysql.component表。它不会将组件添加到mysql.component表中,也不会从mysql.component表中删除以前使用INSTALL COMPONENT安装的组件。

明确的错误日志配置

本过程描述了如何通过使用INSTALL COMPONENT加载组件,然后通过log_error_services启用错误日志组件。有关错误日志配置方法的讨论,请参见错误日志配置方法。

明确加载和启用错误日志组件:

  1. 使用INSTALL COMPONENT加载组件(除非它是内置的或已加载)。例如,要加载 JSON 日志接收器,请执行以下语句:

    INSTALL COMPONENT 'file://component_log_sink_json';
    

    使用INSTALL COMPONENT加载组件会将其注册到mysql.component系统表中,以便服务器在InnoDB初始化后自动加载它以供后续启动使用。

    使用INSTALL COMPONENT加载日志组件时使用的 URN 是组件名称前缀为file://component_。例如,对于log_sink_json组件,相应的 URN 是file://component_log_sink_json。有关错误日志组件 URN,请参见 Section 7.5.3, “Error Log Components”。

  2. 如果错误日志组件公开了必须设置的系统变量以确保组件初始化成功,为这些变量分配适当的值。您可以在选项文件中设置这些变量,也可以使用SET PERSIST

  3. 通过在log_error_services值中列出组件来启用该组件。

    重要

    从 MySQL 8.0.30 开始,当使用INSTALL COMPONENT显式加载日志组件时,请勿在选项文件中持久化或设置log_error_services,该选项文件在启动时隐式加载日志组件。而是使用SET GLOBAL语句在运行时启用日志组件。

    以下示例配置了使用 JSON 日志接收器(log_sink_json)以及内置日志过滤器和接收器(log_filter_internallog_sink_internal)。

    SET GLOBAL log_error_services = 'log_filter_internal; log_sink_internal; log_sink_json';
    

    注意

    要使用 JSON 日志接收器(log_sink_syseventlog)而不是默认接收器(log_sink_internal),您应该将log_sink_internal替换为log_sink_json

要禁用日志组件,请从log_error_services值中删除它。然后,如果组件是可加载的,并且您还想卸载它,请使用UNINSTALL COMPONENT。还要删除您定义的任何相关组件变量设置。

尝试使用UNINSTALL COMPONENT卸载仍在log_error_services值中命名的可加载组件会产生错误。

更改错误日志配置方法

如果您之前使用INSTALL COMPONENT显式加载了错误日志组件,并且希望切换到隐式配置,如隐式错误日志配置中所述,建议执行以下步骤:

  1. log_error_services设置回默认配置。

    SET GLOBAL log_error_services = 'log_filter_internal,log_sink_internal';
    
  2. 使用UNINSTALL COMPONENT卸载您之前安装的任何可加载日志组件。例如,如果之前安装了 JSON 日志接收器,请按照以下方式��载它:

    UNINSTALL COMPONENT 'file://component_log_sink_json';
    
  3. 删除已卸载组件的任何组件变量设置。例如,如果在选项文件中设置了组件变量,请从选项文件中删除这些设置。如果使用SET PERSIST设置了组件变量,请使用RESET PERSIST来清除这些设置。

  4. 按照隐式错误日志配置中的步骤重新实施您的配置。

如果需要从隐式配置恢复到显式配置,请执行以下步骤:

  1. log_error_services设置回其默认配置以卸载隐式加载的日志组件。

    SET GLOBAL log_error_services = 'log_filter_internal,log_sink_internal';
    
  2. 删除与已卸载组件相关的任何组件变量设置。例如,如果在选项文件中设置了组件变量,请从选项文件中删除这些设置。如果使用SET PERSIST设置了组件变量,请使用RESET PERSIST清除这些设置。

  3. 重新启动服务器以卸载隐式加载的日志组件。

  4. 按照显式错误日志配置中的步骤重新实施您的配置。

故障排除配置问题

从 MySQL 8.0.30 开始,在启动时加载在log_error_services值中列出的日志组件会在 MySQL 服务器启动序列的早期隐式加载。如果以前使用INSTALL COMPONENT加载了日志组件,则服务器会在启动序列的后期尝试重新加载该组件,从而产生以下警告:

Cannot load component from specified URN: 'file://component_*component_name*'

您可以在错误日志中检查此警告,或通过以下查询查询性能模式error_log表来查询此警告:

SELECT error_code, data
  FROM performance_schema.error_log
 WHERE data LIKE "%'file://component_%"
   AND error_code="MY-013129" AND data LIKE "%MY-003529%";

要避免此警告,请按照更改错误日志配置方法中的说明调整您的错误日志配置。应使用隐式或显式错误日志配置,但不要同时使用两者。

当尝试显式加载在启动时隐式加载的组件时会出现类似错误。例如,如果log_error_services列出了 JSON 日志接收器组件,则该组件会在启动时隐式加载。尝试稍后显式加载相同组件会返回此错误:

mysql> INSTALL COMPONENT 'file://component_log_sink_json';
ERROR 3529 (HY000): Cannot load component from specified URN: 'file://component_log_sink_json'.
配置多个日志接收器

可以配置多个日志接收器,从而可以将输出发送到多个目的地。要在默认接收器之外启用 JSON 日志接收器(而不是替代),请将log_error_services值设置如下:

SET GLOBAL log_error_services = 'log_filter_internal; log_sink_internal; log_sink_json';

要恢复仅使用默认接收器并卸载系统日志接收器,请执行以下语句:

SET GLOBAL log_error_services = 'log_filter_internal; log_sink_internal;
UNINSTALL COMPONENT 'file://component_log_sink_json';
日志接收器性能模式支持

如果启用了记录组件包含支持性能模式的接收器,那么写入错误日志的事件也会写入性能模式的error_log表中。这样可以使用 SQL 查询来检查错误日志内容。目前,传统格式的log_sink_internal和 JSON 格式的log_sink_json接收器支持此功能。请参阅 Section 29.12.21.2, “错误日志表”。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-destination-configuration.html

7.4.2.2 默认错误日志目的地配置

本节描述了哪些服务器选项配置了默认错误日志目的地,可以是控制台或命名文件。它还指出了哪些日志接收组件将其自身的输出目的地基于默认目的地。

在本讨论中,“控制台”指的是stderr,标准错误输出。这是您的终端或控制台窗口,除非标准错误输出已重定向到其他目的地。

服务器对于确定默认错误日志目的地的选项在 Windows 和 Unix 系统上有些不同。请确保使用适合您平台的信息配置目的地。服务器解释默认错误日志目的地选项后,它将设置log_error系统变量以指示默认目的地,这会影响几个日志接收组件写入错误消息的位置。以下各节将讨论这些主题。

  • Windows 上的默认错误日志目的地

  • Unix 和类 Unix 系统上的默认错误日志目的地

  • 默认错误日志目的地如何影响日志接收组件

Windows 上的默认错误日志目的地

在 Windows 上,mysqld使用--log-error--pid-file--console选项来确定默认错误日志目的地是控制台还是文件,以及如果是文件,则文件名:

  • 如果提供了--console,默认目的地是控制台。(--console优先于--log-error如果两者都提供,则关于--log-error的以下项目不适用。)

  • 如果未提供--log-error,或者提供了但没有指定文件名,则默认目的地是数据目录中名为*host_name*.err的文件,除非指定了--pid-file选项。在这种情况下,文件名是 PID 文件基本名称,带有.err后缀在数据目录中。

  • 如果给定--log-error来命名一个文件,那么默认的目的地就是该文件(如果名称没有后缀,则添加.err后缀)。文件位置位于数据目录下,除非给定绝对路径名以指定不同位置。

如果默认的错误日志目的地是控制台,服务器会将log_error系统变量设置为stderr。否则,默认目的地是一个文件,服务器会将log_error设置为文件名。

Unix 和类 Unix 系统上的默认错误日志目的地

在 Unix 和类 Unix 系统上,mysqld使用--log-error选项来确定默认的错误日志目的地是控制台还是文件,以及文件名:

  • 如果没有给定--log-error,默认的目的地是控制台。

  • 如果给定--log-error而没有命名文件,那么默认的目的地是数据目录中名为*host_name*.err的文件。

  • 如果给定--log-error来命名一个文件,那么默认的目的地就是该文件(如果名称没有后缀,则添加.err后缀)。文件位置位于数据目录下,除非给定绝对路径名以指定不同位置。

  • 如果在[mysqld][server][mysqld_safe]部分的选项文件中给定--log-error,在使用mysqld_safe启动服务器的系统上,mysqld_safe会找到并使用该选项,并将其传递给mysqld

注意

对于 Yum 或 APT 软件包安装来说,通常会在服务器配置文件中使用类似log-error=/var/log/mysqld.log的选项来配置错误日志文件位置在/var/log下。从选项中移除路径名会导致在数据目录中使用*host_name*.err文件。

如果默认的错误日志目的地是控制台,服务器会将log_error系统变量设置为stderr。否则,默认目的地是一个文件,服务器会将log_error设置为文件名。

默认错误日志目的地如何影响日志输出

在服务器解释错误日志目的地配置选项后,它将log_error系统变量设置为指示默认错误日志目的地。日志输出端组件可以基于log_error值确定自己的输出目的地,或者独立于log_error确定它们的目的地。

如果log_errorstderr,默认错误日志目的地为控制台,基于默认目的地的日志输出端也会写入控制台:

  • log_sink_internal, log_sink_json, log_sink_test: 这些输出端写入控制台。即使对于可以多次启用的输出端(例如log_sink_json),所有实例也会写入控制台。

  • log_sink_syseventlog: 此输出端写入系统日志,不受log_error值的影响。

如果log_error不是stderr,默认错误日志目的地是一个文件,并且log_error指示文件名。基于默认目的地的日志输出端会根据该文件名确定输出文件命名。 (一个输出端可能会使用完全相同的名称,或者可能会使用某种变体。)假设log_error值为file_name。那么日志输出端使用以下方式的名称:

  • log_sink_internal, log_sink_test: 这些输出端写入file_name

  • log_sink_json: 连续的此输出端实例命名为log_error_services值写入名为file_name加上编号为.*NN*.json后缀的文件:*file_name*.00.json*file_name*.01.json等等。

  • log_sink_syseventlog: 此输出端写入系统日志,不受log_error值的影响。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-event-fields.html

7.4.2.3 错误事件字段

用于错误日志的错误事件包含一组字段,每个字段由键/值对组成。事件字段可以分类为核心、可选或用户定义:

  • 核心字段会自动设置为错误事件。但是,在事件处理过程中,不能保证事件���存在核心字段,因为核心字段,像任何类型的字段一样,可能会被日志过滤器取消设置。如果发生这种情况,则在该过滤器内部和在过滤器之后执行的组件(如日志接收器)中无法找到该字段。

  • 通常情况下,可选字段通常不存在,但对于某些事件类型可能存在。当存在时,可选字段根据需要和可用性提供额外的事件信息。

  • 用户定义字段是任何名称尚未定义为核心或可选字段的字段。用户定义字段在由日志过滤器创建之前不存在。

如前述描述所示,任何给定字段在事件处理过程中可能不存在,这可能是因为它一开始就不存在,或者被过滤器丢弃。对于日志接收器,字段缺失的影响是特定于接收器的。例如,接收器可能从日志消息中省略该字段,指示该字段丢失,或者替换为默认值。如果有疑问,请进行测试:使用一个取消设置该字段的过滤器,然后检查日志接收器对其的处理方式。

以下部分描述了核心和可选错误事件字段。对于单独的日志过滤器组件,可能会有关于这些字段的其他特定于过滤器的考虑,或者过滤器可能添加此处未列出的用户定义字段。有关详细信息,请参阅特定过滤器的文档。

  • 核心错误事件字段

  • 可选错误事件字段

核心错误事件字段

这些错误事件字段是核心字段:

  • time

    事件时间戳,精确到微秒。

  • msg

    事件消息字符串。

  • prio

    事件优先级,用于指示系统、错误、警告或注意/信息事件。此字段对应于syslog中的严重性。以下表显示可能的优先级级别。

    事件类型 数字优先级
    系统事件 0
    错误事件 1
    警告事件 2
    注意/信息事件 3

    prio值是数字。与此相关,错误事件还可以包括一个可选的label字段,表示优先级为字符串。例如,具有prio值为 2 的事件可能具有label值为'警告'。

    根据优先级,过滤器组件可以包含或删除错误事件,但系统事件是强制性的,不能被删除。

    一般来说,消息优先级的确定如下:

    这种情况或事件是否可操作?

    • 是:情况或事件是否可忽略?

      • 是:优先级是警告。

      • 不:优先级是错误。

    • 不:情况或事件是否强制性?

      • 是:优先级是系统。

      • 不:优先级是注释/信息。

  • err_code

    事件错误代码,作为数字(例如,1022)。

  • err_symbol

    作为字符串的事件错误符号(例如,'ER_DUP_KEY')。

  • SQL_state

    作为字符串的事件 SQLSTATE 值(例如,'23000')。

  • subsystem

    事件发生的子系统。可能的值为InnoDBInnoDB存储引擎)、Repl(复制子系统)、Server(其他)。

可选的错误事件字段

可选的错误事件字段属于以下类别:

  • 关于错误的其他信息,例如操作系统发出的错误或错误标签:

    • OS_errno

      操作系统错误编号。

    • OS_errmsg

      操作系统错误消息。

    • label

      prio值对应的标签,作为字符串。

  • 事件发生的客户端的标识:

    • user

      客户端用户。

    • host

      客户端主机。

    • thread

      mysqld中负责生成错误事件的线程的 ID。此 ID 指示服务器的哪个部分生成了事件,并与一般查询日志和慢查询日志消息一致,这些消息包括连接线程 ID。

    • query_id

      查询 ID。

  • 调试信息:

    • source_file

      事件发生的源文件,不包含任何前导路径。

    • source_line

      事件发生的源文件中的行号。

    • function

      事件发生的函数。

    • component

      事件发生的组件或插件。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-filtering.html

7.4.2.4 错误日志过滤类型

错误日志配置通常包括一个日志过滤组件和一个或多个日志接收组件。对于错误日志过滤,MySQL 提供了多种组件选择:

  • log_filter_internal:该过滤组件基于日志事件优先级和错误代码提供错误日志过滤,结合log_error_verbositylog_error_suppression_list系统变量。log_filter_internal是内置的,默认启用。参见 Section 7.4.2.5, “基于优先级的错误日志过滤(log_filter_internal)”。

  • log_filter_dragnet:该过滤组件基于用户提供的规则,结合dragnet.log_error_filter_rules系统变量,提供错误日志过滤。参见 Section 7.4.2.6, “基于规则的错误日志过滤(log_filter_dragnet)”。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-priority-based-filtering.html

7.4.2.5 基于优先级的错误日志过滤(log_filter_internal)

log_filter_internal日志过滤组件实现了一种基于错误事件优先级和错误代码的简单形式的日志过滤。要影响log_filter_internal如何允许或抑制写入错误日志的错误、警告和信息事件,请设置log_error_verbositylog_error_suppression_list系统变量。

log_filter_internal是内置的并默认启用。如果禁用此过滤器,log_error_verbositylog_error_suppression_list将不起作用,因此必须在需要时使用另一个过滤器服务执行过滤(例如,在使用log_filter_dragnet时使用单独的过滤规则)。有关过滤器配置的信息,请参见第 7.4.2.1 节“错误日志配置”。

  • 详细程度过滤

  • 抑制列表过滤

  • 详细程度和抑制列表交互

详细程度过滤

事件意图记录到错误日志的优先级为ERRORWARNINGINFORMATIONlog_error_verbosity系统变量控制基于哪些优先级允许写入日志的消息的详细程度,如下表所示。

log_error_verbosity 值 允许的消息优先级
1 ERROR
2 ERRORWARNING
3 ERRORWARNINGINFORMATION

如果log_error_verbosity为 2 或更高,则服务器会记录关于对基于语句的日志记录不安全的语句的消息。如果值为 3,则服务器会记录有关新连接尝试的中止连接和访问被拒绝的错误。请参见第 B.3.2.9 节“通信错误和中止连接”。

如果使用复制,建议将log_error_verbosity值设置为 2 或更高,以获取有关正在发生的情况的更多信息,例如有关网络故障和重新连接的消息。

如果在副本上log_error_verbosity为 2 或更高,则副本会将消息打印到错误日志中,以提供有关其状态的信息,例如二进制日志和中继日志的坐标,它开始工作的位置,当它切换到另一个中继日志时,重新连接后等等。

存在一个SYSTEM的消息优先级,不受冗长过滤的影响。关于非错误情况的系统消息会被打印到错误日志中,无论log_error_verbosity的值是多少。这些消息包括启动和关闭消息,以及一些重要的设置更改。

在 MySQL 错误日志中,系统消息标记为“System”。其他日志接收器可能会或可能不会遵循相同的约定,在生成的日志中,系统消息可能被分配给信息优先级级别使用的标签,例如“Note”或“Information”。如果基于消息标签应用任何额外的过滤或重定向以进行日志记录,系统消息不会覆盖您的过滤器,而是以与其他消息相同的方式处理。

抑制列表过滤

log_error_suppression_list系统变量适用于写入错误日志的事件,并指定在出现WARNINGINFORMATION优先级时要抑制哪些事件。例如,如果某种类型的警告被认为是错误日志中频繁发生但不感兴趣的“噪音”,则可以将其抑制。log_error_suppression_list不会抑制具有ERRORSYSTEM优先级的消息。

log_error_suppression_list的值可以是空字符串以表示无抑制,或者是一个或多个逗号分隔值的列表,指示要抑制的错误代码。错误代码可以用符号形式或数字形式指定。可以使用或不使用MY-前缀指定数字代码。数字部分的前导零不重要。允许的代码格式示例:

ER_SERVER_SHUTDOWN_COMPLETE
MY-000031
000031
MY-31
31

为了可读性和可移植性,符号值比数字值更可取。

尽管要抑制的代码可以用符号形式或数字形式表示,但每个代码的数字值必须在允许的范围内:

  • 1 至 999:服务器和客户端使用的全局错误代码。

  • 10000 及以上:服务器错误代码,意在写入错误日志(不发送给客户端)。

此外,指定的每个错误代码必须实际被 MySQL 使用。尝试指定不在允许范围内或在允许范围内但未被 MySQL 使用的代码会产生错误,并且log_error_suppression_list的值保持不变。

有关错误代码范围、每个范围内定义的错误符号和数字的信息,请参见第 B.1 节,“错误消息来源和元素”,以及 MySQL 8.0 错误消息参考。

服务器可以为给定错误代码生成具有不同优先级的消息,因此与log_error_suppression_list中列出的错误代码相关联的消息的抑制取决于其优先级。假设变量的值为'ER_PARSER_TRACE,MY-010001,10002'。那么log_error_suppression_list对这些代码的消息产生以下影响:

  • 生成具有WARNINGINFORMATION优先级的消息会被抑制。

  • 生成具有ERRORSYSTEM优先级的消息不会被抑制。

详细度和抑制列表的交互

log_error_verbosity的效果与log_error_suppression_list的效果相结合。考虑使用以下设置启动的服务器:

[mysqld]
log_error_verbosity=2 # error and warning messages only
log_error_suppression_list='ER_PARSER_TRACE,MY-010001,10002'

在这种情况下,log_error_verbosity允许具有ERRORWARNING优先级的消息,并丢弃具有INFORMATION优先级的消息。在未被丢弃的消息中,log_error_suppression_list会丢弃具有WARNING优先级和任何命名错误代码的消息。

注意

示例中显示的log_error_verbosity值为 2,这也是其默认值,因此该变量对INFORMATION消息的影响默认情况下如上所述,无需显式设置。如果要使log_error_suppression_list影响具有INFORMATION优先级的消息,必须将log_error_verbosity设置为 3。

考虑使用以下设置启动的服务器:

[mysqld]
log_error_verbosity=1 # error messages only

在这种情况下,log_error_verbosity 允许具有ERROR优先级的消息,并丢弃具有WARNINGINFORMATION优先级的消息。设置log_error_suppression_list 不起作用,因为它可能抑制的所有错误代码已经由log_error_verbosity 设置丢弃了。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-rule-based-filtering.html

7.4.2.6 基于规则的错误日志过滤(log_filter_dragnet)

log_filter_dragnet日志过滤组件基于用户定义的规则进行日志过滤。

要启用log_filter_dragnet过滤器,首先加载过滤器组件,然后修改log_error_services的值。以下示例启用了与内置日志接收器结合使用的log_filter_dragnet

INSTALL COMPONENT 'file://component_log_filter_dragnet';
SET GLOBAL log_error_services = 'log_filter_dragnet; log_sink_internal';

要设置log_error_services在服务器启动时生效,请使用第 7.4.2.1 节“错误日志配置”中的说明。这些说明也适用于其他错误日志系统变量。

启用log_filter_dragnet后,通过设置dragnet.log_error_filter_rules系统变量来定义其过滤规则。规则集由零个或多个规则组成,其中���个规则都是以句号(.)字符结尾的IF语句。如果变量值为空(零个规则),则不会进行过滤。

示例 1:此规则集丢弃信息事件,并对其他事件删除source_line字段:

SET GLOBAL dragnet.log_error_filter_rules =
  'IF prio>=INFORMATION THEN drop. IF EXISTS source_line THEN unset source_line.';

其效果类似于使用log_error_verbosity=2设置的log_sink_internal过滤器执行的过滤。

为了可读性,您可能会发现将规则列在单独的行上更可取。例如:

SET GLOBAL dragnet.log_error_filter_rules = '
  IF prio>=INFORMATION THEN drop.
  IF EXISTS source_line THEN unset source_line.
';

示例 2:此规则将信息事件限制为每 60 秒不超过一个:

SET GLOBAL dragnet.log_error_filter_rules =
  'IF prio>=INFORMATION THEN throttle 1/60.';

一旦您按照您的意愿设置了过滤配置,请考虑使用SET PERSIST而不是SET GLOBAL来分配dragnet.log_error_filter_rules,以使设置在服务器重新启动时持久化。或者,将设置添加到服务器选项文件中。

当使用log_filter_dragnet时,log_error_suppression_list会被忽略。

要停止使用过滤语言,首先从错误日志组件集中删除它。通常这意味着使用不同的过滤组件而不是没有过滤组件。例如:

SET GLOBAL log_error_services = 'log_filter_internal; log_sink_internal';

再次考虑使用SET PERSIST而不是SET GLOBAL来使设置在服务器重新启动时持久化。

然后卸载过滤器log_filter_dragnet组件:

UNINSTALL COMPONENT 'file://component_log_filter_dragnet';

以下部分更详细地描述了log_filter_dragnet操作的各个方面:

  • log_filter_dragnet 规则语言的语法

  • log_filter_dragnet 规则的操作

  • log_filter_dragnet 规则中的字段引用

log_filter_dragnet 规则语言的语法

以下语法定义了log_filter_dragnet过滤规则的语言。每个规则都是以句号(.)字符结尾的IF语句。该语言不区分大小写。

*rule*:
    IF *condition* THEN *action*
    [ELSEIF *condition* THEN *action*] ...
    [ELSE *action*]
    .

*condition*: {
    *field* *comparator* *value*
  | [NOT] EXISTS *field*
  | *condition* {AND | OR}  *condition*
}

*action*: {
    drop
  | throttle {*count* | *count* / *window_size*}
  | set *field* [:= | =] *value*
  | unset [*field*]
}

*field*: {
    *core_field*
  | *optional_field*
  | *user_defined_field*
}

*core_field*: {
    time
  | msg
  | prio
  | err_code
  | err_symbol
  | SQL_state
  | subsystem
}

*optional_field*: {
    OS_errno
  | OS_errmsg
  | label
  | user
  | host
  | thread
  | query_id
  | source_file
  | source_line
  | function
  | component
}

*user_defined_field*:
    *sequence of characters in [a-zA-Z0-9_] class*

*comparator*: {== | != | <> | >= | => | <= | =< | < | >}

*value*: {
    *string_literal*
  | *integer_literal*
  | *float_literal*
  | *error_symbol*
  | *priority*
}

*count*: *integer_literal*
*window_size*: *integer_literal*

*string_literal*:
    *sequence of characters quoted as '...' or "..."*

*integer_literal*:
    *sequence of characters in [0-9] class*

*float_literal*:
    *integer_literal*[.*integer_literal*]

*error_symbol*:
    *valid MySQL error symbol such as ER_ACCESS_DENIED_ERROR or ER_STARTUP*

*priority*: {
    ERROR
  | WARNING
  | INFORMATION
}

简单条件将字段与值进行比较或测试字段是否存在。要构建更复杂的条件,请使用ANDOR运算符。这两个运算符具有相同的优先级,并且从左到右进行评估。

要在字符串中转义字符,请在其前面加上反斜杠(\)。反斜杠用于包含反斜杠本身或字符串引号字符,对于其他字符是可选的。

为方便起见,log_filter_dragnet支持对某些字段进行比较的符号名称。为了可读性和可移植性,符号值比数值值更可取(适用的情况下)。

  • 事件优先级值 1、2 和 3 可以指定为ERRORWARNINGINFORMATION。优先级符号仅在与prio字段进行比较时才被识别。这些比较是等效的:

    IF prio == INFORMATION THEN ...
    IF prio == 3 THEN ...
    
  • 错误代码可以以数字形式或相应的错误符号指定。例如,ER_STARTUP是错误1408的符号名称,因此这些比较是等效的:

    IF err_code == ER_STARTUP THEN ...
    IF err_code == 1408 THEN ...
    

    仅在与err_code字段和用户定义字段进行比较时才识别错误符号。

    要找到与给定错误代码号对应的错误符号,请使用以下方法之一:

    • 在服务器错误消息参考中查看服务器错误列表。

    • 使用perror命令。给定一个错误号参数,perror会显示有关错误的信息,包括其符号。

    假设一个带有错误号的规则集如下所示:

    IF err_code == 10927 OR err_code == 10914 THEN drop.
    IF err_code == 1131 THEN drop.
    

    使用perror,确定错误符号:

    $> perror 10927 10914 1131
    MySQL error code MY-010927 (ER_ACCESS_DENIED_FOR_USER_ACCOUNT_LOCKED):
    Access denied for user '%-.48s'@'%-.64s'. Account is locked.
    MySQL error code MY-010914 (ER_ABORTING_USER_CONNECTION):
    Aborted connection %u to db: '%-.192s' user: '%-.48s' host:
    '%-.64s' (%-.64s).
    MySQL error code MY-001131 (ER_PASSWORD_ANONYMOUS_USER):
    You are using MySQL as an anonymous user and anonymous users
    are not allowed to change passwords
    

    通过用数字替换错误符号,规则集变为:

    IF err_code == ER_ACCESS_DENIED_FOR_USER_ACCOUNT_LOCKED
      OR err_code == ER_ABORTING_USER_CONNECTION THEN drop.
    IF err_code == ER_PASSWORD_ANONYMOUS_USER THEN drop.
    

符号名称可以作为带引号的字符串指定,用于与字符串字段进行比较,但在这种情况下,名称是没有特殊含义的字符串,log_filter_dragnet不会将其解析为相应的数值。此外,拼写错误可能不会被检测到,而在尝试使用服务器不认识的未引用符号时,SET会立即出现错误。

log_filter_dragnet 规则的操作

log_filter_dragnet 在过滤规则中支持以下操作:

  • drop: 丢弃当前日志事件(不记录)。

  • throttle: 应用速率限制以减少匹配特定条件的事件的日志冗余。参数表示速率,形式为countcount/window_sizecount值表示每个时间窗口允许记录的事件发生次数。window_size值是以秒为单位的时间窗口;如果省略,则默认窗口为 60 秒。这两个值必须是整数文字。

    此规则将插件关闭消息限制为每 60 秒 5 次:

    IF err_code == ER_PLUGIN_SHUTTING_DOWN_PLUGIN THEN throttle 5.
    

    此规则将错误和警告限制为每小时 1000 次,信息消息限制为每小时 100 次:

    IF prio <= INFORMATION THEN throttle 1000/3600 ELSE throttle 100/3600.
    
  • set: 为字段赋值(如果字段不存在,则创建)。在后续规则中,对字段名称的EXISTS测试为真,并且新值可以通过比较条件进行测试。

  • unset: 丢弃一个字段。在后续规则中,对字段名称的EXISTS测试为假,并且对字段与任何值的比较为假。

    在条件引用确切一个字段名称的特殊情况下,unset后面的字段名称是可选的,unset会丢弃命名字段。以下规则是等效的:

    IF myfield == 2 THEN unset myfield.
    IF myfield == 2 THEN unset.
    
log_filter_dragnet 规则中的字段引用

log_filter_dragnet 规则支持在错误事件中引用核心、可选和用户定义的字段。

  • 核心字段引用

  • 可选字段引用

  • 用户定义字段引用

核心字段引用

log_filter_dragnet 规则语言语法中列出了过滤规则识别的核心字段。有关这些字段的一般描述,请参见 7.4.2.3 节“错误事件字段”,假定您已经熟悉。以下备注仅提供与log_filter_dragnet规则中核心字段引用相关的特定信息。

  • prio

    事件优先级,用于指示错误、警告或注释/信息事件。在比较中,每个优先级可以指定为符号优先级名称或整数文字。优先级符号仅在与prio字段的比较中被识别。以下比较是等效的:

    IF prio == INFORMATION THEN ...
    IF prio == 3 THEN ...
    

    以下表格显示了允许的优先级级别。

    事件类型 优先级符号 数字优先级
    错误事件 ERROR 1
    警告事件 WARNING 2
    注意/信息事件 信息 3

    还有一个消息优先级为 SYSTEM,但系统消息无法被过滤,并且始终写入错误日志。

    优先级值遵循更高优先级具有较低值,反之亦然的原则。优先级值从最严重事件(错误)开始为 1,并随着优先级降低的事件而增加。例如,要丢弃优先级低于警告的事件,请测试高于 WARNING 的优先级值:

    IF prio > WARNING THEN drop.
    

    以下示例显示了实现与每个 log_error_verbosity 值类似效果的 log_filter_dragnet 规则:

    • 仅错误(log_error_verbosity=1):

      IF prio > ERROR THEN drop.
      
    • 错误和警告(log_error_verbosity=2):

      IF prio > WARNING THEN drop.
      
    • 错误、警告和注释(log_error_verbosity=3):

      IF prio > INFORMATION THEN drop.
      

      实际上,这个规则可以被省略,因为没有比 INFORMATION 更大的 prio 值,因此实际上它什么也不丢弃。

  • err_code

    数字事件错误代码。在比较中,要测试的值可以指定为符号错误名称或整数文字。错误符号仅在与 err_code 字段和用户定义字段的比较中被识别。这些比较是等效的:

    IF err_code == ER_ACCESS_DENIED_ERROR THEN ...
    IF err_code == 1045 THEN ...
    
  • err_symbol

    事件错误符号,作为字符串(例如,'ER_DUP_KEY')。 err_symbol 值更适用于识别日志输出中的特定行,而不适用于用于过滤规则比较,因为 log_filter_dragnet 不会将指定为字符串的比较值解析为等效的数值错误代码。(为了发生这种情况,必须使用未引用的符号指定错误。)

可选字段引用

log_filter_dragnet 语法在 Grammar for log_filter_dragnet Rule Language 中命名了过滤规则识别的可选字段。有关这些字段的一般描述,请参见 Section 7.4.2.3, “Error Event Fields”,假定您已熟悉。以下备注仅提供与 log_filter_dragnet 规则中使用的可选字段引用相关的特定信息。

  • 标签

    prio 值对应的标签,作为字符串。过滤规则可以更改支持自定义标签的日志接收器的标签。 label 值更适用于识别日志输出中的特定行,而不适用于用于过滤规则比较,因为 log_filter_dragnet 不会将指定为字符串的比较值解析为等效的数值优先级。

  • source_file

    事件发生的源文件,不包含任何前导路径。例如,要测试 sql/gis/distance.cc 文件,写比较如下:

    IF source_file == "distance.cc" THEN ...
    
用户定义字段引用

log_filter_dragnet过滤规则中,任何未被识别为核心或可选字段名称的字段名称都被视为用户定义字段。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-json.html

7.4.2.7 JSON 格式错误日志

本节描述了如何使用内置过滤器log_filter_internal和 JSON sinklog_sink_json立即生效并在后续服务器启动时生效。有关配置错误日志的一般信息,请参阅 Section 7.4.2.1, “错误日志配置”。

要启用 JSON sink,请首先加载 sink 组件,然后修改log_error_services的值:

INSTALL COMPONENT 'file://component_log_sink_json';
SET PERSIST log_error_services = 'log_filter_internal; log_sink_json';

要在服务器启动时设置log_error_services生效,请使用 Section 7.4.2.1, “错误日志配置”中的说明。这些说明也适用于其他错误日志系统变量。

log_error_services的值中可以多次命名log_sink_json。例如,要使用一个实例写入未经过滤的事件,使用另一个实例写入经过滤的事件,可以设置log_error_services如下:

SET PERSIST log_error_services = 'log_sink_json; log_filter_internal; log_sink_json';

JSON sink 根据默认错误日志目的地确定其输出目的地,该目的地由log_error系统变量给出。如果log_error命名一个文件,则 JSON sink 基于该文件名进行输出文件命名,加上一个编号为.*NN*.json的后缀,其中NN从 00 开始。例如,如果log_errorfile_name,则在log_error_services的值中连续的log_sink_json实例将写入*file_name*.00.json*file_name*.01.json等。

如果log_errorstderr,则 JSON sink 写入控制台。如果在log_error_services的值中多次命名log_sink_json,它们都将写入控制台,这可能没有用处。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-syslog.html

7.4.2.8 将错误日志记录到系统日志

可以让mysqld将错误日志写入系统日志(Windows 上的事件日志,Unix 和类 Unix 系统上的syslog)。

本节描述如何使用内置过滤器log_filter_internal和系统日志接收器log_sink_syseventlog配置错误日志记录,以立即生效并在后续服务器启动时生效。有关配置错误日志的一般信息,请参阅 Section 7.4.2.1, “错误日志配置”。

要启用系统日志接收器,首先加载接收器组件,然后修改log_error_services的值:

INSTALL COMPONENT 'file://component_log_sink_syseventlog';
SET PERSIST log_error_services = 'log_filter_internal; log_sink_syseventlog';

要在服务器启动时设置log_error_services生效,请使用 Section 7.4.2.1, “错误日志配置”中的说明。这些说明也适用于其他错误日志系统变量。

注意

对于 MySQL 8.0 配置,您必须显式启用将错误日志记录到系统日志。这与 MySQL 5.7 及更早版本不同,在 Windows 上默认启用将错误日志记录到系统日志,并且在所有平台上不需要加载组件。

将错误日志记录到系统日志可能需要额外的系统配置。请查阅您平台的系统日志文档。

在 Windows 上,写入应用程序日志中的事件日志错误消息具有以下特征:

  • 标记为ErrorWarningNote的条目会被写入事件日志,但不包括来自各个存储引擎的信息声明。

  • 事件日志条目的来源是MySQL(或MySQL-*tag*,如果syseventlog.tag定义为tag)。

在 Unix 和类 Unix 系统上,记录到系统日志使用syslog。以下系统变量会影响syslog消息:

  • syseventlog.facilitysyslog消息的默认设施是daemon。设置此变量以指定不同的设施。

  • syseventlog.include_pid:是否在每行syslog输出中包含服务器进程 ID。

  • syseventlog.tag:此变量定义要添加到syslog消息中服务器标识符(mysqld)的标记。如果定义了标记,则标记将以前导连字符附加到标识符后面。

注意

在 MySQL 8.0.13 之前,请使用log_syslog_facilitylog_syslog_include_pidlog_syslog_tag系统变量,而不是syseventlog.*xxx*变量。

MySQL 使用自定义标签“系统”来表示关于非错误情况的重要系统消息,例如启动、关闭和一些重要设置更改。在不支持自定义标签的日志中,包括 Windows 上的事件日志和 Unix 及类 Unix 系统上的syslog,系统消息被分配给信息优先级级别使用的标签。然而,即使 MySQL log_error_verbosity 设置通常排除信息级别的消息,这些消息也会被打印到日志中。

当日志接收器必须以“信息”标签而不是“系统”标签回退时,并且日志事件在 MySQL 服务器外进一步处理(例如,通过syslog配置进行过滤或转发),这些事件可能默认由次要应用程序处理为“信息”优先级而不是“系统”优先级。

原文:dev.mysql.com/doc/refman/8.0/en/error-log-format.html

7.4.2.9 错误日志输出格式

每个错误日志输出组件都有其用于将消息写入目的地的特征输出格式,但其他因素可能影响消息的内容:

  • 日志输出可用的信息。如果在执行输出组件之前执行了日志过滤组件以删除日志事件字段,则该字段不可用于写入。有关日志过滤的信息,请参阅第 7.4.2.4 节,“错误日志过滤类型”。

  • 与日志输出组件相关的信息。并非每个输出组件都会写入错误事件中可用的所有字段。

  • 系统变量可能会影响日志输出。请参阅影响错误日志格式的系统变量。

有关错误事件中字段的名称和描述,请参阅第 7.4.2.3 节,“错误事件字段”。对于所有日志输出,包含在错误日志消息中的线程 ID 是负责编写消息的mysqld内的线程 ID。此 ID 指示服务器的哪个部分生成了消息,并与一般查询日志和慢查询日志消息一致,这些消息包括连接线程 ID。

  • log_sink_internal 输出格式

  • log_sink_json 输出格式

  • log_sink_syseventlog 输出格式

  • 早期启动日志输出格式

  • 影响错误日志格式的系统变量

log_sink_internal 输出格式

内部日志输出产生传统错误日志输出。例如:

2020-08-06T14:25:02.835618Z 0 [Note] [MY-012487] [InnoDB] DDL log recovery : begin
2020-08-06T14:25:02.936146Z 0 [Warning] [MY-010068] [Server] CA certificate /var/mysql/sslinfo/cacert.pem is self signed.
2020-08-06T14:25:02.963127Z 0 [Note] [MY-010253] [Server] IPv6 is available.
2020-08-06T14:25:03.109022Z 5 [Note] [MY-010051] [Server] Event Scheduler: scheduler thread started with id 5

传统格式消息具有以下字段:

time thread [label] [err_code] [subsystem] msg

[] 方括号字符是消息格式中的文字字符。它们不表示字段是可选的。

label 值对应于 prio 错误事件优先级字段的字符串形式。

[err_code][subsystem] 字段在 MySQL 8.0 中添加。这些字段在旧服务器生成的日志中缺失。日志解析器可以将这些字段视为仅在包含它们的新服务器生成的日志中存在的消息文本的一部分。解析器必须将 [err_code] 指示器中的 err_code 部分视为字符串值,而不是数字,因为像 MY-012487MY-010051 这样的值包含非数字字符。

log_sink_json 输出格式

JSON 格式的日志接收器生成包含键值对的 JSON 对象作为消息。例如:

{
  "prio": 3,
  "err_code": 10051,
  "source_line": 561,
  "source_file": "event_scheduler.cc",
  "function": "run",
  "msg": "Event Scheduler: scheduler thread started with id 5",
  "time": "2020-08-06T14:25:03.109022Z",
  "ts": 1596724012005,
  "thread": 5,
  "err_symbol": "ER_SCHEDULER_STARTED",
  "SQL_state": "HY000",
  "subsystem": "Server",
  "buffered": 1596723903109022,
  "label": "Note"
}

显示的消息已经重新格式化以提高可读性。写入错误日志的事件每行显示一条消息。

ts(时间戳)键在 MySQL 8.0.20 中添加,是 JSON 格式日志接收器特有的。其值是一个整数,表示自纪元('1970-01-01 00:00:00' UTC)以来的毫秒数。

tsbuffered 值是 Unix 时间戳值,可以使用 FROM_UNIXTIME() 和适当的除数进行转换:

mysql> SET time_zone = '+00:00';
mysql> SELECT FROM_UNIXTIME(1596724012005/1000.0);
+-------------------------------------+
| FROM_UNIXTIME(1596724012005/1000.0) |
+-------------------------------------+
| 2020-08-06 14:26:52.0050            |
+-------------------------------------+
mysql> SELECT FROM_UNIXTIME(1596723903109022/1000000.0);
+-------------------------------------------+
| FROM_UNIXTIME(1596723903109022/1000000.0) |
+-------------------------------------------+
| 2020-08-06 14:25:03.1090                  |
+-------------------------------------------+
log_sink_syseventlog 输出格式

系统日志接收器生成符合本地平台使用的系统日志格式的输出。

早期启动日志输出格式

服务器在启动选项被处理之前生成一些错误日志消息,因此在了解错误日志设置(如log_error_verbositylog_timestamps系统变量值)以及要使用的日志组件之前。服务器处理在启动过程中生成的错误日志消息如下:

  • 在 MySQL 8.0.14 之前,服务器生成具有默认时间戳、格式和详细级别的消息,并对其进行缓冲。在处理启动选项并了解错误日志配置之后,服务器会刷新缓冲的消息。由于这些早期消息使用默认日志配置,它们可能与启动选项指定的内容不同。此外,早期消息不会刷新到除默认接收器之外的日志接收器。例如,记录到 JSON 接收器不包括这些早期消息,因为它们不是 JSON 格式。

  • 从 MySQL 8.0.14 开始,服务器缓冲日志事件而不是格式化的日志消息。这使得在了解设置之后可以对这些事件进行追溯应用配置设置,结果是刷新的消息使用配置的设置,而不是默认设置。此外,消息会刷新到所有配置的接收器,而不仅仅是默认接收器。

    如果在日志配置未知之前发生致命错误并且服务器必须退出,则服务器使用日志默认值格式化缓冲消息,以免丢失。如果没有发生致命错误,但启动在处理启动选项之前过于缓慢,则服务器会定期使用日志默认值格式化和刷新缓冲消息,以免显得无响应。尽管这种行为类似于 8.0.14 之前的行为,即使用默认值,但在异常情况发生时不丢失消息更为可取。

影响错误日志格式的系统变量

log_timestamps系统变量控制写入错误日志(以及一般查询日志和慢查询日志文件)中时间戳的时区。服务器在错误事件到达任何日志接收端之前应用log_timestamps,因此它影响所有接收端的错误消息输出。

允许的log_timestamps值为UTC(默认)和SYSTEM(本地系统时区)。时间戳使用 ISO 8601 / RFC 3339 格式写入:*YYYY-MM-DD*T*hh:mm:ss.uuuuuu* 加上一个尾部值Z表示 Zulu 时间(UTC)或±hh:mm(一个指示本地系统时区相对于 UTC 的调整偏移)。例如:

2020-08-07T15:02:00.832521Z            (UTC)
2020-08-07T10:02:00.832521-05:00       (SYSTEM)

原文:dev.mysql.com/doc/refman/8.0/en/error-log-rotation.html

7.4.2.10 错误日志文件清空和重命名

如果使用FLUSH ERROR LOGSFLUSH LOGS语句,或者使用mysqladmin flush-logs命令来清空错误日志,服务器将关闭并重新打开正在写入的任何错误日志文件。在清空之前,请手动重命名错误日志文件。清空日志后,将使用原始文件名打开一个新文件。例如,假设日志文件名为*host_name*.err,请使用以下命令重命名文件并创建一个新文件:

mv *host_name*.err *host_name*.err-old
mysqladmin flush-logs error
mv *host_name*.err-old *backup-directory*

在 Windows 上,请使用rename而不是mv

如果服务器无法写入错误日志文件的位置,则清空日志操作将无法创建新的日志文件。例如,在 Linux 上,服务器可能会将错误日志写入/var/log/mysqld.log文件,其中/var/log目录由root所有且不可写入mysqld。有关处理此情况的信息,请参见第 7.4.6 节“服务器日志维护”。

如果服务器没有写入命名的错误日志文件,则在清空错误日志时不会发生错误日志文件重命名。

7.4.3 通用查询日志

译文:dev.mysql.com/doc/refman/8.0/en/query-log.html

通用查询日志是mysqld正在执行的一般记录。当客户端连接或断开连接时,服务器会将信息写入此日志,并记录从客户端接收的每个 SQL 语句。当您怀疑客户端中存在错误并想确切知道客户端发送给mysqld的内容时,通用查询日志可能非常有用。

每当客户端连接时显示的每一行还包括using *connection_type*,表示建立连接所使用的协议。connection_type可以是TCP/IP(未使用 SSL 建立的 TCP/IP 连接)、SSL/TLS(使用 SSL 建立的 TCP/IP 连接)、Socket(Unix 套接字文件连接)、Named Pipe(Windows 命名管道连接)或Shared Memory(Windows 共享内存连接)。

mysqld按照接收到的顺序将语句写入查询日志,这可能与执行顺序不同。这种记录顺序与二进制日志的记录顺序相反,二进制日志中的语句是在执行后但在释放任何锁之前写入的。此外,查询日志可能包含仅选择数据的语句,而这些语句永远不会写入二进制日志。

在复制源服务器上使用基于语句的二进制日志记录时,其副本接收的语句将写入每个副本的查询日志。如果客户端使用mysqlbinlog实用程序读取事件并将其传递给服务器,则语句将写入源的查询日志。

然而,当使用基于行的二进制日志记录时,更新以行更改的形式发送,而不是 SQL 语句,因此当binlog_format设置为ROW时,这些语句永远不会写入查询日志。当此变量设置为MIXED时,根据使用的语句,给定的更新也可能不会写入查询日志。有关更多信息,请参见 Section 19.2.1.1, “基于语句和基于行的复制的优缺点”。

默认情况下,通用查询日志被禁用。要明确指定初始通用查询日志状态,请使用--general_log[={0|1}]。没有参数或参数为 1 时,--general_log启用日志。参数为 0 时,此选项禁用日志。要指定日志文件名,请使用--general_log_file=*file_name*。要指定日志目的地,请使用log_output系统变量(如第 7.4.1 节,“选择通用查询日志和慢查询日志输出目的地”中所述)。

注意

如果指定了TABLE日志目的地,请参阅日志表和“打开文件过多”错误。

如果未为通用查询日志文件指定名称,则默认名称为*host_name*.log。服务器会在数据目录中创建文件,除非给定绝对路径名以指定不同的目录。

要在运行时禁用或启用通用查询日志或更改日志文件名,请使用全局general_loggeneral_log_file系统变量。将general_log设置为 0(或OFF)以禁用日志,设置为 1(或ON)以启用日志。设置general_log_file以指定日志文件的名称。如果已经打开了日志文件,则会关闭该文件并打开新文件。

当启用通用查询日志时,服务器会将输出写入由log_output系统变量指定的任何目的地。如果启用日志,服务器会打开日志文件并将启动消息写入其中。但是,除非选择了FILE日志目的地,否则不会进一步记录查询到文件中。如果目的地是NONE,即使启用了通用日志,服务器也不会写入任何查询。如果日志目的地值不包含FILE,设置日志文件名对日志记录没有影响。

服务器重启和日志刷新不会导致生成新的通用查询日志文件(尽管刷新会关闭并重新打开它)。要重命名文件并创建一个新文件,请使用以下命令:

$> mv *host_name*.log *host_name*-old.log
$> mysqladmin flush-logs general
$> mv *host_name*-old.log *backup-directory*

在 Windows 上,使用rename而不是mv

您还可以通过禁用日志来在运行时重命名通用查询日志文件:

SET GLOBAL general_log = 'OFF';

禁用日志后,通过外部重命名日志文件(例如,从命令行)然后再次启用日志:

SET GLOBAL general_log = 'ON';

这种方法适用于任何平台,不需要服务器重启。

要为当前会话禁用或启用一般查询日志记录,请将会话 sql_log_off 变量设置为 ONOFF。(这假定一般查询日志本身已启用。)

写入一般查询日志的语句中的密码会被服务器重写,以避免以明文形式出现。可以通过使用 --log-raw 选项启动服务器来阻止一般查询日志的密码重写。这个选项可能对诊断目的有用,以查看服务器接收到的语句的确切文本,但出于安全原因,不建议在生产环境中使用。另请参见 Section 8.1.2.3, “Passwords and Logging”。

密码重写的一个影响是无法解析的语句(例如由于语法错误)不会被写入一般查询日志,因为无法知道它们是否不包含密码。需要记录所有语句(包括带有错误的语句)的用例应该使用 --log-raw 选项,需要注意的是这也会绕过密码重写。

只有在预期明文密码时才会进行密码重写。对于期望密码哈希值的语法的语句,不会进行重写。如果错误地为这种语法提供了明文密码,则密码将按原样记录,而不进行重写。

log_timestamps 系统变量控制着写入一般查询日志文件(以及慢查询日志文件和错误日志)中的时间戳的时区。它不影响写入日志表的一般查询日志和慢查询日志消息的时区,但是从这些表中检索的行可以通过 CONVERT_TZ() 或设置会话 time_zone 系统变量将其从本地系统时区转换为任何所需的时区。

7.4.4 二进制日志

原文:dev.mysql.com/doc/refman/8.0/en/binary-log.html

7.4.4.1 二进制日志格式

7.4.4.2 设置二进制日志格式

7.4.4.3 混合二进制日志格式

7.4.4.4 更改 mysql 数据库表的日志格式

7.4.4.5 二进制日志事务压缩

二进制日志包含描述数据库更改的“事件”,例如表创建操作或表数据更改。它还包含可能已经进行更改的语句的事件(例如,一个DELETE未匹配任何行),除非使用基于行的日志记录。二进制日志还包含更新数据的每个语句所花费的时间信息。二进制日志有两个重要目的:

  • 对于复制,复制源服务器上的二进制日志提供了要发送到副本的数据更改记录。源服务器将其二进制日志中包含的信息发送给其副本,副本会重现这些事务以进行与源服务器上进行的相同数据更改。参见第 19.2 节,“复制实现”。

  • 某些数据恢复操作需要使用二进制日志。在备份被恢复后,备份后记录的二进制日志中的事件将被重新执行。这些事件将数据库从备份点更新到最新状态。参见第 9.5 节,“时间点(增量)恢复” Recovery")。

二进制日志不用于诸如SELECTSHOW等不修改数据的语句。要记录所有语句(例如,以识别问题查询),请使用一般查询日志。参见第 7.4.3 节,“一般查询日志”。

启用二进制日志记录的服务器运行性能略有下降。然而,二进制日志在启用复制和进行恢复操作方面的好处通常超过了这种轻微的性能降低。

二进制日志对意外停止是有弹性的。只有完整的事件或事务才会被记录或读取回来。

写入二进制日志的语句中的密码由服务器重写,以避免明文出现。另请参见第 8.1.2.3 节,“密码和日志记录”。

从 MySQL 8.0.14 开始,二进制日志文件和中继日志文件可以加密,有助于保护这些文件以及其中可能包含的敏感数据免受外部攻击者的滥用,也免受存储它们的操作系统用户的未经授权查看。 您可以通过将 binlog_encryption 系统变量设置为 ON 在 MySQL 服务器上启用加密。 有关更多信息,请参见 Section 19.3.2, “加密二进制日志文件和中继日志文件”。

以下讨论描述了一些影响二进制日志记录操作的服务器选项和变量。 完整列表,请参见 Section 19.1.6.4, “二进制日志记录选项和变量”。

二进制日志记录默认启用(log_bin 系统变量设置为 ON)。 例外情况是,如果您使用 mysqld 手动调用 --initialize--initialize-insecure 选项初始化数据目录,则默认情况下禁用二进制日志记录,但可以通过指定 --log-bin 选项启用。

要禁用二进制日志记录,您可以在启动时指定 --skip-log-bin--disable-log-bin 选项。 如果指定了其中任何一个选项,并且同时指定了 --log-bin,则后面指定的选项优先。

--log-slave-updates--slave-preserve-commit-order选项需要进行二进制日志记录。如果禁用二进制日志记录,要么省略这些选项,要么指定--log-slave-updates=OFF--skip-slave-preserve-commit-order。当指定--skip-log-bin--disable-log-bin时,MySQL 默认禁用这些选项。如果同时指定--log-slave-updates--slave-preserve-commit-order--skip-log-bin--disable-log-bin,将发出警告或错误消息。

--log-bin[=*base_name*]选项用于指定二进制日志文件的基本名称。如果不提供--log-bin选项,MySQL 将使用binlog作为二进制日志文件的默认基本名称。为了与早期版本兼容,如果提供了--log-bin选项但没有字符串或为空字符串,则基本名称默认为*host_name*-bin,使用主机机器的名称。建议您指定一个基本名称,这样如果主机名更改,您可以轻松地继续使用相同的二进制日志文件名称(参见 Section B.3.7, “Known Issues in MySQL”)。如果在日志名称中提供了扩展名(例如,--log-bin=*base_name.extension*),则扩展名会被静默删除并忽略。

mysqld会在二进制日志基本名称后附加一个数字扩展名以生成二进制日志文件名称。每次服务器创建新的日志文件时,该数字会增加,从而创建一个有序的文件系列。每当发生以下事件之一时,服务器都会在系列中创建一个新文件:

  • 服务器启动或重新启动

  • 服务器会刷新日志。

  • 当��日志文件的大小达到max_binlog_size设置的大小。

如果使用大型事务,二进制日志文件可能会比max_binlog_size设置的大小更大,因为事务会一次性写入文件,而不会在文件之间分割。

为了跟踪已使用的二进制日志文件,mysqld还会创建一个包含二进制日志文件名称的二进制日志索引文件。默认情况下,这个文件与二进制日志文件具有相同的基本名称,扩展名为'.index'。您可以使用--log-bin-index[=*file_name*]选项更改二进制日志索引文件的名称。在mysqld运行时不应手动编辑此文件;这样做会使mysqld混淆。

术语“二进制日志文件”通常表示包含数据库事件的单个编号文件。术语“二进制日志”集体表示一组编号的二进制日志文件和索引文件。

默认的二进制日志文件和二进制日志索引文件的位置是数据目录。您可以使用--log-bin选项来指定另一个位置,只需在基本名称前添加绝对路径名以指定不同的目录。当服务器从二进制日志索引文件中读取条目时(该文件跟踪已使用的二进制日志文件),它会检查条目是否包含相对路径。如果包含相对路径,则使用--log-bin选项设置的绝对路径将替换路径的相对部分。在二进制日志索引文件中记录的绝对路径保持不变;在这种情况下,必须手动编辑索引文件以启用新路径或路径的使用。二进制日志文件基本名称和任何指定的路径可作为log_bin_basename系统变量使用。

在 MySQL 5.7 中,启用二进制日志记录时必须指定服务器 ID,否则服务器将无法启动。在 MySQL 8.0 中,默认情况下将server_id系统变量设置为 1。当启用二进制日志记录时,服务器可以使用此默认 ID 启动,但如果您不使用server_id系统变量显式指定服务器 ID,则会发出信息消息。对于用于复制拓扑的服务器,必须为每个服务器指定唯一的非零服务器 ID。

拥有足够权限设置受限会话系统变量的客户端(参见第 7.1.9.1 节,“系统变量权限”)可以通过使用SET sql_log_bin=OFF语句禁用自己语句的二进制日志记录。

默认情况下,服务器记录事件的长度以及事件本身,并使用这些信息来验证事件是否正确写入。您还可以通过设置binlog_checksum系统变量来导致服务器为事件编写校验和。从二进制日志中读取时,默认情况下源使用事件长度,但可以通过启用系统变量source_verify_checksum(从 MySQL 8.0.26 开始)或master_verify_checksum(在 MySQL 8.0.26 之前)来使用校验和(如果可用)。副本上的复制 I/O(接收器)线程还会验证从源接收的事件。您可以通过启用系统变量replica_sql_verify_checksum(从 MySQL 8.0.26 开始)或slave_sql_verify_checksum(在 MySQL 8.0.26 之前)来导致复制 SQL(应用程序)线程在从中继日志读取时使用校验和(如果可用)。

记录在二进制日志中的事件的格式取决于二进制日志格式。支持三种格式类型:基于行的日志记录、基于语句的日志记录和混合基于日志记录。所使用的二进制日志格式取决于 MySQL 版本。有关日志格式的一般描述,请参见 Section 7.4.4.1, “Binary Logging Formats”。有关二进制日志格式的详细信息,请参见 MySQL Internals: The Binary Log。

服务器以与--replicate-do-db--replicate-ignore-db选项相同的方式评估--binlog-do-db--binlog-ignore-db选项。有关此操作的信息,请参见 Section 19.2.5.1, “Evaluation of Database-Level Replication and Binary Logging Options”。

一个复制品默认启用系统变量log_replica_updates(从 MySQL 8.0.26 开始)或log_slave_updates(MySQL 8.0.26 之前),这意味着复制品会将从源接收到的任何数据修改写入自己的二进制日志。必须启用二进制日志才能使此设置生效(参见第 19.1.6.3 节,“复制品服务器选项和变量”)。此设置使复制品能够作为其他复制品的源。

您可以使用RESET MASTER语句删除所有二进制日志文件,或使用PURGE BINARY LOGS删除其中的一部分。请参见第 15.7.8.6 节,“RESET 语句”,以及第 15.4.1.1 节,“PURGE BINARY LOGS 语句”。

如果您正在使用复制,应在确定没有复制品仍然需要使用旧二进制日志文件之前,不要删除源上的旧二进制日志文件。例如,如果您的复制品永远不会落后于三天,那么每天您可以在源上执行mysqladmin flush-logs binary,然后删除三天前的任何日志。您可以手动删除文件,但最好使用PURGE BINARY LOGS,这也会安全地为您更新二进制日志索引文件(并且可以接受日期参数)。请参见第 15.4.1.1 节,“PURGE BINARY LOGS 语句”。

您可以使用mysqlbinlog实用程序显示二进制日志文件的内容。当您想要重新处理日志中的语句以进行恢复操作时,这可能很有用。例如,您可以按以下方式从二进制日志更新 MySQL 服务器:

$> mysqlbinlog *log_file* | mysql -h *server_name*

mysqlbinlog还可以用于显示复制品上中继日志文件的内容,因为它们使用与二进制日志文件相同的格式进行编写。有关mysqlbinlog实用程序及其使用方法的更多信息,请参见第 6.6.9 节,“mysqlbinlog — 用于处理二进制日志文件的实用���序”。有关二进制日志和恢复操作的更多信息,请参见第 9.5 节,“时间点(增量)恢复”。

二进制日志记录在语句或事务完成后立即进行,但在释放任何锁或执行任何提交之前。这确保了日志按提交顺序记录。

对非事务表的更新会立即存储在二进制日志中。

在未提交的事务中,所有更新(UPDATEDELETEINSERT)对更改事务表(如 InnoDB 表)的操作都会被缓存,直到服务器接收到 COMMIT 语句。此时,mysqld 在执行 COMMIT 之前将整个事务写入二进制日志。

对非事务表的修改无法回滚。如果要回滚的事务包括对非事务表的修改,则整个事务将以 ROLLBACK 语句记录,以确保这些表的修改被复制。

当处理事务的线程启动时,它会分配一个大小为 binlog_cache_size 的缓冲区来缓冲语句。如果语句大于此值,线程将打开一个临时文件来存储事务。当线程结束时,临时文件将被删除。从 MySQL 8.0.17 开始,如果服务器上启用了二进制日志加密,则临时文件将被加密。

Binlog_cache_use 状态变量显示了使用此缓冲区(可能还包括临时文件)存储语句的事务数量。Binlog_cache_disk_use 状态变量显示了实际需要使用临时文件的事务数量。这两个变量可用于调整 binlog_cache_size 的值,使其足够大,避免使用临时文件。

max_binlog_cache_size 系统变量(默认为 4GB,也是最大值)可用于限制用于缓存多语句事务的总大小。如果事务大于此字节数,它将失败并回滚。最小值为 4096。

如果您正在使用二进制日志和基于行的日志记录,CREATE ... SELECTINSERT ... SELECT语句中的并发插入将转换为普通插入。这样做是为了确保您可以通过在备份操作期间应用日志来重新创建表的精确副本。如果使用基于语句的日志记录,则原始语句将写入日志。

二进制日志格式存在一些已知限制,可能会影响从备份中恢复。参见第 19.5.1 节,“复制功能和问题”。

存储程序的二进制日志记录如第 27.7 节,“存储程序二进制日志记录”所述。

请注意,由于复制功能的增强,MySQL 8.0 中的二进制日志格式与 MySQL 先前版本不同。请参见第 19.5.2 节,“MySQL 版本之间的复制兼容性”。

如果服务器无法写入二进制日志,刷新二进制日志文件,或将二进制日志同步到磁盘,复制源服务器上的二进制日志可能会变得不一致,副本可能会与源失去同步。binlog_error_action系统变量控制在遇到此类错误时采取的操作。

  • 默认设置ABORT_SERVER使服务器停止二进制日志记录并关闭。此时,您可以识别和纠正错误的原因。在重新启动时,恢复将如同意外服务器停止的情况一样进行(参见第 19.4.2 节,“处理副本意外停止”)。

  • 设置IGNORE_ERROR提供与旧版本 MySQL 的向后兼容性。使用此设置,服务器将继续进行进行中的事务并记录错误,然后停止二进制日志记录,但继续执行更新。此时,您可以识别和纠正错误的原因。要恢复二进制日志记录,必须重新启用log_bin,这需要重新启动服务器。只有在需要向后兼容性,并且二进制日志在此 MySQL 服务器实例上是非必需的情况下才使用此选项。例如,您可能仅将二进制日志用于服务器的间歇性审计或调试,并且不将其用于从服务器复制或依赖于其进行时间点还原操作。

默认情况下,二进制日志在每次写入时都会同步到磁盘(sync_binlog=1)。如果未启用sync_binlog,并且操作系统或机器(不仅仅是 MySQL 服务器)崩溃,那么二进制日志的最后几条语句可能会丢失。为了防止这种情况发生,启用sync_binlog系统变量,以在每个N提交组后将二进制日志同步到磁盘。参见第 7.1.8 节,“服务器系统变量”。sync_binlog的最安全值是 1(默认值),但这也是最慢的。

在早期的 MySQL 版本中,即使将sync_binlog设置为 1,如果发生崩溃,表内容和二进制日志内容之间仍可能存在不一致的情况。例如,如果您正在使用InnoDB表,并且 MySQL 服务器处理一个COMMIT语句,它会按顺序将许多准备好的事务写入二进制日志,同步二进制日志,然后将事务提交到InnoDB。如果服务器在这两个操作之间意外退出,InnoDB会在重新启动时回滚事务,但事务仍然存在于二进制日志中。在以前的版本中,通过在 XA 事务中启用InnoDB支持两阶段提交来解决了这个问题。在 MySQL 8.0 中,InnoDB对 XA 事务中的两阶段提交始终是启用的。

InnoDB对 XA 事务中的两阶段提交支持确保了二进制日志和InnoDB数据文件的同步。然而,MySQL 服务器还应配置为在提交事务之前将二进制日志和InnoDB日志同步到磁盘。InnoDB日志默认是同步的,而sync_binlog=1确保了二进制日志的同步。隐式InnoDB对 XA 事务中的两阶段提交支持和sync_binlog=1的效果是,在崩溃后重新启动后,在回滚事务后,MySQL 服务器会扫描最新的二进制日志文件以收集事务xid值,并计算二进制日志文件中的最后有效位置。然后,MySQL 服务器告诉InnoDB完成已成功写入二进制日志的任何准备好的事务,并将二进制日志截断到最后的有效位置。这确保了二进制日志反映了InnoDB表的确切数据,因此复制品保持与源的同步,因为它不会接收已回滚的语句。

如果 MySQL 服务器在崩溃恢复时发现二进制日志比应该的长度短,那么至少缺少一个成功提交的InnoDB事务。如果sync_binlog=1,并且磁盘/文件系统在被请求时进行了实际同步(有些不会),那么不应该发生这种情况,因此服务器会打印错误消息The binary log *file_name* is shorter than its expected size。在这种情况下,此二进制日志不正确,复制应该从源数据的新快照重新启动。

以下系统变量的会话值将被写入二进制日志,并在解析二进制日志时被复制实例所遵守:

  • sql_mode(除了NO_DIR_IN_CREATE模式不会被复制;参见第 19.5.1.39 节,“复制和变量”)

  • foreign_key_checks

  • unique_checks

  • character_set_client

  • collation_connection

  • collation_database

  • collation_server

  • sql_auto_is_null

原文:dev.mysql.com/doc/refman/8.0/en/binary-log-formats.html

7.4.4.1 二进制日志格式

服务器使用几种日志记录格式来记录二进制日志中的信息:

  • MySQL 中的复制功能最初基于从源到副本的 SQL 语句传播。这被称为基于语句的日志记录。您可以通过使用--binlog-format=STATEMENT启动服务器来使用此格式。

  • 基于行的日志记录(默认情况下)中,源将事件写入二进制日志,指示单个表行受到的影响。您可以通过使用--binlog-format=ROW启动服务器来使用基于行的日志记录。

  • 还有第三个选项:混合日志记录。使用混合日志记录,默认情况下使用基于语句的日志记录,但在某些情况下自动切换到基于行的日志记录,如下所述。您可以通过使用选项--binlog-format=MIXED显式启动 MySQL 来使用混合日志记录。

日志记录格式也可以由正在使用的存储引擎设置或限制。这有助于消除在源和副本之间复制某些语句时使用不同存储引擎时出现的问题。

使用基于语句的复制时,可能会出现复制非确定性语句的问题。在决定给定语句是否适合基于语句的复制时,MySQL 确定是否可以保证该语句可以使用基于语句的日志记录进行复制。如果 MySQL 无法做出此保证,则将该语句标记为潜在不可靠,并发出警告,语句可能不安全以语句格式记录。

您可以通过使用 MySQL 的基于行的复制来避免这些问题。

原文:dev.mysql.com/doc/refman/8.0/en/binary-log-setting.html

7.4.4.2 设置二进制日志格式

您可以通过使用--binlog-format=*type*启动 MySQL 服务器来明确选择二进制日志记录格式。type支持的值为:

  • STATEMENT导致记录以语句为基础。

  • ROW导致记录以行为基础。这是默认设置。

  • MIXED导致记录使用混合格式。

设置二进制日志记录格式不会激活服务器的二进制日志记录。该设置仅在服务器启用二进制日志记录时生效,当log_bin系统变量设置为ON时为此情况。从 MySQL 8.0 开始,默认情况下启用二进制日志记录,只有在启动时指定--skip-log-bin--disable-log-bin选项时才会禁用。

记录格式也可以在运行时切换,尽管请注意,在本节后面讨论的一些情况下,您无法这样做。设置全局值binlog_format系统变量以指定更改后连接的客户端的格式:

mysql> SET GLOBAL binlog_format = 'STATEMENT';
mysql> SET GLOBAL binlog_format = 'ROW';
mysql> SET GLOBAL binlog_format = 'MIXED';

通过设置binlog_format的会话值,个别客户端可以控制其自己语句的记录格式:

mysql> SET SESSION binlog_format = 'STATEMENT';
mysql> SET SESSION binlog_format = 'ROW';
mysql> SET SESSION binlog_format = 'MIXED';

更改全局binlog_format值需要具有足够权限来设置全局系统变量。更改会话binlog_format值需要具有足够权限来设置受限会话系统变量。参见 Section 7.1.9.1, “System Variable Privileges”。

有几个原因可能导致客户端希望按会话设置二进制日志记录:

  • 对数据库进行许多小更改的会话可能希望使用基于行的记录。

  • 执行更新匹配WHERE子句中许多行的会话可能希望使用基于语句的记录,因为记录少量语句比记录许多行更有效率。

  • 一些语句在源端执行时需要大量时间,但只会修改少量行。因此,使用基于行的记录可能是有益的。

在运行时无法切换复制格式的情况有例外:

  • 无法从存储函数或触发器内部更改复制格式。

  • 如果启用了NDB存储引擎。

  • 如果会话中有打开的临时表,则无法为该会话更改复制格式(SET @@SESSION.binlog_format)。

  • 如果任何复制通道有打开的临时表,则无法全局更改复制格式(SET @@GLOBAL.binlog_formatSET @@PERSIST.binlog_format)。

  • 如果任何复制通道应用程序线程当前正在运行,则无法全局更改复制格式(SET @@GLOBAL.binlog_formatSET @@PERSIST.binlog_format)。

在这些情况下尝试切换复制格式(或尝试设置当前复制格式)会导致错误。但是,您可以随时使用 PERSIST_ONLYSET @@PERSIST_ONLY.binlog_format)更改复制格式,因为此操作不会修改运行时全局系统变量值,并且仅在服务器重新启动后生效。

不建议在存在任何临时表时在运行时切换复制格式,因为仅在使用基于语句的复制时才记录临时表,而在基于行的复制和混合复制中,它们不会被记录。

当复制正在进行时切换复制格式也可能会导致问题。每个 MySQL 服务器都可以设置自己的二进制日志格式(无论 binlog_format 是以全局还是会话范围设置)。这意味着在复制源服务器上更改日志格式不会导致副本更改其日志格式以匹配。在使用 STATEMENT 模式时,binlog_format 系统变量不会被复制。在使用 MIXEDROW 日志模式时,它会被复制,但副本会忽略它。

副本无法将以 ROW 日志格式接收的二进制日志条目转换为 STATEMENT 格式以在其自己的二进制日志中使用。因此,如果源使用 ROWMIXED 格式,则副本必须使用 ROWMIXED 格式。在复制仍在进行的情况下,将源上的二进制日志格式从 STATEMENT 更改为 ROWMIXED 到具有 STATEMENT 格式的副本可能会导致复制失败,出现错误,例如执行行事件时出错:'无法执行语句:由于语句处于行格式且 BINLOG_FORMAT = STATEMENT,因此无法写入二进制日志。' 当源仍在使用 MIXEDROW 格式时,将副本上的二进制日志格式更改为 STATEMENT 格式也会导致相同类型的复制失败。要安全更改格式,必须停止复制,并确保在源和副本上都进行相同的更改。

如果您正在使用 InnoDB 表,并且事务隔离级别为 READ COMMITTEDREAD UNCOMMITTED,则只能使用基于行的日志记录。可以可能将日志格式更改为 STATEMENT,但在运行时这样做会非常快速地导致错误,因为 InnoDB 无法再执行插入操作。

将二进制日志格式设置为 ROW 后,许多更改将以基于行的格式写入二进制日志。然而,仍然有一些更改使用基于语句的格式。例如,所有 DDL(数据定义语言)语句,如 CREATE TABLE, ALTER TABLE, 或 DROP TABLE

当使用基于行的二进制日志记录时,binlog_row_event_max_size 系统变量及其对应的启动选项 --binlog-row-event-max-size 设置了行事件的最大大小的软限制。默认值为 8192 字节,该值只能在服务器启动时更改。在可能的情况下,存储在二进制日志中的行被分组为大小不超过此设置值的事件。如果事件无法分割,则最大大小可能会超过。

--binlog-row-event-max-size 选项适用于能够进行基于行的复制的服务器。行以不超过此选项值的字节大小的块存储在二进制日志中。该值必须是 256 的倍数。默认值为 8192。

警告

当为复制使用基于语句的日志记录时,如果语句设计为数据修改是非确定性的,即由查询优化器决定,则源和副本上的数据可能会变得不同。一般来说,即使在复制之外,这也不是一个好的做法。有关此问题的详细解释,请参见 Section B.3.7, “MySQL 中的已知问题”。

原文:dev.mysql.com/doc/refman/8.0/en/binary-log-mixed.html

7.4.4.3 混合二进制日志格式

当在MIXED日志格式下运行时,服务器在以下情况下会自动从基于语句的日志切换到基于行的日志记录:

  • 当函数包含UUID()时。

  • 当更新一个或多个具有AUTO_INCREMENT列的表并调用触发器或存储函数时。与所有其他不安全语句一样,如果binlog_format = STATEMENT,则会生成警告。

    更多信息,请参见第 19.5.1.1 节,“复制和 AUTO_INCREMENT”。

  • 当视图的主体需要基于行的复制时,创建视图的语句也会使用它。例如,当创建视图的语句使用UUID()函数时。

  • 当涉及对可加载函数的调用时。

  • 当使用FOUND_ROWS()ROW_COUNT()时。(Bug #12092, Bug #30244)

  • 当使用USER()CURRENT_USER()CURRENT_USER时。(Bug #28086)

  • 当涉及的表之一是mysql数据库中的日志表时。

  • 当使用LOAD_FILE()函数时。(Bug #39701)

  • 当语句涉及一个或多个系统变量时。(Bug #31168)

    异常。 下列系统变量在会话范围(仅限)中使用时不会导致日志格式切换:

    • auto_increment_increment

    • auto_increment_offset

    • character_set_client

    • character_set_connection

    • character_set_database

    • character_set_server

    • collation_connection

    • collation_database

    • collation_server

    • foreign_key_checks

    • identity

    • last_insert_id

    • lc_time_names

    • pseudo_thread_id

    • sql_auto_is_null

    • time_zone

    • timestamp

    • unique_checks

    有关确定系统变量范围的信息,请参见 Section 7.1.9, “Using System Variables”。

    有关复制如何处理sql_mode的信息,请参见 Section 19.5.1.39, “Replication and Variables”。

在早期版本中,当使用混合二进制日志格式时,如果一条语句被记录为行,并且执行该语句的会话有任何临时表,那么所有后续语句都被视为不安全,并以行为基础的格式记录,直到该会话中使用的所有临时表都被删除。从 MySQL 8.0 开始,对临时表的操作不会以混合二进制日��格式记录,并且会话中临时表的存在不会影响每条语句使用的日志模式。

注意

如果尝试使用基于语句的日志记录执行应该使用基于行的日志记录的语句,则会生成警告。警告会显示在客户端(在SHOW WARNINGS的输出中)和通过mysqld错误日志。每次执行这样的语句时,都会向SHOW WARNINGS表中添加一个警告。但是,为了防止日志淹没,每个客户端会话中生成警告的第一条语句才会写入错误日志。

除了上述决定外,各个引擎还可以确定在更新表中的信息时使用的日志格式。各个引擎的日志记录能力可以定义如下:

  • 如果一个引擎支持基于行的日志记录,那么该引擎被称为支持行日志记录。

  • 如果一个引擎支持基于语句的日志记录,那么该引擎被称为支持语句日志记录。

给定的存储引擎可以支持任一或两种日志记录格式。以下表格列出了每个引擎支持的格式。

存储引擎 支持行日志记录 支持语句日志记录
ARCHIVE
BLACKHOLE
CSV
EXAMPLE
FEDERATED
HEAP
InnoDB 当事务隔离级别为REPEATABLE READSERIALIZABLE时为是;否则为否。
MyISAM
MERGE
NDB
存储引擎 支持行记录 支持语句记录

语句是否记录以及使用的记录模式是根据语句类型(安全、不安全或二进制注入)、二进制日志格式(STATEMENTROWMIXED)以及存储引擎的记录能力(支持语句、支持行、两者都支持或两者都不支持)来确定的。(二进制注入指的是必须使用ROW格式记录的更改的记录。)

语句可能会被记录,有或没有警告;失败的语句不会被记录,但会在日志中生成错误。这在以下决策表中显示。类型binlog_formatSLCRLC列概述了条件,错误/警告记录为列代表相应的操作。SLC代表“支持语句记录”,RLC代表“支持行记录”。

类型 binlog_format SLC RLC 错误/警告 记录为
* * 错误:无法执行语句:由于至少有一个既不支持行也不支持语句的引擎参与其中,因此无法进行二进制日志记录。 -
安全 STATEMENT - STATEMENT
安全 MIXED - STATEMENT
安全 ROW 错误:无法执行语句:由于BINLOG_FORMAT = ROW且至少有一张表使用不支持基于行的日志记录的存储引擎,因此无法进行二进制日志记录。 -
不安全 STATEMENT 警告:由于BINLOG_FORMAT = STATEMENT,不安全语句以语句格式记录到二进制日志中 STATEMENT
不安全 MIXED 错误:无法执行语句:当存储引擎限制为基于语句的日志记录时,即使BINLOG_FORMAT = MIXED,也无法对不安全语句进行二进制日志记录。 -
不安全 ROW 错误:无法执行语句:由于BINLOG_FORMAT = ROW且至少有一张表使用不支持基于行的日志记录的存储引擎,因此无法进行二进制日志记录。 -
行注入 STATEMENT 错误:无法执行行注入:由于至少有一张表使用不支持基于行的日志记录的存储引擎,因此无法进行二进制日志记录。 -
行注入 MIXED 错误:无法执行行注入:由于至少有一张表使用不支持基于行的日志记录的存储引擎,因此无法进行二进制日志记录。 -
行注入 ROW 错误:无法执行行注入:由于至少有一张表使用不支持基于行的日志记录的存储引擎,因此无法进行二进制日志记录。 -
安全 STATEMENT 错误:无法执行语句:由于BINLOG_FORMAT = STATEMENT且至少有一张表使用不支持基于语句的日志记录的存储引擎,因此无法进行二进制日志记录。 -
安全 MIXED - ROW
安全 ROW - ROW
不安全 STATEMENT 错误:无法执行语句:由于 BINLOG_FORMAT = STATEMENT,并且至少有一个表使用不支持基于语句的日志记录的存储引擎,因此无法进行二进制日志记录。 -
不安全 MIXED - ROW
不安全 ROW - ROW
行注入 STATEMENT 错误:无法执行行注入:由于 BINLOG_FORMAT = STATEMENT,因此无法进行二进制日志记录。 -
行注入 MIXED - ROW
行注入 ROW - ROW
安全 STATEMENT - STATEMENT
安全 MIXED - STATEMENT
安全 ROW - ROW
不安全 STATEMENT 警告:由于 BINLOG_FORMAT = STATEMENT,不安全的语句以语句格式记录到二进制日志中。 STATEMENT
不安全 MIXED - ROW
不安全 ROW - ROW
行注入 STATEMENT 错误:无法执行行注入:由于 BINLOG_FORMAT = STATEMENT,因此无法进行二进制日志记录。 -
行注入 MIXED - ROW
行注入 ROW - ROW
类型 binlog_format SLC RLC 错误 / 警告 记录为

当决定产生警告时,会产生一个标准的 MySQL 警告(可以使用 SHOW WARNINGS 查看)。这些信息也会被写入到 mysqld 错误日志中。为了防止日志被淹没,每个客户端连接的每个错误实例只记录一个错误。日志消息包括尝试执行的 SQL 语句。

如果一个复制实例设置了 log_error_verbosity 以显示警告,那么复制实例会将消息打印到错误日志中,以提供有关其状态的信息,例如开始作业的二进制日志和中继日志坐标,切换到另一个中继日志时,重新连接后的情况,不适合基于语句的日志记录的语句等等。

原文:dev.mysql.com/doc/refman/8.0/en/binary-log-mysql-database.html

7.4.4.4 更改mysql数据库表的日志格式

mysql数据库中授权表的内容可以直接(例如,使用INSERTDELETE)或间接(例如,使用GRANTCREATE USER)进行修改。影响mysql数据库表的语句将根据以下规则写入二进制日志:

  • 直接更改mysql数据库表中数据的数据操作语句将根据binlog_format系统变量的设置进行记录。这包括诸如INSERTUPDATEDELETEREPLACEDOLOAD DATASELECTTRUNCATE TABLE等语句。

  • 间接更改mysql数据库的语句将作为语句记录,不受binlog_format值的影响。这包括诸如GRANTREVOKESET PASSWORDRENAME USERCREATE(除CREATE TABLE ... SELECT之外的所有形式)、ALTER(所有形式)和DROP(所有形式)等语句。

CREATE TABLE ... SELECT是数据定义和数据操作的组合。CREATE TABLE部分使用语句格式记录,而SELECT部分根据binlog_format的值进行记录。

原文:dev.mysql.com/doc/refman/8.0/en/binary-log-transaction-compression.html

7.4.4.5 二进制日志事务压缩

从 MySQL 8.0.20 开始,您可以在 MySQL 服务器实例上启用二进制日志事务压缩。启用二进制日志事务压缩后,事务负载将使用 zstd 算法进行压缩,然后作为单个事件(Transaction_payload_event)写入服务器的二进制日志文件。

在将压缩的事务负载发送到副本、其他组复制组成员或客户端(如mysqlbinlog)时,压缩的事务负载保持压缩状态。接收线程不会对其进行解压缩,并且仍以压缩状态写入中继日志。因此,二进制日志事务压缩在事务发起者和接收者(以及它们的备份)上节省了存储空间,并在服务器实例之间发送事务时节省了网络带宽。

当需要检查其中包含的各个事件时,压缩的事务负载将被解压缩。例如,Transaction_payload_event由应用程序线程解压缩,以便在接收端应用其中包含的事件。在恢复期间,通过mysqlbinlog重放事务时,以及通过SHOW BINLOG EVENTSSHOW RELAYLOG EVENTS语句进行解压缩。

你可以使用binlog_transaction_compression系统变量在 MySQL 服务器实例上启用二进制日志事务压缩,该变量默认为OFF。您还可以使用binlog_transaction_compression_level_zstd系统变量设置用于压缩的 zstd 算法的级别。该值确定了压缩的努力程度,从 1(最低努力)到 22(最高努力)。随着压缩级别的增加,压缩比例增加,从而减少了事务负载所需的存储空间和网络带宽。然而,数据压缩所需的努力也增加,消耗了源服务器上的时间、CPU 和内存资源。压缩努力的增加与压缩比例的增加之间没有线性关系。

注意

NDB 8.0.31 之前:可以在 NDB Cluster 中启用二进制日志事务压缩,但仅在使用--binlog-transaction-compression 选项(可能还包括--binlog-transaction-compression-level-zstd)启动服务器时;在运行时更改binlog_transaction_compressionbinlog_transaction_compression_level_zstd系统变量的值对NDB表的日志记录没有影响。

NDB 8.0.31 及更高版本:您可以在运行时使用该版本引入的ndb_log_transaction_compression系统变量启用对使用NDB存储引擎的表的压缩事务的二进制日志记录,并使用ndb_log_transaction_compression_level_zstd控制压缩级别。在命令行或my.cnf文件中使用--binlog-transaction-compression启动mysqld会自动启用ndb_log_transaction_compression,并忽略--ndb-log-transaction-compression选项的任何设置;要仅为NDB存储引擎禁用二进制日志事务压缩,需在启动mysqld后在客户端会话中设置ndb_log_transaction_compression=OFF

以下类型的事件不包括在二进制日志事务压缩中,因此始终以未压缩形式写入二进制日志:

  • 与事务的 GTID 相关的事件(包括匿名 GTID 事件)。

  • 其他类型的控制事件,例如视图更改事件和心跳事件。

  • 事故事件和包含它们的任何事务的全部内容。

  • 非事务事件和包含它们的任何事务的全部内容。涉及非事务性和事务性存储引擎混合的事务不会对其有效负载进行压缩。

  • 使用基于语句的二进制日志记录的事件。二进制日志事务压缩仅适用于基于行的二进制日志格式。

可以在包含压缩事务的二进制日志文件上使用二进制日志加密。

7.4.4.5.1 启用二进制日志事务压缩时的行为

具有压缩有效负载的事务可以像任何其他事务一样回滚,并且也可以通过常规过滤选项在副本中过滤掉。二进制日志事务压缩可以应用于 XA 事务。

当启用二进制日志事务压缩时,服务器的max_allowed_packetreplica_max_allowed_packetslave_max_allowed_packet限制仍然适用,并且是基于Transaction_payload_event的压缩大小加上事件头使用的字节进行计量。

重要

压缩事务负载作为一个单独的数据包发送,而不是在未使用二进制日志事务压缩时,将事务的每个事件作为单独的数据包发送。如果您的复制拓扑处理大型事务,请注意,当使用二进制日志事务压缩时,一个在未使用二进制日志事务压缩时可以成功复制的大型事务,可能由于其大小而停止复制。

对于多线程工作者,每个事务(包括其 GTID 事件和Transaction_payload_event)被分配给一个工作线程。工作线程解压缩事务负载,并逐个应用其中的各个事件。如果在Transaction_payload_event中应用任何事件时发现错误,则将报告整个事务失败给协调者。当replica_parallel_typeslave_parallel_type设置为DATABASE时,事务调度之前将受事务影响的所有数据库映射。与未压缩事务相比,使用二进制日志事务压缩与DATABASE策略可以减少并行性,后者将每个事件映射并调度。

对于半同步复制(参见 Section 19.4.10, “Semisynchronous Replication”),当完整的Transaction_payload_event被接收时,副本确认事务。

当启用二进制日志校验和(这是默认设置)时,复制源服务器不会为压缩事务负载中的单个事件写入校验和。相反,为完整的Transaction_payload_event写入校验和,并为未压缩的任何事件写入单独的校验和,例如与 GTID 相关的事件。

对于SHOW BINLOG EVENTSSHOW RELAYLOG EVENTS语句,Transaction_payload_event首先作为一个单元打印,然后解压缩并打印其中的每个事件。

对于引用事件结束位置的操作,比如START REPLICA(或在 MySQL 8.0.22 之前的版本中,START SLAVE)带有UNTIL子句,SOURCE_POS_WAIT()MASTER_POS_WAIT(),以及sql_replica_skip_countersql_slave_skip_counter,您必须指定压缩事务有效载荷(Transaction_payload_event)的结束位置。当使用sql_replica_skip_countersql_slave_skip_counter跳过事件时,压缩的事务有效载荷被计为单个计数器值,因此其中的所有事件都作为一个单元被跳过。

7.4.4.5.2 组合压缩和未压缩的事务有效载荷

支持二进制日志事务压缩的 MySQL 服务器版本可以处理压缩和未压缩的事务有效载荷的混合。

  • 与二进制日志事务压缩相关的系统变量不需要在所有组复制组成员上设置相同,并且不会从源复制到副本在复制拓扑中。您可以决定是否对具有二进制日志的每个 MySQL 服务器实例启用二进制日志事务压缩。

  • 如果启用了事务压缩,然后在服务器上禁用了压缩,则未来在该服务器上发起的事务不会应用压缩,但已经压缩的事务有效载荷仍然可以被处理和显示。

  • 如果通过设置binlog_transaction_compression的会话值为个别会话指定了事务压缩,则二进制日志可以包含压缩和未压缩的事务有效载荷的混合。

当复制拓扑中的源和其副本都启用了二进制日志事务压缩时,副本接收压缩的事务有效载荷并将其压缩写入其中继日志。它解压事务有效载荷以应用事务,然后在应用后再次压缩以写入其二进制日志。任何下游副本都会接收压缩的事务有效载荷。

当复制拓扑中的源具有启用二进制日志事务压缩,但其副本没有启用时,副本接收压缩的事务有效载荷并将其压缩写入其中继日志。它解压事务有效载荷以应用事务,然后将其未压缩写入其自己的二进制日志(如果有)。任何下游副本接收未压缩的事务有效载荷。

当复制拓扑中的源没有启用二进制日志事务压缩,但其副本启用时,如果副本具有二进制日志,则在应用事务后压缩事务有效载荷,并将压缩的事务有效载荷写入其二进制日志。任何下游副本接收压缩的事务有效载荷。

当 MySQL 服务器实例没有二进制日志时,如果它是来自 MySQL 8.0.20 的版本,则无论其对binlog_transaction_compression的值如何,它都可以接收、处理和显示压缩的事务有效载荷。这些服务器实例接收的压缩事务有效载荷以其压缩状态写入中继日志,因此它们间接受益于复制拓扑中其他服务器执行的压缩。

MySQL 8.0.20 之前的版本的副本无法从启用二进制日志事务压缩的源进行复制。MySQL 8.0.20 或更高版本的副本可以从不支持二进制日志事务压缩的早期版本的源进行复制,并在将其写入自己的二进制日志时对从该源接收的事务进行自己的压缩。

7.4.4.5.3 监视二进制日志事务压缩

您可以使用性能模式表binary_log_transaction_compression_stats监视二进制日志事务压缩的影响。统计数据包括监控期间的数据压缩比率,您还可以查看压缩对服务器上最后一个事务的影响。您可以通过截断表来重置统计信息。二进制日志和中继日志的统计数据是分开的,因此您可以看到每种日志类型的压缩影响。MySQL 服务器实例必须具有二进制日志才能生成这些统计信息。

Performance Schema 表 events_stages_current 显示事务何时处于解压缩或压缩阶段,以及显示该阶段的进度。压缩是由处理事务的工作线程在事务提交之前执行的,前提是在最终捕获缓存中没有排除事务的事件(例如,事故事件)。当需要解压缩时,会逐个事件从有效载荷中进行解压缩。

mysqlbinlog 使用 --verbose 选项时,会包含注释,说明压缩事务有效载荷的压缩大小和未压缩大小,以及所使用的压缩算法。

您可以在复制连接的协议级别启用连接压缩,使用 CHANGE REPLICATION SOURCE TO 语句(从 MySQL 8.0.23 开始)或 CHANGE MASTER TO 语句(在 MySQL 8.0.23 之前),或 replica_compressed_protocolslave_compressed_protocol 系统变量的 SOURCE_COMPRESSION_ALGORITHMS | MASTER_COMPRESSION_ALGORITHMSSOURCE_ZSTD_COMPRESSION_LEVEL | MASTER_ZSTD_COMPRESSION_LEVEL 选项。如果在启用连接压缩的系统中启用了二进制日志事务压缩,连接压缩的影响会减小,因为可能很少有机会进一步压缩已经压缩的事务有效载荷。但是,连接压缩仍然可以操作未压缩的事件和消息头。如果您需要节省存储空间以及网络带宽,可以在启用连接压缩的情况下启用二进制日志事务压缩。有关复制连接的连接压缩的更多信息,请参见 Section 6.2.8, “Connection Compression Control”。

对于组复制,当消息超过group_replication_compression_threshold系统变量设置的阈值时,默认启用压缩。您还可以通过使用group_replication_recovery_compression_algorithmsgroup_replication_recovery_zstd_compression_level系统变量,为从捐赠者的二进制日志进行状态传输的消息配置压缩。如果在配置了这些内容的系统中启用了二进制日志事务压缩,组复制的消息压缩仍然可以在未压缩事件和消息头上运行,但其影响会减小。有关组复制消息压缩的更多信息,请参见第 20.7.4 节,“消息压缩”。

7.4.5 慢查询日志

原文:dev.mysql.com/doc/refman/8.0/en/slow-query-log.html

慢查询日志包含执行时间超过long_query_time秒且需要至少检查min_examined_row_limit行的 SQL 语句。慢查询日志可用于查找执行时间长且需要优化的查询。然而,检查长时间的慢查询日志可能是一项耗时的任务。为了简化这个过程,可以使用mysqldumpslow命令处理慢查询日志文件并总结其内容。参见第 6.6.10 节,“mysqldumpslow — Summarize Slow Query Log Files”。

获取初始锁的时间不计入执行时间。mysqld在执行完语句并释放所有锁之后将其写入慢查询日志,因此日志顺序可能与执行顺序不同。

  • 慢查询日志参数

  • 慢查询日志内容

慢查询日志参数

long_query_time的最小和默认值分别为 0 和 10。该值可以以微秒为分辨率进行指定。

默认情况下,不会记录管理语句,也不会记录未使用索引进行查找的查询。可以通过log_slow_admin_statementslog_queries_not_using_indexes进行更改,稍后会详细描述。

默认情况下,慢查询日志是禁用的。要明确指定初始慢查询日志状态,请使用--slow_query_log[={0|1}]。没有参数或参数为 1 时,--slow_query_log启用日志。参数为 0 时,此选项禁用日志。要指定日志文件名,请使用--slow_query_log_file=*file_name*。要指定日志目标,请使用log_output系统变量(如第 7.4.1 节,“选择通用查询日志和慢查询日志输出目标”中所述)。

注意

如果指定TABLE日志目的地,请参阅 Log Tables and “Too many open files” Errors。

如果未为慢查询日志文件指定名称,则默认名称为*host_name*-slow.log。服务器将在数据目录中创建该文件,除非给定绝对路径名以指定不同的目录。

要在运行时禁用或启用慢查询日志,或更改日志文件名,请使用全局slow_query_logslow_query_log_file系统变量。将slow_query_log设置为 0 以禁用日志,设置为 1 以启用日志。将slow_query_log_file设置为指定日志文件的名称。如果已经打开了日志文件,则关闭该文件并打开新文件。

如果使用--log-short-format选项,服务器将向慢查询日志写入较少的信息。

要在慢查询日志中包含慢管理语句,请启用log_slow_admin_statements系统变量。管理语句包括ALTER TABLEANALYZE TABLECHECK TABLECREATE INDEXDROP INDEXOPTIMIZE TABLEREPAIR TABLE

要在慢查询日志中写入不使用索引进行行查找的查询语句,请启用log_queries_not_using_indexes系统变量。(即使启用了该变量,由于表少于两行,服务器也不会记录不受索引影响的查询。)

当记录不使用索引的查询时,慢查询日志可能会迅速增长。可以通过设置log_throttle_queries_not_using_indexes系统变量对这些查询设置速率限制。默认情况下,此变量为 0,表示没有限制。正值对不使用索引的查询的日志记录施加每分钟限制。第一个这样的查询打开一个 60 秒的窗口,在此窗口内,服务器记录达到给定限制的查询,然后抑制额外的查询。如果在窗口结束时有被抑制的查询,服务器将记录一个摘要,指示有多少个查询以及在其中花费的总时间。当服务器记录下一个不使用索引的查询时,下一个 60 秒的窗口开始。

服务器按照以下顺序使用控制参数来确定是否将查询写入慢查询日志:

  1. 查询必须不是管理语句,或者必须启用log_slow_admin_statements

  2. 查询必须至少花费long_query_time秒,或者必须启用log_queries_not_using_indexes,并且查询没有使用索引进行行查找。

  3. 查询必须至少检查了min_examined_row_limit行。

  4. 查询必须根据log_throttle_queries_not_using_indexes设置而不被抑制。

log_timestamps系统变量控制写入慢查询日志文件(以及一般查询日志文件和错误日志)中消息的时间戳的时区。它不影响写入日志表的一般查询日志和慢查询日志消息的时区,但是可以通过CONVERT_TZ()或设置会话time_zone系统变量,将从这些表中检索的行从本地系统时区转换为任何所需的时区。

默认情况下,副本不会将复制的查询写入慢查询日志。要更改此设置,请启用系统变量log_slow_replica_statements(从 MySQL 8.0.26 开始)或log_slow_slave_statements(在 MySQL 8.0.26 之前)。请注意,如果使用基于行的复制(binlog_format=ROW),这些系统变量不起作用。仅当以语句格式在二进制日志中记录时,即当设置了binlog_format=STATEMENT时,或者当设置了binlog_format=MIXED并且语句以语句格式记录时,才会将查询添加到副本的慢查询日志中。即使启用了log_slow_replica_statementslog_slow_slave_statements,当以行格式记录慢查询时,即使设置了binlog_format=MIXED,或者当设置了binlog_format=ROW,也不会将其添加到副本的慢查询日志中。

慢查询日志内容

当慢查询日志被启用时,服务器会将输出写入由log_output系统变量指定的任何目的地。如果启用了日志,服务器会打开日志文件并将启动消息写入其中。然而,除非选择了FILE日志目的地,否则不会进一步将查询记录到文件中。如果目的地是NONE,即使启用了慢查询日志,服务器也不会写入任何查询。如果未选择FILE作为输出目的地,则设置日志文件名不会影响日志记录。

如果启用了慢查询日志并选择了FILE作为输出目的地,则写入日志的每个语句前面都会有一行以#字符开头并具有以下字段(所有字段都在一行上):

  • Query_time: *持续时间*

    语句执行时间(秒)。

  • Lock_time: *持续时间*

    获取锁所需的时间(秒)。

  • Rows_sent: *N*

    发送到客户端的行数。

  • Rows_examined:

    服务器层检查的行数(不包括存储引擎内部处理的任何处理)。

启用log_slow_extra系统变量(MySQL 8.0.14 起可用)会导致服务器将以下额外字段写入FILE输出,除了刚刚列出的字段外(TABLE`输出不受影响)。一些字段描述涉及状态变量名称。有关更多信息,请参考状态变量描述。但是,在慢查询日志中,计数器是每个语句的值,而不是每个会话的累积值。

  • Thread_id: *ID*

    语句线程标识符。

  • Errno: *错误编号*

    语句错误编号,如果没有错误则为 0。

  • Killed: *N*

    如果语句被终止,表示为什么的错误编号,如果语句正常终止则为 0。

  • Bytes_received: *N*

    Bytes_received语句的值。

  • Bytes_sent: *N*

    Bytes_sent语句的值。

  • Read_first: *N*

    Handler_read_first语句的值。

  • Read_last: *N*

    Handler_read_last语句的值。

  • Read_key: *N*

    Handler_read_key语句的值。

  • Read_next: *N*

    Handler_read_next语句的值。

  • Read_prev: *N*

    Handler_read_prev语句的值。

  • Read_rnd: *N*

    Handler_read_rnd语句的值。

  • Read_rnd_next: *N*

    Handler_read_rnd_next语句的值。

  • Sort_merge_passes: *N*

    Sort_merge_passes语句的值。

  • Sort_range_count: *N*

    Sort_range语句的值。

  • Sort_rows: *N*

    Sort_rows语句的值。

  • Sort_scan_count: *N*

    Sort_scan语句的值。

  • Created_tmp_disk_tables: *N*

    Created_tmp_disk_tables语句的值。

  • Created_tmp_tables: *N*

    Created_tmp_tables语句的值。

  • Start: *时间戳*

    语句执行开始时间。

  • End: *时间戳*

    语句执行结束时间。

给定的慢查询日志文件可能包含启用log_slow_extra后添加了额外字段的行和没有额外字段的行。日志文件分析器可以通过字段计数确定一行是否包含额外字段。

每条写入慢查询日志文件的语句前面都有一个包含时间戳的SET语句。从 MySQL 8.0.14 开始,时间戳表示慢语句开始执行的时间。在 8.0.14 之前,时间戳表示慢语句被记录的时间(这发生在语句执行完成后)。

写入慢查询日志的语句中的密码会被服务器重写,以避免明文出现。参见第 8.1.2.3 节,“密码和日志记录”。

从 MySQL 8.0.29 开始,由于语法错误等原因无法解析的语句不会被写入慢查询日志。

7.4.6 服务器日志维护

原文:dev.mysql.com/doc/refman/8.0/en/log-file-maintenance.html

如 第 7.4 节,“MySQL 服务器日志” 中所述,MySQL 服务器可以创建几个不同的日志文件,帮助您查看正在发生的活动。然而,您必须定期清理这些文件,以确保日志不会占用太多磁盘空间。

当使用启用日志记录的 MySQL 时,您可能希望定期备份并删除旧的日志文件,并告诉 MySQL 开始记录到新文件中。参见 第 9.2 节,“数据库备份方法”。

在 Linux(Red Hat)安装中,您可以使用 mysql-log-rotate 脚本进行日志维护。如果您从 RPM 发行版安装了 MySQL,则此脚本应该已自动安装。如果您正在使用二进制日志进行复制,请小心使用此脚本。在确定所有副本都已处理其内容之前,不应删除二进制日志。

在其他系统上,您必须自己安装一个短脚本,然后从 cron(或其等效物)启动以处理日志文件。

二进制日志文件在服务器的二进制日志过期期间后会自动删除。文件的删除可以在启动时和二进制日志刷新时进行。默认的二进制日志过期期限为 30 天。要指定替代的过期期限,请使用 binlog_expire_logs_seconds 系统变量。如果您正在使用复制,您应该指定一个不低于副本可能滞后源的最长时间的过期期限。要按需删除二进制日志,请使用 PURGE BINARY LOGS 语句(参见 第 15.4.1.1 节,“PURGE BINARY LOGS 语句”)。

要强制 MySQL 开始使用新的日志文件,需要刷新日志。执行FLUSH LOGS语句或mysqladmin flush-logsmysqladmin refreshmysqldump --flush-logsmysqldump --master-data命令时会发生日志刷新。参见第 15.7.8.3 节,“FLUSH 语句”、第 6.5.2 节,“mysqladmin — A MySQL Server Administration Program”和第 6.5.4 节,“mysqldump — A Database Backup Program”。此外,当当前二进制日志文件大小达到max_binlog_size系统变量的值时,服务器会自动刷新二进制日志。

FLUSH LOGS支持可选修饰符,以启用对单个日志的选择性刷新(例如,FLUSH BINARY LOGS)。参见第 15.7.8.3 节,“FLUSH 语句”。

日志刷新操作具有以下效果:

  • 如果启用了二进制日志记录,服务器会关闭当前的二进制日志文件,并打开下一个序列号的新日志文件。

  • 如果启用了一般查询日志或慢查询日志到日志文件的记录,服务器会关闭并重新打开日志文件。

  • 如果服务器是使用--log-error选项启动的,以将错误日志写入文件,服务器会关闭并重新打开日志文件。

执行刷新日志语句或命令需要使用具有RELOAD权限的帐户连接到服务器。在 Unix 和类 Unix 系统上,刷新日志的另一种方法是向服务器发送信号,可以由root或拥有服务器进程的帐户执行。(参见第 6.10 节,“MySQL 中的 Unix 信号处理”。)信号使得可以在不连接到服务器的情况下执行日志刷新:

  • SIGHUP信号会刷新所有日志。然而,SIGHUP除了日志刷新之外还有其他可能不希望的附加效果。

  • 截至 MySQL 8.0.19 版本,SIGUSR1会导致服务器刷新错误日志、一般查询日志和慢查询日志。如果只想刷新这些日志,SIGUSR1可以作为一个更“轻量级”的信号,不会产生与日志无关的SIGHUP效果。

如前所述,刷新二进制日志会创建一个新的二进制日志文件,而刷新一般查询日志、慢查询日志或错误日志只是关闭并重新打开日志文件。对于后者的日志,在 Unix 上,要在刷新之前重命名当前日志文件以创建一个新的日志文件。在刷新时,服务器会使用原始名称打开新的日志文件。例如,如果一般查询日志、慢查询日志和错误日志文件分别命名为mysql.logmysql-slow.logerr.log,您可以在命令行中使用一系列命令如下:

cd *mysql-data-directory*
mv mysql.log mysql.log.old
mv mysql-slow.log mysql-slow.log.old
mv err.log err.log.old
mysqladmin flush-logs

在 Windows 上,使用rename而不是mv

此时,您可以备份mysql.log.oldmysql-slow.log.olderr.log.old,然后将它们从磁盘中删除。

要在运行时重命名一般查询日志或慢查询日志,首先连接到服务器并禁用日志:

SET GLOBAL general_log = 'OFF';
SET GLOBAL slow_query_log = 'OFF';

禁用日志后,可以在外部重命名日志文件(例如,从命令行)。然后再次启用日志:

SET GLOBAL general_log = 'ON';
SET GLOBAL slow_query_log = 'ON';

这种方法适用于任何平台,不需要重新启动服务器。

注意

在您在外部重命名文件后,服务器重新创建给定日志文件时,文件位置必须可被服务器写入。这并非总是如此。例如,在 Linux 上,服务器可能将错误日志写入为/var/log/mysqld.log,其中/var/logroot拥有且不可写入mysqld。在这种情况下,日志刷新操作无法创建新的日志文件。

处理这种情况,您必须在重命名原始日志文件后手动创建具有适当所有权的新日志文件。例如,以root身份执行以下命令:

mv /var/log/mysqld.log /var/log/mysqld.log.old
install -omysql -gmysql -m0644 /dev/null /var/log/mysqld.log

7.5 MySQL 组件

译文:dev.mysql.com/doc/refman/8.0/en/components.html

7.5.1 安装和卸载组件

7.5.2 获取组件信息

7.5.3 错误日志组件

7.5.4 查询属性组件

7.5.5 调度器组件

MySQL Server 包括一个基于组件的基础架构,用于扩展服务器功能。组件提供对服务器和其他组件可用的服务。(在服务使用方面,服务器是一个组件,与其他组件相等。)组件之间仅通过它们提供的服务进行交互。

MySQL 发行版包含几个实现服务器扩展的组件:

  • 用于配置错误日志的组件。参见第 7.4.2 节,“错误日志”和第 7.5.3 节,“错误日志组件”。

  • 一个用于检查密码的组件。参见第 8.4.3 节,“密码验证组件”。

  • Keyring 组件为敏感信息提供安全存储。参见第 8.4.4 节,“MySQL Keyring”。

  • 一个使应用程序能够向审计日志添加自己的消息事件的组件。参见第 8.4.6 节,“审计消息组件”。

  • 实现用于访问查询属性的可加载函数的组件。参见第 11.6 节,“查询属性”。

  • 用于调度主动执行任务的组件。参见第 7.5.5 节,“调度器组件”。

当组件安装时,由组件实现的系统和状态变量将被公开,并具有以组件特定前缀开头的名称。例如,log_filter_dragnet错误日志过滤组件实现了一个名为log_error_filter_rules的系统变量,其完整名称为dragnet.log_error_filter_rules。要引用此变量,请使用完整名称。

以下部分描述了如何安装和卸载组件,以及在运行时如何确定已安装的组件并获取有关它们的信息。

有关组件的内部实现信息,请参阅 MySQL Server Doxygen 文档,网址为dev.mysql.com/doc/index-other.html。例如,如果您打算编写自己的组件,了解这些信息对于理解组件的工作原理非常重要。

7.5.1 安装和卸载组件

译文:dev.mysql.com/doc/refman/8.0/en/component-loading.html

组件必须在服务器中加载后才能使用。MySQL 支持在运行时手动加载组件和在服务器启动期间自动加载组件。

在加载组件时,可以按照 Section 7.5.2, “Obtaining Component Information”中描述的方式获取有关组件的信息。

INSTALL COMPONENTUNINSTALL COMPONENT SQL 语句可实现组件的加载和卸载。例如:

INSTALL COMPONENT 'file://component_validate_password';
UNINSTALL COMPONENT 'file://component_validate_password';

加载程序服务处理组件的加载和卸载,并在mysql.component系统表中注册已加载的组件。

组件操作的 SQL 语句会影响服务器操作和mysql.component系统表,具体如下:

  • INSTALL COMPONENT会将组件加载到服务器中。组件会立即生效。加载程序服务还会在mysql.component系统表中注册已加载的组件。对于后续的服务器重新启动,加载程序服务会在启动序列中加载mysql.component中列出的任何组件。即使服务器使用--skip-grant-tables选项启动,也会发生这种情况。可选的SET子句允许在安装组件时设置组件系统变量的值。

  • UNINSTALL COMPONENT会停用组件并从服务器中卸载它们。加载程序服务还会从mysql.component系统表中注销这些组件,以便服务器在后续重新启动时不再在启动序列中加载它们。

与服务器插件的对应INSTALL PLUGIN语句相比,组件的INSTALL COMPONENT语句具有显著优势,不需要知道任何特定于平台的文件名后缀来命名组件。这意味着给定的INSTALL COMPONENT语句可以在各个平台上统一执行。

安装组件时,可能还会自动安装相关的可加载函数。如果是这样,卸载组件时也会自动卸载这些函数。

7.5.2 获取组件信息

原文:dev.mysql.com/doc/refman/8.0/en/obtaining-component-information.html

mysql.component 系统表包含有关当前加载的组件的信息,并显示哪些组件已使用INSTALL COMPONENT进行注册。从表中选择显示已安装的组件。例如:

mysql> SELECT * FROM mysql.component;
+--------------+--------------------+------------------------------------+
| component_id | component_group_id | component_urn                      |
+--------------+--------------------+------------------------------------+
|            1 |                  1 | file://component_validate_password |
|            2 |                  2 | file://component_log_sink_json     |
+--------------+--------------------+------------------------------------+

component_idcomponent_group_id 值仅供内部使用。component_urn 是在INSTALL COMPONENTUNINSTALL COMPONENT语句中用于加载和卸载组件的 URN。

7.5.3 错误日志组件

原文:dev.mysql.com/doc/refman/8.0/en/error-log-components.html

本节描述了各个错误日志组件的特性。有关配置错误日志的一般信息,请参见 Section 7.4.2, “The Error Log”。

日志组件可以是过滤器或接收器:

  • 过滤器处理日志事件,以添加、删除或修改事件字段,或完全删除事件。处理后的事件传递到已启用组件列表中的下一个日志组件。

  • 接收器是日志事件的目的地(写入器)。通常,接收器将日志事件处理成具有特定格式的日志消息,并将这些消息写入其关联的输出,如文件或系统日志。接收器还可以写入到性能模式error_log表;参见 Section 29.12.21.2, “The error_log Table”。事件未经修改地传递到已启用组件列表中的下一个日志组件(即,尽管接收器格式化事件以生成输出消息,但它不会在内部传递给下一个组件时修改事件)。

log_error_services系统变量值列出了已启用的日志组件。未在列表中命名的组件已禁用。从 MySQL 8.0.30 开始,如果未加载错误日志组件,则log_error_services也会隐式加载它们。有关更多信息,请参见 Section 7.4.2.1, “Error Log Configuration”。

以下各节描述了按组件类型分组的各个日志组件:

  • 过滤器错误日志组件

  • 接收器错误日志组件

组件描述包括以下类型的信息:

  • 组件名称和预期目的。

  • 组件是内置的还是必须加载。对于可加载组件,描述指定了在使用INSTALL COMPONENTUNINSTALL COMPONENT语句显式加载或卸载组件时要使用的 URN。隐式加载错误日志组件只需要组件名称。有关更多信息,请参见 Section 7.4.2.1, “Error Log Configuration”。

  • 组件是否可以在log_error_services值中列出多次。

  • 对于一个接收组件,组件写入输出的目的地。

  • 对于一个接收组件,它是否支持与性能模式error_log表的接口。

过滤错误日志组件

错误日志过滤组件实现对错误日志事件的过滤。如果没有启用过滤组件,则不会进行过滤。

任何启用的过滤组件仅影响稍后在log_error_services值中列出的组件的日志事件。特别是,对于在log_error_services中较早列出的任何日志接收组件,不会发生任何日志事件过滤。

log_filter_internal 组件
  • 目的:实现基于日志事件优先级和错误代码的过滤,结合log_error_verbositylog_error_suppression_list系统变量。参见第 7.4.2.5 节“基于优先级的错误日志过滤(log_filter_internal)”。

  • URN:此组件是内置的,无需加载。

  • 允许多次使用:否。

如果log_filter_internal被禁用,log_error_verbositylog_error_suppression_list将不起作用。

log_filter_dragnet 组件
  • 目的:实现根据dragnet.log_error_filter_rules系统变量设置定义的规则进行过滤。参见第 7.4.2.6 节“基于规则的错误日志过滤(log_filter_dragnet)”。

  • URN:file://component_log_filter_dragnet

  • 允许多次使用:否。

接收错误日志组件

错误日志接收组件是实现错误日志输出的写入器。如果没有启用接收组件,则不会发生日志输出。

一些接收组件描述涉及默认的错误日志目的地。这是控制台或文件,并由log_error系统变量的值表示,如第 7.4.2.2 节“默认错误日志目的地配置”中所述确定。

log_sink_internal 组件
  • 目的:实现传统的错误日志消息输出格式。

  • URN:此组件是内置的,无需加载。

  • 允许多次使用:否。

  • 输出目的地:写入默认的错误日志目的地。

  • 性能模式支持:写入error_log表。提供一个解析器用于读取以前服务器实例创建的错误日志文件。

JSON 格式日志汇聚组件
  • 目的:实现 JSON 格式的错误日志记录。参见第 7.4.2.7 节,“JSON 格式错误日志记录”。

  • URN:file://component_log_sink_json

  • 多次使用允许:允许。

  • 输出目的地:该汇聚根据默认错误日志目的地确定其输出目的地,该目的地由log_error系统变量给出:

    • 如果log_error指定了一个文件,汇聚将基于该文件名进行输出文件命名,加上一个以.*NN*.json为后缀的编号,其中NN从 00 开始。例如,如果log_errorfile_name,那么在log_error_services值中连续命名的log_sink_json将写入*file_name*.00.json*file_name*.01.json等。

    • 如果log_errorstderr,则汇聚将写入控制台。如果在log_error_services值中多次命名log_sink_json,它们都将写入控制台,这可能没有用处。

  • 性能模式支持:写入error_log表。提供一个解析器用于读取以前服务器实例创建的错误日志文件。

日志汇聚系统事件日志组件
  • 目的:实现将错误日志记录到系统日志。这是 Windows 上的事件日志,以及 Unix 和类 Unix 系统上的syslog。参见第 7.4.2.8 节,“将错误日志记录到系统日志”。

  • URN:file://component_log_sink_syseventlog

  • 多次使用允许:不允许。

  • 输出目的地:写入系统日志。不使用默认错误日志目的地。

  • 性能模式支持:不写入error_log表。不提供解析器用于读取以前服务器实例创建的错误日志文件。

日志汇聚测试组件
  • 目的:用于编写测试用例的内部使用,不用于生产环境。

  • URN:file://component_log_sink_test

由于log_sink_test是用于内部使用,因此未指定诸如是否允许多次使用和输出目的地等汇聚属性。因此,其行为可能随时发生变化。

7.5.4 查询属性组件

原文:dev.mysql.com/doc/refman/8.0/en/query-attribute-components.html

从 MySQL 8.0.23 开始,一个组件服务提供了对查询属性的访问(参见第 11.6 节,“查询属性”)。query_attributes组件使用此服务在 SQL 语句中提供对查询属性的访问。

  • 目的:实现mysql_query_attribute_string()函数,该函数接受属性名称参数并将属性值作为字符串返回,如果属性不存在则返回NULL

  • URN:file://component_query_attributes

希望使用query_attributes所使用的相同查询属性组件服务的开发人员应查阅 MySQL 源代码分发中的mysql_query_attributes.h文件。

7.5.5 调度程序组件

原文:dev.mysql.com/doc/refman/8.0/en/scheduler-component.html

注意

scheduler组件包含在 MySQL 企业版中,这是一款商业产品。要了解更多关于商业产品的信息,请参见www.mysql.com/products/

截至 MySQL 8.0.34,scheduler组件提供了mysql_scheduler服务的实现,使应用程序、组件或插件可以每隔N秒配置、运行和取消配置任务。例如,audit_log服务器插件在初始化时调用scheduler组件,并配置定期刷新其内存缓存(参见启用审计日志刷新任务)。

  • 目的:实现component_scheduler.enabled系统变量,控制调度程序是否正在执行任务。在启动时,scheduler组件注册performance_schema.component_scheduler_tasks表,列出当前计划任务以及关于每个任务的一些运行时数据。

  • URN:file://component_sheduler

安装说明,请参见第 7.5.1 节,“安装和卸载组件”。

scheduler组件使用以下元素实现服务:

  • 一个按照下次运行时间(升序)排序的注册的非活动计划任务的优先级队列。

  • 一个注册的活动任务列表。

  • 一个后台线程:

    • 如果没有任务或者顶部任务需要更多时间来运行,则休眠。它会定期唤醒以检查是否到达结束时间。

    • 编译需要运行的任务列表,将其从非活动队列移动到活动队列,并逐个执行每个任务。

    • 执行任务列表后,将任务从活动列表中移除,添加到非活动列表,并计算它们下次需要运行的时间。

当调用者调用mysql_scheduler.create()服务时,它会创建一个新的计划任务实例添加到队列中,这会向后台线程的信号量发送信号。将新任务的句柄返回给调用者。调用代码应保留此句柄和调度服务的引用,直到调用mysql_scheduler.destroy()服务后。当调用者调用destroy()并传入从create()接收的句柄时,服务会等待任务变为非活动状态(如果正在运行),然后将其从非活动队列中移除。

组件服务调用每个应用程序提供的回调(函数指针)到同一调度线程中,依次按照每个需要运行的时间的顺序。

希望将调度队列功能整合到应用程序、组件或插件中的开发人员应查阅 MySQL 源代码分发中的 mysql_scheduler.h 文件。

7.6 MySQL 服务器插件

原文:dev.mysql.com/doc/refman/8.0/en/server-plugins.html

7.6.1 安装和卸载插件

7.6.2 获取服务器插件信息

7.6.3 MySQL 企业线程池

7.6.4 Rewriter Query Rewrite 插件

7.6.5 ddl_rewriter 插件

7.6.6 版本标记

7.6.7 Clone 插件

7.6.8 Keyring Proxy Bridge 插件

7.6.9 MySQL 插件服务

MySQL 支持一个插件 API,可以创建服务器插件。插件可以在服务器启动时加载,也可以在运行时加载和卸载而无需重新启动服务器。此接口支持的插件包括但不限于存储引擎、INFORMATION_SCHEMA表、全文解析器插件和服务器扩展。

MySQL 发行版包括几个实现服务器扩展的插件:

  • 用于验证客户端连接到 MySQL 服务器的尝试的插件。有几种认证协议的插件可用。参见第 8.2.17 节,“可插拔认证”。

  • 一个连接控制插件,使管理员能够在一定数量的连续失败的客户端连接尝试之后引入逐渐增加的延迟。参见第 8.4.2 节,“连接控制插件”。

  • 一个密码验证插件实现密码强度策略并评估潜在密码的强度。参见第 8.4.3 节,“密码验证组件”。

  • 半同步复制插件实现了一个接口,允许源继续进行,只要至少有一个副本对每个事务做出响应。参见第 19.4.10 节,“半同步复制”。

  • Group Replication 使您能够在一组 MySQL 服务器实例之间创建高可用的分布式 MySQL 服务,具有数据一致性、冲突检测和解决以及组成员服务等功能。参见第二十章,Group Replication

  • MySQL 企业版包括一个线程池插件,通过有效管理大量客户端连接的语句执行线程来增加服务器性能。参见第 7.6.3 节,“MySQL 企业线程池”。

  • MySQL Enterprise Edition 包括用于监视和记录连接和查询活动的审计插件。参见第 8.4.5 节,“MySQL 企业审计”。

  • MySQL Enterprise Edition 包括一个防火墙插件,实现应用级防火墙,使数据库管理员可以根据匹配接受的语句模式允许或拒绝 SQL 语句执行。参见第 8.4.7 节,“MySQL 企业防火墙”。

  • 查询重写插件检查 MySQL 服务器接收到的语句,并在服务器执行之前可能对其进行重写。参见第 7.6.4 节,“重写器查询重写插件”,以及第 7.6.5 节,“ddl_rewriter 插件”。

  • 版本令牌允许创建和同步服务器令牌,应用程序可以使用这些令牌来防止访问不正确或过时的数据。版本令牌基于一个实现version_tokens插件和一组可加载函数的插件库。参见第 7.6.6 节,“版本令牌”。

  • Keyring 插件为敏感信息提供安全存储。参见第 8.4.4 节,“MySQL Keyring”。

    在 MySQL 8.0.24 中,MySQL Keyring 开始从插件过渡到使用组件基础架构,通过使用名为daemon_keyring_proxy_plugin的插件作为插件和组件服务 API 之间的桥梁来实现。参见第 7.6.8 节,“Keyring 代理桥插件”。

  • X Plugin 扩展了 MySQL Server 的功能,使其能够作为文档存储库。运行 X Plugin 使 MySQL Server 能够使用 X 协议与客户端通信,该协议旨在将 MySQL 的 ACID 兼容存储能力作为文档存储库暴露出来。参见第 22.5 节,“X 插件”。

  • 克隆允许从本地或远程 MySQL 服务器实例克隆InnoDB数据。参见第 7.6.7 节,“克隆插件”。

  • 测试框架插件测试服务器服务。有关这些插件的信息,请参阅 MySQL Server Doxygen 文档中的 Plugins for Testing Plugin Services 部分,网址为dev.mysql.com/doc/index-other.html

以下各节描述了如何安装和卸载插件,以及如何在运行时确定已安装的插件并获取有关它们的信息。有关编写插件的信息,请参见 MySQL 插件 API。

7.6.1 安装和卸载插件

原文:dev.mysql.com/doc/refman/8.0/en/plugin-loading.html

必须在服务器中加载服务器插件才能使用它们。MySQL 支持在服务器启动和运行时加载插件。还可以在启动时控制已加载插件的激活状态,并在运行时卸载它们。

插件加载后,可以根据第 7.6.2 节“获取服务器插件信息”中的描述获取有关插件的信息。

  • 安装插件

  • 控制插件激活状态

  • 卸载插件

  • 插件和可加载函数

安装插件

在使用服务器插件之前,必须使用以下方法之一安装它。在描述中,plugin_name代表插件名称,如innodbcsvvalidate_password

  • 内置插件

  • 注册在 mysql.plugin 系统表中的插件

  • 使用命令行选项命名的插件

  • 使用 INSTALL PLUGIN 语句安装的插件

内置插件

服务器会自动识别内置插件。默认情况下,服务器在启动时启用插件。一些内置插件允许使用--*plugin_name*[=*activation_state*]选项进行更改。

注册在 mysql.plugin 系统表中的插件

mysql.plugin系统表用作插件的注册表(内置插件无需注册)。在正常启动序列期间,服务器会加载在表中注册的插件。默认情况下,对于从mysql.plugin表加载的插件,服务器还会启用插件。这可以通过--*plugin_name*[=*activation_state*]选项进行更改。

如果服务器使用--skip-grant-tables选项启动,mysql.plugin表中注册的插件将不会被加载,也将无法使用。

使用命令行选项命名的插件

位于插件库文件中的插件可以通过--plugin-load--plugin-load-add--early-plugin-load选项在服务器启动时加载。通常,对于在启动时加载的插件,服务器还会启用该插件。这可以通过--*plugin_name*[=*activation_state*]选项进行更改。

--plugin-load--plugin-load-add选项在服务器启动序列期间内置插件和存储引擎初始化后加载插件。--early-plugin-load选项用于加载必须在内置插件和存储引擎初始化之前可用的插件。

每个插件加载选项的值是一个以分号分隔的plugin_libraryname=plugin_library值的列表。每个plugin_library是包含插件代码的库文件的名称,每个name是要加载的插件的名称。如果插件库的名称没有任何前置插件名称,服务器将加载库中的所有插件。有了前置插件名称,服务器将仅从库中加载指定的插件。服务器在由plugin_dir系统变量命名的目录中查找插件库文件。

插件加载选项不会在mysql.plugin表中注册任何插件。对于后续的重新启动,只有在再次提供--plugin-load--plugin-load-add--early-plugin-load时,服务器才会再次加载插件。也就是说,该选项产生一次性的插件安装操作,仅持续一个服务器调用。

--plugin-load--plugin-load-add--early-plugin-load使得即使在给定--skip-grant-tables的情况下(导致服务器忽略mysql.plugin表),也能加载插件。--plugin-load--plugin-load-add--early-plugin-load还使得在启动时加载无法在运行时加载的插件成为可能。

--plugin-load-add选项是对--plugin-load选项的补充:

  • 每个--plugin-load的实例都会在启动时重置要加载的插件集合,而--plugin-load-add会向要加载的插件集合添加一个或多个插件,而不会重置当前集合。因此,如果指定了多个--plugin-load的实例,只有最后一个会生效。对于多个--plugin-load-add的实例,所有实例都会生效。

  • 参数格式与--plugin-load相同,但可以使用多个--plugin-load-add的实例来避免将大量插件作为单个长而难以控制的--plugin-load参数进行指定。

  • 可以在没有--plugin-load的情况下给出--plugin-load-add,但是在--plugin-load之前出现的任何--plugin-load-add实例都不会生效,因为--plugin-load会重置要加载的插件集合。

例如,这些选项:

--plugin-load=x --plugin-load-add=y

等同于这些选项:

--plugin-load-add=x --plugin-load-add=y

并且等同于这个选项:

--plugin-load="x;y"

但这些选项:

--plugin-load-add=y --plugin-load=x

等同于这个选项:

--plugin-load=x
使用 INSTALL PLUGIN 语句安装的插件

位于插件库文件中的插件可以通过INSTALL PLUGIN语句在运行时加载。该语句还会在mysql.plugin表中注册插件,以便导致服务器在后续重新启动时加载它。因此,INSTALL PLUGIN需要对mysql.plugin表的INSERT权限。

插件库文件的基本名称取决于您的平台。Unix 和类 Unix 系统通常使用.so作为后缀,Windows 则使用.dll

示例:--plugin-load-add选项在服务器启动时安装插件。要从名为somepluglib.so的插件库文件中安装名为myplugin的插件,请在my.cnf文件中使用以下行:

[mysqld]
plugin-load-add=myplugin=somepluglib.so

在这种情况下,插件不会在mysql.plugin中注册。在没有--plugin-load-add选项的情况下重新启动服务器会导致插件在启动时不被加载。

替代地,INSTALL PLUGIN语句会导致服务器在运行时从库文件加载插件代码:

INSTALL PLUGIN myplugin SONAME 'somepluglib.so';

INSTALL PLUGIN还会导致“永久”插件注册:插件将列在mysql.plugin表中,以确保服务器在后续重新启动时加载它。

许多插件可以在服务器启动时或运行时加载。但是,如果插件设计为必须在服务器启动期间加载和初始化,则尝试使用INSTALL PLUGIN在运行时加载插件会产生错误:

mysql> INSTALL PLUGIN myplugin SONAME 'somepluglib.so';
ERROR 1721 (HY000): Plugin 'myplugin' is marked as not dynamically
installable. You have to stop the server to install it.

在这种情况下,必须使用--plugin-load--plugin-load-add--early-plugin-load

如果插件既使用--plugin-load--plugin-load-add--early-plugin-load选项命名,又(由于先前的INSTALL PLUGIN语句的结果)在mysql.plugin表中,服务器会启动,但会将这些消息写入错误日志:

[ERROR] Function '*plugin_name*' already exists
[Warning] Couldn't load plugin named '*plugin_name*'
with soname '*plugin_object_file*'.

控制插件激活状态

如果服务器在启动时知道插件(例如,因为插件是使用--plugin-load-add选项命名或在mysql.plugin表中注册的),服务器会默认加载和启用插件。可以使用--*plugin_name*[=*activation_state*]启动选项来控制此类插件的激活状态,其中plugin_name是要影响的插件名称,如innodbcsvvalidate_password。与其他选项一样,选项名称中的破折号和下划线是可以互换的。此外,激活状态值不区分大小写。例如,--my_plugin=ON--my-plugin=on是等效的。

  • --*plugin_name*=OFF

    告诉服务器禁用插件。对于某些内置插件,如mysql_native_password,可能无法实现。

  • --*plugin_name*[=ON]

    告诉服务器启用插件。(不带值地指定选项为--*plugin_name*具有相同效果。)如果插件初始化失败,服务器将以插件禁用状态运行。

  • --*plugin_name*=FORCE

    告诉服务器启用插件,但如果插件初始化失败,服务器将不会启动。换句话说,此选项强制服务器以插件启用或完全禁用的方式运行。

  • --*plugin_name*=FORCE_PLUS_PERMANENT

    类似于FORCE,但另外防止插件在运行时卸载。如果用户尝试使用UNINSTALL PLUGIN这样做,将会出现错误。

插件激活状态可在信息模式PLUGINS表的LOAD_OPTION列中看到。

假设CSVBLACKHOLEARCHIVE是内置的可插拔存储引擎,并且您希望服务器在启动时加载它们,但要满足以下条件:如果CSV初始化失败,服务器允许运行,必须要求BLACKHOLE初始化成功,并且应禁用ARCHIVE。为了实现这一点,在选项文件中使用以下行:

[mysqld]
csv=ON
blackhole=FORCE
archive=OFF

--enable-*plugin_name*选项格式是--*plugin_name*=ON的同义词。--disable-*plugin_name*--skip-*plugin_name*选项格式是--*plugin_name*=OFF的同义词。

如果插件被禁用,要么明确使用OFF禁用,要么因为启用了ON但初始化失败而隐式禁用,那么需要插件的服务器操作方面发生变化。例如,如果插件实现了存储引擎,那么现有的存储引擎表将变得无法访问,并且尝试为存储引擎创建新表将导致使用默认存储引擎的表,除非启用了NO_ENGINE_SUBSTITUTION SQL 模式以导致发生错误。

禁用插件可能需要调整其他选项。例如,如果您使用--skip-innodb启动服务器以禁用InnoDB,则启动时可能还需要省略其他innodb_*xxx*选项。此外,因为InnoDB是默认存储引擎,除非您使用--default_storage_engine指定另一个可用的存储引擎,否则它无法启动。您还必须设置--default_tmp_storage_engine

卸载插件

在运行时,UNINSTALL PLUGIN语句会禁用并卸载服务器已知的插件。该语句会卸载插件并从mysql.plugin系统表中删除它(如果在那里注册)。因此,UNINSTALL PLUGIN语句需要对mysql.plugin表具有DELETE权限。由于插件不再在表中注册,服务器在后续重新启动期间不会加载插件。

UNINSTALL PLUGIN可以卸载插件,无论它是在运行时使用INSTALL PLUGIN加载还是在启动时使用插件加载选项加载,但要满足以下条件:

  • 无法卸载内置于服务器中的插件。这些可以通过信息模式PLUGINS表或SHOW PLUGINS的输出中具有NULL库名称的插件来识别。

  • 无法卸载在服务器启动时使用--*plugin_name*=FORCE_PLUS_PERMANENT启动的插件,这会阻止运行时插件的卸载。这些可以从PLUGINS表的LOAD_OPTION列中识别出来。

要卸载当前在服务器启动时使用插件加载选项加载的插件,请使用以下步骤。

  1. my.cnf文件中删除与插件相关的任何选项和系统变量。如果任何插件系统变量已经持久化到mysqld-auto.cnf文件中,请使用RESET PERSIST *var_name*来逐个删除它们。

  2. 重新启动服务器。

  3. 通常情况下,插件可以通过启动时的插件加载选项或在运行时使用INSTALL PLUGIN来安装,但不能同时使用两者。然而,如果在某个时刻还使用了INSTALL PLUGIN,那么仅仅从my.cnf文件中删除插件的选项可能不足以卸载它。如果插件仍然出现在PLUGINSSHOW PLUGINS的输出中,请使用UNINSTALL PLUGIN将其从mysql.plugin表中移除。然后再次重启服务器。

插件和可加载函数

安装插件时,可能还会自动安装相关的可加载函数。如果是这样,那么卸载插件时也会自动卸载这些函数。

7.6.2 获取服务器插件信息

原文:dev.mysql.com/doc/refman/8.0/en/obtaining-plugin-information.html

有几种方法可以确定服务器中安装了哪些插件:

  • 信息模式PLUGINS表为每个已加载的插件包含一行。任何具有PLUGIN_LIBRARY值为NULL的插件都是内置的,无法卸载。

    mysql> SELECT * FROM INFORMATION_SCHEMA.PLUGINS\G
    *************************** 1\. row ***************************
               PLUGIN_NAME: binlog
            PLUGIN_VERSION: 1.0
             PLUGIN_STATUS: ACTIVE
               PLUGIN_TYPE: STORAGE ENGINE
       PLUGIN_TYPE_VERSION: 50158.0
            PLUGIN_LIBRARY: NULL
    PLUGIN_LIBRARY_VERSION: NULL
             PLUGIN_AUTHOR: Oracle Corporation
        PLUGIN_DESCRIPTION: This is a pseudo storage engine to represent the binlog in a transaction
            PLUGIN_LICENSE: GPL
               LOAD_OPTION: FORCE
    ...
    *************************** 10\. row ***************************
               PLUGIN_NAME: InnoDB
            PLUGIN_VERSION: 1.0
             PLUGIN_STATUS: ACTIVE
               PLUGIN_TYPE: STORAGE ENGINE
       PLUGIN_TYPE_VERSION: 50158.0
            PLUGIN_LIBRARY: ha_innodb_plugin.so
    PLUGIN_LIBRARY_VERSION: 1.0
             PLUGIN_AUTHOR: Oracle Corporation
        PLUGIN_DESCRIPTION: Supports transactions, row-level locking,
                            and foreign keys
            PLUGIN_LICENSE: GPL
               LOAD_OPTION: ON
    ...
    
  • SHOW PLUGINS语句为每个已加载的插件显示一行。任何具有Library值为NULL的插件都是内置的,无法卸载。

    mysql> SHOW PLUGINS\G
    *************************** 1\. row ***************************
       Name: binlog
     Status: ACTIVE
       Type: STORAGE ENGINE
    Library: NULL
    License: GPL
    ...
    *************************** 10\. row ***************************
       Name: InnoDB
     Status: ACTIVE
       Type: STORAGE ENGINE
    Library: ha_innodb_plugin.so
    License: GPL
    ...
    
  • mysql.plugin表显示已经通过INSTALL PLUGIN注册的插件。该表仅包含插件名称和库文件名称,因此提供的信息不如PLUGINS表或SHOW PLUGINS语句详细。

7.6.3 MySQL 企业线程池

原文:dev.mysql.com/doc/refman/8.0/en/thread-pool.html

7.6.3.1 线程池元素

7.6.3.2 线程池安装

7.6.3.3 线程池操作

7.6.3.4 线程池调优

注意

MySQL 企业线程池是 MySQL 企业版中包含的一个扩展,是一款商业产品。要了解更多关于商业产品的信息,请访问www.mysql.com/products/

MySQL 企业版包括 MySQL 企业线程池,使用服务器插件实现。MySQL 服务器中的默认线程处理模型使用每个客户端连接一个线程执行语句。随着更多客户端连接到服务器并执行语句,整体性能会下降。线程池插件提供了一个旨在减少开销并提高性能的替代线程处理模型。该插件实现了一个线程池,通过有效管理大量客户端连接的语句执行线程来提高服务器性能。

线程池解决了使用每个连接一个线程的模型存在的几个问题:

  • 太多线程堆栈使 CPU 缓存在高度并行执行工作负载中几乎无用。线程池促进线程堆栈重用,以最小化 CPU 缓存占用。

  • 太多线程并行执行时,上下文切换开销很高。这也对操作系统调度程序构成挑战。线程池控制活动线程的数量,以保持 MySQL 服务器内部的并行性在一个服务器主机上可以处理的水平,并且适合 MySQL 正在执行的服务器主机。

  • 太多并行执行的事务会增加资源争用。在InnoDB中,这会增加持有中央互斥锁的时间。线程池控制事务何时开始以确保不会有太多并行执行。

其他资源

第 A.15 节,“MySQL 8.0 FAQ:MySQL 企业线程池”

原文:dev.mysql.com/doc/refman/8.0/en/thread-pool-elements.html

7.6.3.1 线程池元素

MySQL 企业线程池包括以下元素:

  • 一个插件库文件实现了线程池代码的插件以及几个相关的监控表,提供有关线程池操作的信息:

    • 截至 MySQL 8.0.14,监控表是性能模式表;请参见第 29.12.16 节,“性能模式线程池表”。

    • 在 MySQL 8.0.14 之前,监控表是INFORMATION_SCHEMA表;请参见第 28.5 节,“INFORMATION_SCHEMA 线程池表”。

      INFORMATION_SCHEMA表现在已被弃用;预计它们将在将来的 MySQL 版本中被移除。应用程序应该从INFORMATION_SCHEMA表过渡到性能模式表。例如,如果一个应用程序使用此查询:

      SELECT * FROM INFORMATION_SCHEMA.TP_THREAD_STATE;
      

      应用程序应该改用此查询:

      SELECT * FROM performance_schema.tp_thread_state;
      

    注意

    如果您没有加载所有监控表,一些或所有 MySQL 企业监控器线程池图可能为空。

    要详细了解线程池的工作原理,请参见第 7.6.3.3 节,“线程池操作”。

  • 有几个系统变量与线程池相关。当服务器成功加载线程池插件时,thread_handling系统变量的值为loaded-dynamically

    其他相关的系统变量由线程池插件实现,并且除非启用,否则不可用。有关使用这些变量的信息,请参见第 7.6.3.3 节,“线程池操作”和第 7.6.3.4 节,“线程池调整”。

  • 性能模式具有暴露有关线程池信息的工具,可用于调查操作性能。要识别它们,请使用此查询:

    SELECT * FROM performance_schema.setup_instruments
    WHERE NAME LIKE '%thread_pool%';
    

    有关更多信息,请参见第二十九章,“MySQL 性能模式”。

原文:dev.mysql.com/doc/refman/8.0/en/thread-pool-installation.html

7.6.3.2 线程池安装

本节描述了如何安装 MySQL Enterprise Thread Pool。有关安装插件的一般信息,请参见第 7.6.1 节,“安装和卸载插件”。

要被服务器使用,插件库文件必须位于 MySQL 插件目录中(由plugin_dir系统变量命名的目录)。如有必要,在服务器启动时通过设置plugin_dir的值来��置插件目录位置。

插件库文件基本名称为thread_pool。文件名后缀因平台而异(例如,对于 Unix 和类 Unix 系统,为.so,对于 Windows 为.dll)。

  • MySQL 8.0.14 线程池安装

  • MySQL 8.0.14 之前的线程池安装

MySQL 8.0.14 线程池安装

在 MySQL 8.0.14 及更高版本中,线程池监控表是性能模式表,随着线程池插件一起加载和卸载。INFORMATION_SCHEMA 版本的表已被弃用,但仍可用;它们按照 MySQL 8.0.14 之前的线程池安装说明中的说明安装。

要启用线程池功能,请通过使用--plugin-load-add选项启动服务器加载插件。为此,请将以下行放入服务器的my.cnf文件中,并根据需要调整.so后缀以适应您的平台:

[mysqld]
plugin-load-add=thread_pool.so

要验证插件安装,请检查信息模式PLUGINS表或使用SHOW PLUGINS语句(参见第 7.6.2 节,“获取服务器插件信息”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE 'thread%';
+-----------------------+---------------+
| PLUGIN_NAME           | PLUGIN_STATUS |
+-----------------------+---------------+
| thread_pool           | ACTIVE        |
+-----------------------+---------------+

要验证性能模式监控表是否可用,请检查信息模式TABLES表或使用SHOW TABLES语句。例如:

mysql> SELECT TABLE_NAME
       FROM INFORMATION_SCHEMA.TABLES
       WHERE TABLE_SCHEMA = 'performance_schema'
       AND TABLE_NAME LIKE 'tp%';
+-----------------------+
| TABLE_NAME            |
+-----------------------+
| tp_thread_group_state |
| tp_thread_group_stats |
| tp_thread_state       |
+-----------------------+

如果服务器成功加载线程池插件,则将thread_handling系统变量设置为loaded-dynamically

如果插件初始化失败,请检查服务器错误日志以获取诊断消息。

MySQL 8.0.14 之前的线程池安装

在 MySQL 8.0.14 之前,线程池监视表是与线程池插件分开的插件,可以单独安装。

要启用线程池功能,请通过使用--plugin-load-add选项启动服务器加载要使用的插件。例如,如果只命名插件库文件,则服务器将加载其中包含的所有插件(即线程池插件和所有INFORMATION_SCHEMA表)。为此,请将以下行放入服务器的my.cnf文件中,并根据需要调整平台的.so后缀:

[mysqld]
plugin-load-add=thread_pool.so

这相当于通过逐个命名加载所有线程池插件:

[mysqld]
plugin-load-add=thread_pool=thread_pool.so
plugin-load-add=tp_thread_state=thread_pool.so
plugin-load-add=tp_thread_group_state=thread_pool.so
plugin-load-add=tp_thread_group_stats=thread_pool.so

如果需要,可以从库文件中加载单独的插件。要加载线程池插件但不加载INFORMATION_SCHEMA表,请使用以下选项:

[mysqld]
plugin-load-add=thread_pool=thread_pool.so

要加载线程池插件和仅TP_THREAD_STATE INFORMATION_SCHEMA表,请使用以下选项:

[mysqld]
plugin-load-add=thread_pool=thread_pool.so
plugin-load-add=tp_thread_state=thread_pool.so

要验证插件安装,请检查信息模式PLUGINS表,或使用SHOW PLUGINS语句(参见第 7.6.2 节,“获取服务器插件信息”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE 'thread%' OR PLUGIN_NAME LIKE 'tp%';
+-----------------------+---------------+
| PLUGIN_NAME           | PLUGIN_STATUS |
+-----------------------+---------------+
| thread_pool           | ACTIVE        |
| TP_THREAD_STATE       | ACTIVE        |
| TP_THREAD_GROUP_STATE | ACTIVE        |
| TP_THREAD_GROUP_STATS | ACTIVE        |
+-----------------------+---------------+

如果服务器成功加载线程池插件,则将thread_handling系统变量设置为loaded-dynamically

如果插件初始化失败,请检查服务器错误日志以获取诊断消息。

原文:dev.mysql.com/doc/refman/8.0/en/thread-pool-operation.html

7.6.3.3 线程池操作

线程池由多个线程组组成,每个组管理一组客户端连接。随着连接的建立,线程池以轮询方式将它们分配给线程组。

线程池公开了可用于配置其操作的系统变量:

  • thread_pool_algorithm: 用于调度的并发算法。

  • thread_pool_dedicated_listeners: 在每个线程组中专门指定一个监听线程,以监听分配给该组的连接的传入语句。

  • thread_pool_high_priority_connection: 如何为会话安排语句执行。

  • thread_pool_max_active_query_threads: 每组允许的活动线程数。

  • thread_pool_max_transactions_limit: 线程池插件允许的最大事务数。

  • thread_pool_max_unused_threads: 允许的休眠线程数。

  • thread_pool_prio_kickup_timer: 在低优先级队列中等待执行的语句移动到高优先级队列之前的时间。

  • thread_pool_query_threads_per_group: 在线程组中允许的查询线程数(默认为单个查询线程)。如果由于长时间运行的事务导致响应时间变慢,考虑增加该值。

  • thread_pool_size: 线程池中线程组的数量。这是控制线程池性能最重要的参数。

  • thread_pool_stall_limit: 执行语句被视为停滞之前的时间。

  • thread_pool_transaction_delay: 开始新事务之前的延迟时间。

要配置线程组的数量,请使用thread_pool_size系统变量。默认组数为 16。有关设置此变量的指导,请参见第 7.6.3.4 节“线程池调优”。

每个组的最大线程数为 4096(在某些系统上为 4095,其中一个线程在内部使用)。

线程池将连接和线程分开,因此连接和执行来自这些连接的语句的线程之间没有固定关系。这与默认的线程处理模型不同,后者将一个线程与一个连接关联起来,以便给定线程执行来自其连接的所有语句。

默认情况下,线程池尝试确保每个组中最多有一个线程在任何时候执行,但有时允许更多线程暂时执行以获得最佳性能:

  • 每个线程组都有一个监听线程,用于监听分配给该组的连接的传入语句。当语句到达时,线程组要么立即开始执行它,要么将其排队以供稍后执行:

    • 如果接收到的语句是唯一的,并且没有排队或当前正在执行的语句,则会立即执行。

      从 MySQL 8.0.31 开始,可以通过配置thread_pool_transaction_delay来延迟立即执行,这对事务有限制作用。有关更多信息,请参考后续讨论中对该变量的描述。

    • 如果语句由于同时排队或执行的语句而无法立即开始执行,则会发生排队。

  • thread_pool_transaction_delay 变量指定了以毫秒为单位的事务延迟。工作线程在执行新事务之前会休眠指定的时间段。

    在并行事务影响其他操作的性能的情况下,可以使用事务延迟。例如,如果并行事务影响索引创建或在线缓冲池调整操作,可以配置事务延迟以减少资源争用。延迟对事务有限制作用。

    thread_pool_transaction_delay 设置不影响从特权连接(分配给Admin线程组的连接)发出的查询。这些查询不受配置的事务延迟影响。

  • 如果立即执行发生,则监听线程执行它。(这意味着暂时没有线程在组中监听。)如果语句很快完成,执行线程将返回到监听语句。否则,线程池会认为语句被阻塞,并启动另一个线程作为监听线程(必要时创建)。为了确保没有线程组被阻塞在被阻塞的语句上,线程池有一个定期监视线程组状态的后台线程。

    通过使用监听线程执行可以立即开始的语句,如果语句很快完成,则无需创建额外的线程。这确保在并发线程数量较低的情况下实现最有效的执行。

    当线程池插件启动时,它会为每个组创建一个线程(监听线程),以及后台线程。根据需要创建额外的线程来执行语句。

  • thread_pool_stall_limit系统变量的值确定了前一项中“快速完成”的含义。在被视为停顿之前的默认时间为 60ms,但可以设置为最大 6 秒。此参数可配置,以便您能够在服务器工作负载中找到适当的平衡。较短的等待值允许线程更快地启动。较短的值也更有利于避免死锁情况。较长的等待值对包含长期运行语句的工作负载很有用,以避免在当前语句执行时启动过多的新语句。

  • 如果thread_pool_max_active_query_threads为 0,则默认算法适用于确定每个组的活动线程的最大数量,就像前面描述的那样。默认算法考虑了停顿的线程,并可能暂时允许更多的活动线程。如果thread_pool_max_active_query_threads大于 0,则它会限制每个组的活动线程数量。

  • 线程池专注于限制并发短期运行的语句数量。在执行语句达到停顿时间之前,它会阻止其他语句开始执行。如果语句执行超过停顿时间,它将被允许继续执行,但不再阻止其他语句开始。通过这种方式,线程池试图确保在每个线程组中永远不会有多个短期运行的语句,尽管可能存在多个长期运行的语句。让长期运行的语句阻止其他语句执行是不可取的,因为可能需要等待的时间没有限制。例如,在复制源服务器上,负责向副本发送二进制日志事件的线程实际上会永远运行。

  • 如果语句遇到磁盘 I/O 操作或用户级锁(行锁或表锁),则该语句将被阻塞。阻塞将导致线程组变为未使用状态,因此会有回调到线程池,以确保线程池可以立即在该组中启动一个新线程来执行另一个语句。当阻塞的线程返回时,线程池允许其立即重新启动。

  • 有两个队列,一个高优先级队列和一个低优先级队列。事务中的第一条语句进入低优先级队列。如果事务正在进行中(其语句已开始执行),则事务的任何后续语句进入高优先级队列,否则进入低优先级队列。通过启用thread_pool_high_priority_connection系统变量,可以影响队列分配,导致会话的所有排队语句进入高优先级队列。

    针对非事务性存储引擎的语句,或者如果启用了autocommit的事务性引擎,被视为低优先级语句,因为在这种情况下每条语句都是一个事务。因此,对于InnoDBMyISAM表的语句混合,线程池优先处理InnoDB表的语句而不是MyISAM表的语句,除非启用了autocommit。启用autocommit后,所有语句都具有低优先级。

  • 当线程组选择一个排队的语句进行执行时,首先查看高优先级队列,然后查看低优先级队列。如果找到一条语句,则将其从队列中移除并开始执行。

  • 如果一条语句在低优先级队列中停留时间过长,线程池将移动到高优先级队列。thread_pool_prio_kickup_timer系统变量的值控制移动前的时间。对于每个线程组,每 10ms(每秒 100 次)最多将一条语句从低优先级队列移动到高优先级队列。

  • 线程池重复使用最活跃的线程以更好地利用 CPU 缓存。这是一个对性能有很大影响的小调整。

  • 当一个线程执行来自用户连接的语句时,性能模式仪表化将线程活动归因于用户连接。否则,性能模式将活动归因于线程池。

以下是线程组可能启动多个线程执行语句的条件示例:

  • 一个线程开始执行一条语句,但运行时间足够长以被视为停滞。线程组允许另一个线程开始执行另一条语句,即使第一个线程仍在执行。

  • 一个线程开始执行一条语句,然后变为阻塞状态并将此情况报告给线程池。线程组允许另一个线程开始执行另一条语句。

  • 一个线程开始执行一个语句,变得阻塞,但没有报告它被阻塞,因为阻塞不发生在已经使用线程池回调进行仪器化的代码中。在这种情况下,该线程对线程组来说仍在运行。如果阻塞持续时间足够长,使语句被视为停滞不前,组允许另一个线程开始执行另一个语句。

线程池设计为可扩展到越来越多的连接。它还设计为避免由于限制活动执行语句的数量而可能产生的死锁。重要的是,不向线程池报告的线程不应该阻止其他语句的执行,从而导致线程池陷入死锁。以下是此类语句的示例:

  • 长时间运行的语句。这些将导致仅有少数语句使用所有资源,它们可能阻止其他所有人访问服务器。

  • 读取二进制日志并将其发送到副本的二进制日志转储线程。这是一种长时间运行的“语句”,运行时间很长,不应该阻止其他语句的执行。

  • 在行锁、表锁、休眠或任何其他未被 MySQL 服务器或存储引擎报告给线程池的阻塞活动上被阻塞的语句。

在每种情况下,为了防止死锁,当语句不能快速完成时,将该语句移至停滞类别,以便线程组可以允许另一个语句开始执行。通过这种设计,当线程执行或长时间阻塞时,线程池将该线程移至停滞类别,并在语句的其余执行过程中,不会阻止其他语句的执行。

可发生的线程最大数量是max_connectionsthread_pool_size的总和。这可能发生在所有连接都处于执行模式且每个组创建了一个额外线程来监听更多语句的情况下。这不一定经常发生,但在理论上是可能的。

特权连接

当达到thread_pool_max_transactions_limit定义的限制时,新连接似乎会挂起,直到一个或多个现有事务完成。当尝试在现有连接上启动新事务时也会发生相同情况。如果现有连接被阻塞或长时间运行,访问服务器的唯一方法是使用特权连接。

要建立特权连接,发起连接的用户必须具有TP_CONNECTION_ADMIN权限。特权连接会忽略由thread_pool_max_transactions_limit定义的限制,并允许连接到服务器以增加限制、移除限制或终止正在运行的事务。TP_CONNECTION_ADMIN权限必须显式授予,不会默认授予任何用户。

特权连接可以执行语句和启动事务,并分配给指定为Admin线程组的线程组。

当查询performance_schema.tp_thread_group_stats表时,该表报告每个线程组的统计信息,Admin线程组的统计信息报告在结果集的最后一行。例如,如果SELECT * FROM performance_schema.tp_thread_group_stats\G返回 17 行(每个线程组一行),Admin线程组的统计信息将报告在第 17 行。

原文:dev.mysql.com/doc/refman/8.0/en/thread-pool-tuning.html

7.6.3.4 线程池调优

本节提供了关于确定线程池性能最佳配置的指导,以事务每秒等指标来衡量。

最重要的是线程池中线程组的数量,可以在服务器启动时使用--thread-pool-size选项进行设置;这个值在运行时无法更改。对于这个选项的推荐值取决于主要使用的存储引擎是InnoDB还是MyISAM

  • 如果主要存储引擎是InnoDB,线程池大小的推荐值是主机机器上可用的物理核心数,最大不超过 512。

  • 如果主要存储引擎是MyISAM,线程池大小应该设置得相对较低。通常情况下,最佳性能在 4 到 8 之间。较高的值可能会对性能产生轻微负面影响,但不会太明显。

线程池插件可以处理的并发事务数量上限由thread_pool_max_transactions_limit的值确定。这个系统变量的推荐初始设置是物理核心数乘以 32。您可能需要根据特定工作负载调整这个值;这个值的合理上限是预期的最大并发连接数;Max_used_connections状态变量的值可以作为确定这个值的指导。一个好的方法是将thread_pool_max_transactions_limit设置为这个值,然后在观察吞吐量的影响时逐渐调整它的值。

线程组中允许的最大查询线程数由thread_pool_query_threads_per_group的值确定,可以在运行时进行调整。此值与线程池大小的乘积大致等于可用于处理查询的总线程数。通常获得最佳性能意味着在thread_pool_query_threads_per_group和线程池大小之间为您的应用程序找到适当的平衡。较大的thread_pool_query_threads_per_group值使得在线程组中同时执行长时间查询并阻塞较短查询的可能性较小,当工作负载包括长时间和短时间运行的查询时。您应该记住,当使用较小的线程池大小值和较大的thread_pool_query_threads_per_group值时,每个线程组的连接轮询操作的开销会增加。因此,我们建议将thread_pool_query_threads_per_group的起始值设置为2;将此变量设置为较低的值通常不会提供任何性能优势。

在正常情况下获得最佳性能,我们还建议将thread_pool_algorithm设置为 1 以实现高并发。

此外,thread_pool_stall_limit系统变量的值决定了阻塞和长时间运行语句的处理方式。如果所有阻塞 MySQL 服务器的调用都报告给线程池,那么它将始终知道执行线程何时被阻塞,但这并不总是正确的。例如,可能会在未使用线程池回调进行仪器化的代码中发生阻塞。对于这种情况,线程池必须能够识别似乎被阻塞的线程。这是通过由thread_pool_stall_limit的值确定的超时来完成的,该超时确保服务器不会完全被阻塞。thread_pool_stall_limit的值表示 10 毫秒间隔的数量,因此600(最大值)表示 6 秒。

thread_pool_stall_limit还可以使线程池处理长时间运行的语句。如果允许长时间运行的语句阻塞线程组,那么分配给该组的所有其他连接都将被阻塞,无法开始执行,直到长时间运行的语句完成。在最坏的情况下,这可能需要几个小时甚至几天。

应选择thread_pool_stall_limit的值,使得执行时间超过该值的语句被视为停滞。停滞的语句会产生大量额外开销,因为它们涉及额外的上下文切换,有时甚至涉及额外的线程创建。另一方面,将thread_pool_stall_limit参数设置得太高意味着长时间运行的语句会阻塞一些短时间运行的语句,时间超过必要的时间。较短的等待值允许线程更快地启动。较短的值也更有利于避免死锁情况。较长的等待值对包含长时间运行语句的工作负载有用,以避免在当前语句执行时启动太多新语句。

假设一个服务器执行的工作负载中,即使在服务器负载较重时,99.9%的语句在 100ms 内完成,而剩余的语句在 100ms 至 2 小时之间均匀分布。在这种情况下,将thread_pool_stall_limit设置为 10(10 × 10ms = 100ms)是有意义的。默认值为 6(60ms),适用于主要执行非常简单语句的服务器。

thread_pool_stall_limit 参数可以在运行时更改,以使您能够找到适合服务器工作负载的平衡。假设启用了tp_thread_group_stats表,您可以使用以下查询来确定停滞执行语句的比例:

SELECT SUM(STALLED_QUERIES_EXECUTED) / SUM(QUERIES_EXECUTED)
FROM performance_schema.tp_thread_group_stats;

这个数字应尽可能低。为了减少语句停滞的可能性,增加thread_pool_stall_limit的值。

当一个语句到达时,它实际开始执行之前可以延迟的最长时间是多少?假设满足以下条件:

  • 低优先级队列中有 200 个语句在排队。

  • 高优先级队列中有 10 个语句在排队。

  • thread_pool_prio_kickup_timer 设置为 10000(10 秒)。

  • thread_pool_stall_limit 设置为 100(1 秒)。

在最坏的情况下,这 10 个高优先级语句代表了 10 个长时间执行的事务。因此,在最坏的情况下,没有语句可以移动到高优先级队列,因为它总是包含等待执行的语句。在 10 秒后,新语句有资格被移动到高优先级队列。然而,在它被移动之前,它之前的所有语句也必须被移动。这可能需要另外 2 秒,因为每秒最多可以将 100 个语句移动到高优先级队列。现在当语句到达高优先级队列时,可能会有许多长时间运行的语句在它前面。在最坏的情况下,每一个都会被阻塞,每个语句之间需要 1 秒才能从高优先级队列中检索到下一个语句。因此,在这种情况下,新语句开始执行前需要 222 秒。

这个例子展示了一个应用程序的最坏情况。如何处理取决于应用程序。如果应用程序对响应时间有很高的要求,它很可能应该在更高的级别自行限制用户。否则,它可以使用线程池配置参数来设置某种最大等待时间。

7.6.4 Rewriter 查询重写插件

译文:dev.mysql.com/doc/refman/8.0/en/rewriter-query-rewrite-plugin.html

7.6.4.1 安装或卸载 Rewriter 查询重写插件

7.6.4.2 使用 Rewriter 查询重写插件

7.6.4.3 Rewriter 查询重写插件参考

MySQL 支持查询重写插件,可以在服务器执行之前检查并可能修改服务器接收到的 SQL 语句。请参阅 查询重写插件。

MySQL 发行版包括一个名为 Rewriter 的后解析查询重写插件以及用于安装插件及其相关元素的脚本。这些元素共同工作,提供语句重写功能:

  • 一个名为 Rewriter 的服务器端插件检查语句并可能根据其内存中的重写规则缓存对其进行重写。

  • 以下语句可能会被重写:

    • 截至 MySQL 8.0.12:支持 SELECTINSERTREPLACEUPDATEDELETE

    • 在 MySQL 8.0.12 之前:仅支持 SELECT

    独立语句和预编译语句可能会被重写。出现在视图定义或存储程序中的语句不会被重写。

  • Rewriter 插件使用名为 query_rewrite 的数据库,其中包含名为 rewrite_rules 的表。该表为插件决定是否重写语句提供持久存储的规则。用户通过修改存储在此表中的规则集与插件进行通信。插件通过设置表行的 message 列与用户进行通信。

  • query_rewrite 数据库包含一个名为 flush_rewrite_rules() 的存储过程,将规则表的内容加载到插件中。

  • 一个名为 load_rewrite_rules() 的可加载函数由 flush_rewrite_rules() 存储过程使用。

  • Rewriter 插件公开了系统变量,使插件配置和状态变量提供运行时操作信息。在 MySQL 8.0.31 及更高版本中,该插件还支持一个权限(SKIP_QUERY_REWRITE),用于保护特定用户的查询免受重写。

以下部分描述了如何安装和使用 Rewriter 插件,并提供了其相关元素的参考信息。

原文:dev.mysql.com/doc/refman/8.0/en/rewriter-query-rewrite-plugin-installation.html

7.6.4.1 安装或卸载 Rewriter 查询重写插件

注意

如果安装了Rewriter插件,即使禁用了也会带来一些开销。为避免这种开销,除非打算使用该插件,否则不要安装它。

要安装或卸载Rewriter查询重写插件,请选择位于 MySQL 安装的share目录中的适当脚本:

  • install_rewriter.sql:选择此脚本以安装Rewriter插件及其相关元素。

  • uninstall_rewriter.sql:选择此脚本以卸载Rewriter插件及其相关元素。

按照以下方式运行所选脚本:

$> mysql -u root -p < install_rewriter.sql
Enter password: *(enter root password here)*

此处示例使用install_rewriter.sql安装脚本。如果要卸载插件,请替换为uninstall_rewriter.sql

运行安装脚本应该会安装并启用插件。要验证,请连接到服务器并执行以下语句:

mysql> SHOW GLOBAL VARIABLES LIKE 'rewriter_enabled';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| rewriter_enabled | ON    |
+------------------+-------+

有关使用说明,请参见第 7.6.4.2 节,“使用 Rewriter 查询重写插件”。有关参考信息,请参见第 7.6.4.3 节,“Rewriter 查询重写插件参考”。

原文:dev.mysql.com/doc/refman/8.0/en/rewriter-query-rewrite-plugin-usage.html

7.6.4.2 使用 Rewriter 查询重写插件

要启用或禁用插件,请启用或禁用rewriter_enabled系统变量。默认情况下,安装插件时Rewriter插件是启用的(参见第 7.6.4.1 节,“安装或卸载 Rewriter 查询重写插件”)。要显式设置初始插件状态,可以在服务器启动时设置该变量。例如,要在选项文件中启用插件,请使用以下行:

[mysqld]
rewriter_enabled=ON

也可以在运行时启用或禁用插件:

SET GLOBAL rewriter_enabled = ON;
SET GLOBAL rewriter_enabled = OFF;

假设Rewriter插件已启用,它会检查并可能修改服务器接收到的每个可重写语句。插件根据其内存中的重写规则缓存来决定是否重写语句,这些规则从query_rewrite数据库中的rewrite_rules表中加载。

这些语句会被重写:

  • 截至 MySQL 8.0.12:SELECTINSERTREPLACEUPDATEDELETE

  • 在 MySQL 8.0.12 之前:仅SELECT

独立语句和准备语句会被重写。在视图定义或存储程序中出现的语句不会被重写。

从 MySQL 8.0.31 开始,具有SKIP_QUERY_REWRITE权限的用户运行的语句不会被重写,前提是rewriter_enabled_for_threads_without_privilege_checks系统变量设置为OFF(默认为ON)。这可用于控制语句和应该保持不变的语句,例如来自由CHANGE REPLICATION SOURCE TO指定的SOURCE_USER的语句。对于由 MySQL 客户端程序执行的语句,包括mysqlbinlogmysqladminmysqldumpmysqlpump;因此,您应该授予SKIP_QUERY_REWRITE给这些实用程序用于连接到 MySQL 的用户帐户或帐户。

  • 添加重写规则

  • 语句匹配工作原理

  • 重写准备语句

  • 重写插件操作信息

  • 字符集的重写插件使用

添加重写规则

要为Rewriter插件添加规则,请向rewrite_rules表添加行,然后调用flush_rewrite_rules()存储过程将规则从表中加载到插件中。以下示例创建了一个简单的规则,用于匹配选择单个文字值的语句:

INSERT INTO query_rewrite.rewrite_rules (pattern, replacement)
VALUES('SELECT ?', 'SELECT ? + 1');

结果表内容如下所示:

mysql> SELECT * FROM query_rewrite.rewrite_rules\G
*************************** 1\. row ***************************
                id: 1
           pattern: SELECT ?
  pattern_database: NULL
       replacement: SELECT ? + 1
           enabled: YES
           message: NULL
    pattern_digest: NULL
normalized_pattern: NULL

规则指定了一个模式模板,指示要匹配哪些SELECT语句,并指定了一个替换模板,指示如何重写匹配的语句。但是,将规则添加到rewrite_rules表中并不足以使Rewriter插件使用该规则。您必须调用flush_rewrite_rules()将表内容加载到插件的内存缓存中:

mysql> CALL query_rewrite.flush_rewrite_rules();

提示

如果您的重写规则似乎无法正常工作,请确保通过调用flush_rewrite_rules()重新加载规则表。

当插件从规则表中读取每个规则时,它会从模式计算出一个规范化(语句摘要)形式和一个摘要哈希值,并使用它们来更新normalized_patternpattern_digest列:

mysql> SELECT * FROM query_rewrite.rewrite_rules\G
*************************** 1\. row ***************************
                id: 1
           pattern: SELECT ?
  pattern_database: NULL
       replacement: SELECT ? + 1
           enabled: YES
           message: NULL
    pattern_digest: d1b44b0c19af710b5a679907e284acd2ddc285201794bc69a2389d77baedddae
normalized_pattern: select ?

有关语句摘要、规范化语句和摘要哈希值的信息,请参见第 29.10 节,“性能模式语句摘要和采样”。

如果由于某些错误而无法加载��则,则调用flush_rewrite_rules()会产生一个错误:

mysql> CALL query_rewrite.flush_rewrite_rules();
ERROR 1644 (45000): Loading of some rule(s) failed.

当发生这种情况时,插件会将错误消息写入规则行的message列,以传达问题。检查rewrite_rules表,查看具有非NULL message列值的行,以查看存在哪些问题。

模式使用与准备语句相同的语法(参见第 15.5.1 节,“PREPARE 语句”)。在模式模板中,?字符充当匹配数据值的参数标记。?字符不应包含在引号内。参数标记仅可用于数据值应出现的位置,不能用于 SQL 关键字、标识符、函数等。插件解析语句以识别文本值(如第 11.1 节,“文本值”中定义的那样),因此您可以在任何文本值的位置放置参数标记。

像模式一样,替换内容可以包含?字符。对于与模式模板匹配的语句,插件会重写它,使用数据值替换替换中的?参数标记,这些数据值由模式中相应标记匹配的数据值确定。结果是一个完整的语句字符串。插件要求服务器解析它,并将重写后的语句表示返回给服务器。

添加并加载规则后,请检查是否根据语句是否与规则模式匹配而进行重写:

mysql> SELECT PI();
+----------+
| PI()     |
+----------+
| 3.141593 |
+----------+
1 row in set (0.01 sec)

mysql> SELECT 10;
+--------+
| 10 + 1 |
+--------+
|     11 |
+--------+
1 row in set, 1 warning (0.00 sec)

第一个SELECT语句不会进行重写,但第二个会。第二个语句说明了当Rewriter插件重写语句时,会生成警告消息。要查看消息,请使用SHOW WARNINGS

mysql> SHOW WARNINGS\G
*************************** 1\. row ***************************
  Level: Note
   Code: 1105
Message: Query 'SELECT 10' rewritten to 'SELECT 10 + 1' by a query rewrite plugin

语句不必重写为相同类型的语句。以下示例加载一个将DELETE语句重写为UPDATE语句的规则:

INSERT INTO query_rewrite.rewrite_rules (pattern, replacement)
VALUES('DELETE FROM db1.t1 WHERE col = ?',
       'UPDATE db1.t1 SET col = NULL WHERE col = ?');
CALL query_rewrite.flush_rewrite_rules();

要启用或禁用现有规则,请修改其enabled列并重新加载表到插件中。要禁用规则 1:

UPDATE query_rewrite.rewrite_rules SET enabled = 'NO' WHERE id = 1;
CALL query_rewrite.flush_rewrite_rules();

这使您可以停用规则而无需将其从表中删除。

要重新启用规则 1:

UPDATE query_rewrite.rewrite_rules SET enabled = 'YES' WHERE id = 1;
CALL query_rewrite.flush_rewrite_rules();

rewrite_rules表包含一个pattern_database列,Rewriter用于匹配未使用数据库名称限定的表名:

  • 语句中的限定表名仅在相应数据库和表名相同的情况下与模式中的限定名称匹配。

  • 语句中的未限定表名仅在默认数据库与pattern_database相同且表名相同的情况下与模式中的未限定名称匹配。

假设一个名为appdb.users的表有一个名为id的列,并且应用程序预期使用以下形式之一的查询从表中选择行,第二种形式可以在appdb是默认数据库时使用:

SELECT * FROM users WHERE appdb.id = *id_value*;
SELECT * FROM users WHERE id = *id_value*;

还假设id列被重命名为user_id(也许必须修改表以添加另一种 ID,并且有必要更明确地指示id列代表什么类型的 ID)。

更改意味着应用程序必须在WHERE子句中引用user_id而不是id,但无法更新的旧应用程序将不再正常工作。Rewriter插件可以通过匹配和重写有问题的语句来解决此问题。要将语句SELECT * FROM appdb.users WHERE id = *value*匹配并重写为SELECT * FROM appdb.users WHERE user_id = *value*,您可以向重写规则表中插入代表替换规则的行。如果还想使用未限定表名匹配此SELECT,还需要添加一个显式规则。使用?作为值占位符,需要的两个INSERT语句如下:

INSERT INTO query_rewrite.rewrite_rules
    (pattern, replacement) VALUES(
    'SELECT * FROM appdb.users WHERE id = ?',
    'SELECT * FROM appdb.users WHERE user_id = ?'
    );
INSERT INTO query_rewrite.rewrite_rules
    (pattern, replacement, pattern_database) VALUES(
    'SELECT * FROM users WHERE id = ?',
    'SELECT * FROM users WHERE user_id = ?',
    'appdb'
    );

添加两个新规则后,执行以下语句使其生效:

CALL query_rewrite.flush_rewrite_rules();

Rewriter使用第一条规则匹配使用限定表名的语句,第二条规则匹配使用未限定名称的语句。只有当appdb是默认数据库时,第二条规则才有效。

语句匹配原理

Rewriter插件使用语句摘要和摘要哈希值来在各个阶段匹配传入语句与重写规则。max_digest_length系统变量确定用于计算语句摘要的缓冲区大小。较大的值可以计算出区分较长语句的摘要。较小的值使用更少的内存,但增加了较长语句与相同摘要值发生冲突的可能性。

该插件将每个语句与重写规则进行匹配:

  1. 计算语句摘要哈希值并将其与规则摘要哈希值进行比较。这可能会产生误报,但可以作为快速拒绝测试。

  2. 如果语句摘要哈希值与任何模式摘要哈希值匹配,则将语句的规范形式(语句摘要)与匹配规则模式的规范形式进行匹配。

  3. 如果规范语句与规则匹配,则比较语句和模式中的文字值。模式中的?字符匹配语句中的任何文字值。如果语句准备了一个语句,则模式中的?也匹配语句中的?。否则,相应的文字值必须相同。

如果多个规则匹配一个语句,则插件使用哪个规则重写语句是不确定的。

如果模式包含的标记比替换多,插件会丢弃多余的数据值。如果模式包含的标记比替换少,这将是一个错误。当加载规则表时,插件会注意到这一点,将错误消息写入规则行的message列以传达问题,并将Rewriter_reload_error状态变量设置为ON

重写预处理语句

预处理语句在解析时(即在准备时)重写,而不是在稍后执行时。

预处理语句与非预处理语句的区别在于,它们可能包含?字符作为参数标记。要匹配预处理语句中的?Rewriter模式必须在相同位置包含?。假设重写规则具有以下模式:

SELECT ?, 3

以下表格显示了几个预处理SELECT语句以及规则模式是否匹配它们。

预处理语句 匹配语句的模式是否匹配
PREPARE s AS 'SELECT 3, 3'
PREPARE s AS 'SELECT ?, 3'
PREPARE s AS 'SELECT 3, ?'
PREPARE s AS 'SELECT ?, ?'
重写插件操作信息

Rewriter插件通过几个状态变量提供有关其操作的信息:

mysql> SHOW GLOBAL STATUS LIKE 'Rewriter%';
+-----------------------------------+-------+
| Variable_name                     | Value |
+-----------------------------------+-------+
| Rewriter_number_loaded_rules      | 1     |
| Rewriter_number_reloads           | 5     |
| Rewriter_number_rewritten_queries | 1     |
| Rewriter_reload_error             | ON    |
+-----------------------------------+-------+

有关这些变量的描述,请参阅 Section 7.6.4.3.4, “Rewriter Query Rewrite Plugin Status Variables”。

当通过调用flush_rewrite_rules()存储过程加载规则表时,如果某个规则出现错误,则CALL语句会产生错误,并且插件将Rewriter_reload_error状态变量设置为ON

mysql> CALL query_rewrite.flush_rewrite_rules();
ERROR 1644 (45000): Loading of some rule(s) failed. 
mysql> SHOW GLOBAL STATUS LIKE 'Rewriter_reload_error';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Rewriter_reload_error | ON    |
+-----------------------+-------+

在这种情况下,检查rewrite_rules表中具有非NULL message列值的行,以查看存在哪些问题。

重写插件使用字符集

rewrite_rules表加载到Rewriter插件中时,插件使用当前全局值的character_set_client系统变量解释语句。如果随后更改了全局character_set_client值,则必须重新加载规则表。

客户端必须具有与加载规则表时全局值相同的会话character_set_client值,否则该客户端的规则匹配将无法工作。

原文:dev.mysql.com/doc/refman/8.0/en/rewriter-query-rewrite-plugin-reference.html

7.6.4.3 Rewriter查询重写插件参考

以下讨论作为与Rewriter查询重写插件相关的这些元素的参考:

  • query_rewrite数据库中的Rewriter规则表

  • Rewriter过程和函数

  • Rewriter系统和状态变量

7.6.4.3.1 Rewriter查询重写插件规则表

query_rewrite数据库中的rewrite_rules表为Rewriter插件提供了规则的持久存储,用于决定是否重写语句。

用户通过修改存储在此表中的规则集与插件进行通信。插件通过设置表的message列向用户传递信息。

注意

通过flush_rewrite_rules存储过程将规则表加载到插件中。除非在最近的表修改后调用了该过程,否则表内容不一定对应插件正在使用的规则集。

rewrite_rules表具有以下列:

  • id

    规则 ID。此列是表的主键。您可以使用 ID 唯一标识任何规则。

  • pattern

    指示规则匹配语句模式的模板。使用?表示匹配数据值的参数标记。

  • pattern_database

    用于匹配语句中未限定表名的数据库。语句中的限定表名仅在默认数据库与pattern_database相同且表名相同时,才与模式中的限定名称匹配。语句中的未限定表名仅在默认数据库与pattern_database相同且表名相同时,才与模式中的未限定名称匹配。

  • replacement

    指示如何重写与pattern列值匹配的语句的模板。使用?表示匹配数据值的参数标记。在重写的语句中,插件使用replacement中的?参数标记,使用与pattern中相应标记匹配的数据值进行替换。

  • enabled

    是否启用规则。加载操作(通过调用flush_rewrite_rules()存储过程执行)仅在此列为YES时,将规则从表加载到Rewriter内存缓存中。

    此列使得可以在不移除规则的情况下停用规则:将列设置为非YES的值,并重新加载表到插件中。

  • message

    插件使用此列与用户进行通信。如果在将规则表加载到内存时没有发生错误,则插件将message列设置为NULL。非NULL值表示错误,列内容为错误消息。错误可能发生在以下情况下:

    • 要么模式,要么替换是产生语法错误的不正确 SQL 语句。

    • 替换包含比模式更多的?参数标记。

    如果发生加载错误,插件还会将Rewriter_reload_error状态变量设置为ON

  • pattern_digest

    此列用于调试和诊断。如果在将规则表加载到内存时存在该列,则插件将使用模式摘要更新它。如果您试图确定某个语句未能重写的原因,此列可能会有用。

  • normalized_pattern

    此列用于调试和诊断。如果在将规则表加载到内存时存在该列,则插件将使用模式的规范形式更新它。如果您试图确定某个语句未能重写的原因,此列可能会有用。

7.6.4.3.2 Rewriter 查询重写插件的过程和函数

Rewriter插件操作使用一个存储过程,将规则表加载到其内存缓存中,并使用一个辅助可加载函数。在正常操作下,用户只调用存储过程。该函数旨在由存储过程调用,而不是直接由用户调用。

  • flush_rewrite_rules()

    此存储过程使用load_rewrite_rules()函数将rewrite_rules表的内容加载到Rewriter内存缓存中。

    调用flush_rewrite_rules()意味着COMMIT

    在修改规则表后调用此存储过程,使插件从新表内容更新其缓存。如果发生任何错误,插件将为表中适当规则行设置message列,并将Rewriter_reload_error状态变量设置为ON

  • load_rewrite_rules()

    此函数是由flush_rewrite_rules()存储过程使用的辅助程序。

7.6.4.3.3 Rewriter 查询重写插件系统变量

Rewriter查询重写插件支持以下系统变量。仅当安装了插件时才可用这些变量(请参阅第 7.6.4.1 节,“安装或卸载 Rewriter 查询重写插件”)。

  • rewriter_enabled

    系统变量 rewriter_enabled
    范围 全局
    动态
    SET_VAR提示适用
    类型 布尔值
    默认值 ON
    有效值 OFF

    是否启用了Rewriter查询重写插件。

  • rewriter_enabled_for_threads_without_privilege_checks

    引入版本 8.0.31
    系统变量 rewriter_enabled_for_threads_without_privilege_checks
    作用域 全局
    动态
    SET_VAR 提示适用
    类型 布尔值
    默认值 ON
    有效值 OFF

    是否应用于执行时禁用权限检查的复制线程的重写。如果设置为OFF,则跳过此类重写。需要SYSTEM_VARIABLES_ADMIN权限或SUPER权限来设置。

    如果rewriter_enabledOFF,则此变量无效。

  • rewriter_verbose

    系统变量 rewriter_verbose
    作用域 全局
    动态
    SET_VAR 提示适用
    类型 整数

    供内部使用。

7.6.4.3.4 Rewriter 查询重写插件状态变量

Rewriter查询重写插件支持以下状态变量。仅当插件已安装时才可用(请参阅第 7.6.4.1 节,“安装或卸载 Rewriter 查询重写插件”)。

  • Rewriter_number_loaded_rules

    成功从rewrite_rules表加载到内存中供Rewriter插件使用的重写插件重写规则数量。

  • Rewriter_number_reloads

    rewrite_rules表被加载到Rewriter插件使用的内存缓存中的次数。

  • Rewriter_number_rewritten_queries

    Rewriter查询重写插件自加载以来重写的查询次数。

  • Rewriter_reload_error

    上次将rewrite_rules表加载到Rewriter插件使用的内存缓存中时是否发生错误。如果值为OFF,则未发生错误。如果值为ON,则发生了错误;请检查rewriter_rules表的message列以获取错误消息。

7.6.5 ddl_rewriter 插件

原文:dev.mysql.com/doc/refman/8.0/en/ddl-rewriter.html

7.6.5.1 安装或卸载 ddl_rewriter

7.6.5.2 ddl_rewriter 插件选项

MySQL 8.0.16 及更高版本包括一个ddl_rewriter插件,该插件在服务器解析和执行之前修改接收到的CREATE TABLE语句。该插件删除ENCRYPTIONDATA DIRECTORYINDEX DIRECTORY子句,这在从加密数据库或将表存储在数据目录之外的数据库创建的 SQL 转储文件中恢复表时可能会有所帮助。例如,该插件可以使这些转储文件能够恢复到未加密实例或在路径在数据目录之外不可访问的环境中。

在使用ddl_rewriter插件之前,请根据第 7.6.5.1 节“安装或卸载 ddl_rewriter”中提供的说明进行安装。

ddl_rewriter在服务器解析之前检查接收到的 SQL 语句,根据这些条件对其进行重写:

  • ddl_rewriter仅考虑CREATE TABLE语句,只有当它们是独立的语句,并且出现在输入行的开头或准备语句文本的开头时。ddl_rewriter不考虑存储程序定义中的CREATE TABLE语句。语句可以跨越多行。

  • 在进行重写考虑的语句中,以下子句的实例将被重写,并且每个实例将被单个空格替换:

    • ENCRYPTION

    • DATA DIRECTORY(在表和分区级别)

    • INDEX DIRECTORY(在表和分区级别)

  • 重写不依赖于大小写。

如果ddl_rewriter重写了一个语句,它会生成一个警告:

mysql> CREATE TABLE t (i INT) DATA DIRECTORY '/var/mysql/data';
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> SHOW WARNINGS\G
*************************** 1\. row ***************************
  Level: Note
   Code: 1105
Message: Query 'CREATE TABLE t (i INT) DATA DIRECTORY '/var/mysql/data''
         rewritten to 'CREATE TABLE t (i INT) ' by a query rewrite plugin 1 row in set (0.00 sec)

如果启用了一般查询日志或二进制日志,服务器会在任何ddl_rewriter重写后将语句写入其中。

安装后,ddl_rewriter会为跟踪插件内存使用情况暴露性能模式memory/rewriter/ddl_rewriter。请参阅第 29.12.20.10 节“内存摘要表”

原文:dev.mysql.com/doc/refman/8.0/en/ddl-rewriter-installation.html

7.6.5.1 安装或卸载 ddl_rewriter

本节描述了如何安装或卸载ddl_rewriter插件。有关安装插件的一般信息,请参见 Section 7.6.1,“安装和卸载插件”。

注意

如果安装了ddl_rewriter插件,即使禁用了,也会涉及一些最小的开销。为避免这种开销,只在打算使用它的期间安装ddl_rewriter

主要用例是修改从转储文件中恢复的语句,因此典型的使用模式是:1)安装插件;2)恢复转储文件或文件;3)卸载插件。

要被服务器使用,插件库文件必须位于 MySQL 插件目录中(由plugin_dir系统变量命名的目录)。如有必要,在服务器启动时通过设置plugin_dir的值来配置插件目录位置。

插件库文件基本名称为ddl_rewriter。文件名后缀因平台而异(例如,Unix 和类 Unix 系统为.so,Windows 为.dll)。

要安装ddl_rewriter插件,请使用INSTALL PLUGIN语句,根据需要调整您平台的.so后缀:

INSTALL PLUGIN ddl_rewriter SONAME 'ddl_rewriter.so';

要验证插件安装,请检查信息模式PLUGINS表或使用SHOW PLUGINS语句(参见 Section 7.6.2,“获取服务器插件信息”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_TYPE
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME LIKE 'ddl%';
+--------------+---------------+-------------+
| PLUGIN_NAME  | PLUGIN_STATUS | PLUGIN_TYPE |
+--------------+---------------+-------------+
| ddl_rewriter | ACTIVE        | AUDIT       |
+--------------+---------------+-------------+

如前述结果所示,ddl_rewriter被实现为审计插件。

如果插件初始化失败,请检查服务器错误日志以获取诊断消息。

一旦按照上述描述安装,ddl_rewriter将保持安装状态,直到卸载。要删除它,请使用UNINSTALL PLUGIN

UNINSTALL PLUGIN ddl_rewriter;

如果安装了ddl_rewriter,您可以使用--ddl-rewriter选项来控制后续服务器启动时ddl_rewriter插件的激活。例如,要防止插件在运行时启用,请使用此选项:

[mysqld]
ddl-rewriter=OFF

原文:dev.mysql.com/doc/refman/8.0/en/ddl-rewriter-options.html

7.6.5.2 ddl_rewriter 插件选项

本节描述了控制ddl_rewriter插件操作的命令选项。如果在启动时指定的值不正确,则ddl_rewriter插件可能无法正确初始化,服务器也不会加载它。

要控制ddl_rewriter插件的激活,请使用此选项:

  • --ddl-rewriter[=*value*]

    命令行格式 --ddl-rewriter[=value]
    引入版本 8.0.16
    类型 枚举
    默认值 ON
    有效值 ON``OFF``FORCE``FORCE_PLUS_PERMANENT

    此选项控制服务器在启动时如何加载ddl_rewriter插件。仅当插件先前已通过INSTALL PLUGIN注册或通过--plugin-load--plugin-load-add加载时才可用。参见 Section 7.6.5.1, “Installing or Uninstalling ddl_rewriter”。

    选项值应为插件加载选项中可用的值之一,如 Section 7.6.1, “Installing and Uninstalling Plugins”中所述。例如,--ddl-rewriter=OFF可在服务器启动时禁用插件。

7.6.6 版本标记

原文:dev.mysql.com/doc/refman/8.0/en/version-tokens.html

7.6.6.1 版本标记元素

7.6.6.2 安装或卸载版本标记

7.6.6.3 使用版本标记

7.6.6.4 版本标记参考

MySQL 包括版本标记,这是一个功能,可以创建和围绕服务器标记进行同步,应用程序可以使用这些标记来防止访问不正确或过时的数据。

版本标记接口具有以下特征:

  • 版本标记是由一个作为键或标识符的名称和一个值组成的对。

  • 版本标记可以被锁定。应用程序可以使用标记锁定来指示其他合作应用程序正在使用标记,不应该被修改。

  • 版本标记列表是针对每个服务器建立的(例如,用于指定服务器分配或操作状态)。此外,与服务器通信的应用程序可以注册其自己的标记列表,指示其需要服务器处于的状态。应用程序向未处于所需状态的服务器发送的 SQL 语句会产生错误。这是一个信号,告诉应用程序应该寻找一个处于所需状态的不同服务器来接收 SQL 语句。

以下各节描述了版本标记的元素,讨论了如何安装和使用它,并为其元素提供了参考信息。

原文:dev.mysql.com/doc/refman/8.0/en/version-tokens-elements.html

7.6.6.1 版本令牌元素

版本令牌基于一个实现以下元素的插件库:

  • 一个名为version_tokens的服务器端插件保存与服务器关联的版本令牌列表,并订阅语句执行事件的通知。version_tokens插件使用审计插件 API 来监视来自客户端的传入语句,并将每个客户端的会话特定版本令牌列表与服务器版本令牌列表进行匹配。如果匹配成功,插件允许语句通过,服务器继续处理。否则,插件向客户端返回错误,语句失败。

  • 一组可加载函数提供了一个 SQL 级 API,用于操作和检查插件维护的服务器版本令牌列表。调用任何版本令牌函数都需要VERSION_TOKEN_ADMIN权限(或已弃用的SUPER权限)。

  • version_tokens插件加载时,它定义了VERSION_TOKEN_ADMIN动态权限。这个权限可以授予函数的用户。

  • 一个系统变量使客户端能够指定注册所需服务器状态的版本令牌列表。如果服务器在客户端发送语句时处于不同状态,则客户端会收到错误。

原文:dev.mysql.com/doc/refman/8.0/en/version-tokens-installation.html

7.6.6.2 安装或卸载版本标记

注意

如果安装了版本标记,会涉及一些开销。为避免这种开销,请不要安装它,除非您打算使用它。

本节描述了如何安装或卸载版本标记(Version Tokens),它是在一个包含插件和可加载函数的插件库文件中实现的。有关安装或卸载插件和可加载函数的一般信息,请参见第 7.6.1 节,“安装和卸载插件”,以及第 7.7.1 节,“安装和卸载可加载函数”。

要使服务器可用,插件库文件必须位于 MySQL 插件目录中(由plugin_dir系统变量命名的目录)。如有必要,在服务器启动时通过设置plugin_dir的值来配置插件目录位置。

插件库文件基本名称为version_tokens。文件名后缀因平台而异(例如,对于 Unix 和类 Unix 系统,为.so,对于 Windows 为.dll)。

要安装版本标记插件和函数,请使用INSTALL PLUGINCREATE FUNCTION语句,根据需要调整平台的.so后缀:

INSTALL PLUGIN version_tokens SONAME 'version_token.so';
CREATE FUNCTION version_tokens_set RETURNS STRING
  SONAME 'version_token.so';
CREATE FUNCTION version_tokens_show RETURNS STRING
  SONAME 'version_token.so';
CREATE FUNCTION version_tokens_edit RETURNS STRING
  SONAME 'version_token.so';
CREATE FUNCTION version_tokens_delete RETURNS STRING
  SONAME 'version_token.so';
CREATE FUNCTION version_tokens_lock_shared RETURNS INT
  SONAME 'version_token.so';
CREATE FUNCTION version_tokens_lock_exclusive RETURNS INT
  SONAME 'version_token.so';
CREATE FUNCTION version_tokens_unlock RETURNS INT
  SONAME 'version_token.so';

您必须安装用于管理服务器版本标记列表的函数,但也必须安装插件,因为没有插件,函数无法正常工作。

如果插件和函数在复制源服务器上使用,请在所有副本服务器上安装它们,以避免复制问题。

一旦按照上述方式安装,插件和函数将保持安装状态直到卸载。要移除它们,请使用UNINSTALL PLUGINDROP FUNCTION语句:

UNINSTALL PLUGIN version_tokens;
DROP FUNCTION version_tokens_set;
DROP FUNCTION version_tokens_show;
DROP FUNCTION version_tokens_edit;
DROP FUNCTION version_tokens_delete;
DROP FUNCTION version_tokens_lock_shared;
DROP FUNCTION version_tokens_lock_exclusive;
DROP FUNCTION version_tokens_unlock;

原文:dev.mysql.com/doc/refman/8.0/en/version-tokens-usage.html

7.6.6.3 使用版本令牌

在使用版本令牌之前,请根据第 7.6.6.2 节,“安装或卸载版本令牌”中提供的说明进行安装。

版本令牌可以派上用场的一个场景是访问一组 MySQL 服务器的系统,但需要通过监视它们并根据负载变化调整服务器分配来进行负载平衡管理。这样的系统包括以下元素:

  • 要管理的 MySQL 服务器集合。

  • 与服务器通信并将其组织成高可用性组的管理或管理应用程序。组具有不同的目的,每个组内的服务器可能具有不同的分配。某个组内服务器的分配可以随时更改。

  • 客户端应用程序访问服务器以检索和更新数据,根据分配给它们的目的选择服务器。例如,客户端不应向只读服务器发送更新。

版本令牌允许根据分配管理服务器访问,而无需客户端反复查询服务器的分配情况:

  • 管理应用程序执行服务器分配并在每个服务器上建立版本令牌以反映其分配。该应用程序缓存此信息以提供对其的集中访问点。

    如果管理应用程序在某个时刻需要更改服务器分配(例如,将其从允许写入更改为只读),则更改服务器的版本令牌列表并更新其缓存。

  • 为了提高性能,客户端应用程序从管理应用程序获取缓存信息,使它们无需为每个语句检索有关服务器分配的信息。根据其发出的语句类型(例如,读取与写入),客户端选择适当的服务器并连接到它。

  • 此外,客户端向服务器发送自己的客户端特定版本令牌,以注册其对服务器所需的分配。对于客户端发送给服务器的每个语句,服务器将其自己的令牌列表与客户端令牌列表进行比较。如果服务器令牌列表包含客户端令牌列表中具有相同值的所有令牌,则存在匹配项,服务器执行该语句。

    另一方面,也许管理应用程序已更改了服务器分配及其版本令牌列表。在这种情况下,新的服务器分配现在可能与客户端要求不兼容。服务器和客户端令牌列表之间存在令牌不匹配,并且服务器在回复语句中返回错误。这是向客户端指示从管理应用程序缓存中刷新其版本令牌信息,并选择一个新服务器进行通信的迹象。

用于检测版本令牌错误并选择新服务器的客户端端逻辑可以以不同的方式实现:

  • 客户端可以自行处理所有版本令牌注册、不匹配检测和连接切换。

  • 这些操作的逻辑可以在一个连接器中实现,该连接器管理客户端和 MySQL 服务器之间的连接。这样的连接器可能会自行处理不匹配错误检测和语句重发,或者将错误传递给应用程序,由应用程序重新发送语句。

以下示例以更具体的形式说明了前面的讨论。

当版本令牌在给定服务器上初始化时,服务器的版本令牌列表为空。通过调用函数执行令牌列表维护。调用任何版本令牌函数都需要VERSION_TOKEN_ADMIN权限(或已弃用的SUPER权限),因此预计令牌列表修改将由具有该权限的管理或管理应用程序执行。

假设管理应用程序与一组由客户端查询以访问员工和产品数据库(分别命名为empprod)的服务器通信。所有服务器都被允许处理数据检索语句,但只有一些服务器被允许进行数据库更新。为了在特定于数据库的基础上处理这个问题,管理应用程序在每台服务器上建立了一个版本令牌列表。在给定服务器的令牌列表中,令牌名称代表数据库名称,令牌值为readwrite,取决于数据库必须以只读方式使用还是可以进行读写操作。

客户端应用程序通过设置系统变量注册它们需要服务器匹配的版本令牌列表。变量设置是基于特定客户端的,因此不同的客户端可以注册不同的要求。默认情况下,客户端令牌列表为空,与任何服务器令牌列表匹配。当客户端将其令牌列表设置为非空值时,匹配可能成功或失败,这取决于服务器版本令牌列表。

要为服务器定义版本令牌列表,管理应用程序调用version_tokens_set()函数。(还有用于修改和显示令牌列表的函数,稍后描述。)例如,应用程序可能向三个服务器组发送以下语句:

服务器 1:

mysql> SELECT version_tokens_set('emp=read;prod=read');
+------------------------------------------+
| version_tokens_set('emp=read;prod=read') |
+------------------------------------------+
| 2 version tokens set.                    |
+------------------------------------------+

服务器 2:

mysql> SELECT version_tokens_set('emp=write;prod=read');
+-------------------------------------------+
| version_tokens_set('emp=write;prod=read') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+

服务器 3:

mysql> SELECT version_tokens_set('emp=read;prod=write');
+-------------------------------------------+
| version_tokens_set('emp=read;prod=write') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+

在每种情况下,令牌列表都被指定为以分号分隔的*name*=*value*对的列表。生成的令牌列表值导致以下服务器分配:

  • 任何服务器都接受任一数据库的读取。

  • 只有服务器 2 接受emp数据库的更新。

  • 只有服务器 3 接受prod数据库的更新���

除了为每个服务器分配版本令牌列表外,管理应用程序还维护反映服务器分配的缓存。

在与服务器通信之前,客户端应用程序会联系管理应用程序并检索有关服务器分配的信息。然后客户端根据这些分配选择服务器。假设客户端想在emp数据库上执行读取和写入操作。根据前述分配,只有服务器 2 符合条件。客户端连接到服务器 2 并通过设置其version_tokens_session系统变量在那里注册其服务器要求:

mysql> SET @@SESSION.version_tokens_session = 'emp=write';

对于客户端发送到服务器 2 的后续语句,服务器将比较自己的版本令牌列表与客户端列表,以检查它们是否匹配。如果匹配,则语句正常执行:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4981;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT last_name, first_name FROM emp.employee WHERE id = 4981;
+-----------+------------+
| last_name | first_name |
+-----------+------------+
| Smith     | Abe        |
+-----------+------------+
1 row in set (0.01 sec)

服务器和客户端版本令牌列表之间的差异可能以两种方式发生:

  • version_tokens_session值中的令牌名称不在服务器令牌列表中。在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND错误。

  • version_tokens_session值中的令牌值与服务器令牌列表中相应令牌的值不同。在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_MISMATCH错误。

只要服务器 2 的分配不改变,客户端就会继续将其用于读取和写入。但假设管理应用程序想要更改服务器分配,以便将emp数据库的写入操作发送到服务器 1 而不是服务器 2。为此,它使用version_tokens_edit()来修改两个服务器上的emp令牌值(并更新其服务器分配的缓存):

服务器 1:

mysql> SELECT version_tokens_edit('emp=write');
+----------------------------------+
| version_tokens_edit('emp=write') |
+----------------------------------+
| 1 version tokens updated.        |
+----------------------------------+

服务器 2:

mysql> SELECT version_tokens_edit('emp=read');
+---------------------------------+
| version_tokens_edit('emp=read') |
+---------------------------------+
| 1 version tokens updated.       |
+---------------------------------+

version_tokens_edit() 修改服务器令牌列表中命名的令牌,并保持其他令牌不变。

下次客户端向服务器 2 发送语句时,其自身的令牌列表不再与服务器令牌列表匹配,将会发生错误:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4982;
ERROR 3136 (42000): Version token mismatch for emp. Correct value read

在这种情况下,客户端应联系管理应用程序以获取关于服务器分配的更新信息,选择一个新服务器,并将失败的语句发送到新服务器。

注意

每个客户端必须通过仅发送符合其向特定服务器注册的令牌列表的语句来与版本令牌合作。例如,如果客户端注册了一个令牌列表为'emp=read',那么版本令牌中没有任何内容可以阻止客户端发送对emp数据库的更新。客户端必须自行避免这样做。

对于从客户端接收的每个语句,服务器隐式使用锁定,如下所示:

  • 对于客户端令牌列表中命名的每个令牌(即在version_tokens_session值中),获取共享锁。

  • 执行服务器和客户端令牌列表之间的比较

  • 根据比较结果执行语句或产生错误

  • 释放锁

服务器使用共享锁,以便进行多个会话的比较而不会阻塞,同时防止任何尝试在操作具有相同名称的令牌之前获取独占锁的会话对令牌进行更改。

前面的示例仅使用了版本令牌插件库中包含的一些函数,但还有其他函数。一组函数允许操作和检查服务器的版本令牌列表。另一组函数允许锁定和解锁版本令牌。

这些函数允许创建、更改、删除和检查服务器的版本令牌列表:

  • version_tokens_set() 完全替换当前列表并分配新列表。参数是一个以分号分隔的*name*=*value*对列表。

  • version_tokens_edit() 允许对当前列表进行部分修改。它可以添加新令牌或更改现有令牌的值。参数是一个以分号分隔的*name*=*value*对列表。

  • version_tokens_delete() 从当前列表中删除令牌。参数是一个以分号分隔的令牌名称列表。

  • version_tokens_show() 显示当前令牌列表。它不需要参数。

如果成功,这些函数中的每一个都会返回一个指示发生了什么操作的二进制字符串。以下示例建立了服务器令牌列表,通过添加新令牌对其进行修改,删除一些令牌,并显示生成的令牌列表:

mysql> SELECT version_tokens_set('tok1=a;tok2=b');
+-------------------------------------+
| version_tokens_set('tok1=a;tok2=b') |
+-------------------------------------+
| 2 version tokens set.               |
+-------------------------------------+
mysql> SELECT version_tokens_edit('tok3=c');
+-------------------------------+
| version_tokens_edit('tok3=c') |
+-------------------------------+
| 1 version tokens updated.     |
+-------------------------------+
mysql> SELECT version_tokens_delete('tok2;tok1');
+------------------------------------+
| version_tokens_delete('tok2;tok1') |
+------------------------------------+
| 2 version tokens deleted.          |
+------------------------------------+
mysql> SELECT version_tokens_show();
+-----------------------+
| version_tokens_show() |
+-----------------------+
| tok3=c;               |
+-----------------------+

如果令牌列表格式不正确,则会出现警告:

mysql> SELECT version_tokens_set('tok1=a; =c');
+----------------------------------+
| version_tokens_set('tok1=a; =c') |
+----------------------------------+
| 1 version tokens set.            |
+----------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1\. row ***************************
  Level: Warning
   Code: 42000
Message: Invalid version token pair encountered. The list provided
         is only partially updated. 1 row in set (0.00 sec)

如前所述,版本令牌是使用分号分隔的*名称*=**对定义的。考虑这个version_tokens_set()的调用:

mysql> SELECT version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4')
+---------------------------------------------------------------+
| version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4') |
+---------------------------------------------------------------+
| 3 version tokens set.                                         |
+---------------------------------------------------------------+

版本令牌解释参数如下:

  • 名称和值周围的空格将被忽略。允许名称和值内部的空格。(对于version_tokens_delete(),它接受没有值的名称列表,名称周围的空格将被忽略。)

  • 没有引用机制。

  • 令牌的顺序不重要,除非令牌列表包含给定令牌名称的多个实例,最后一个值优先于先前的值。

根据这些规则,前面的version_tokens_set()调用会导致一个包含两个令牌的令牌列表:tok1的值为1'2 3"4tok2的值为a = b。要验证这一点,请调用version_tokens_show()

mysql> SELECT version_tokens_show();
+--------------------------+
| version_tokens_show()    |
+--------------------------+
| tok2=a = b;tok1=1'2 3"4; |
+--------------------------+

如果令牌列表包含两个令牌,为什么version_tokens_set()返回值为3 version tokens set?这是因为原始令牌列表包含了两个tok1的定义,第二个定义替换了第一个。

版本令牌的令牌操作函数对令牌名称和值施加了以下约束:

  • 令牌名称不能包含=��字符,最大长度为 64 个字符。

  • 令牌值不能包含字符。值的长度受max_allowed_packet系统变量值的限制。

  • 版本令牌将令牌名称和值视为二进制字符串,因此比较区分大小写。

版本令牌还包括一组函数,使令牌可以被锁定和解锁:

  • version_tokens_lock_exclusive()获取独占版本令牌锁。它接受一个或多个锁名称列表和一个超时值。

  • version_tokens_lock_shared()获取共享版本令牌锁。它接受一个或多个锁名称列表和一个超时值。

  • version_tokens_unlock()释放版本令牌锁(独占和共享)。它不接受参数。

每个锁定函数返回非零值表示成功。否则,将发生错误:

mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 0);
+-------------------------------------------------+
| version_tokens_lock_shared('lock1', 'lock2', 0) |
+-------------------------------------------------+
|                                               1 |
+-------------------------------------------------+

mysql> SELECT version_tokens_lock_shared(NULL, 0);
ERROR 3131 (42000): Incorrect locking service lock name '(null)'.

使用版本令牌锁定函数进行锁定是建议性的;应用程序必须同意合作。

可以锁定不存在的令牌名称。这不会创建令牌。

注意

版本令牌锁定函数基于第 7.6.9.1 节,“锁定服务”中描述的锁定服务,并且对于共享和独占锁具有相同的语义。(版本令牌使用内置于服务器中的锁定服务例程,而不是锁定服务函数接口,因此不需要安装这些函数来使用版本令牌。)版本令牌获取的锁使用 version_token_locks 的锁定服务命名空间。可以使用性能模式监视锁定服务锁,因此对于版本令牌锁也是如此。有关详细信息,请参见锁定服务监控。

对于版本令牌锁定函数,令牌名称参数将按照指定的方式使用。周围的空白不会被忽略,=; 字符是允许的。这是因为版本令牌只是将要锁定的令牌名称原样传递给锁定服务。

原文:dev.mysql.com/doc/refman/8.0/en/version-tokens-reference.html

7.6.6.4 版本标记参考

以下讨论作为这些版本标记元素的参考:

版本标记函数

版本标记插件库包含多个函数。一组函数允许操作和检查服务器的版本标记列表。另一组函数允许锁定和解锁版本标记。调用任何版本标记函数都需要VERSION_TOKEN_ADMIN权限(或已弃用的SUPER权限)。

以下函数允许创建、更改、删除和检查服务器的版本标记列表。对name_listtoken_list参数的解释(包括空格处理)如第 7.6.6.3 节“使用版本标记”所述,该节提供了关于指定标记语法的详细信息,以及额外的示例。

  • version_tokens_delete(*name_list*)

    使用name_list参数从服务器的版本标记列表中删除标记,并返回指示操作结果的二进制字符串。name_list是一个以分号分隔的版本标记名称列表,用于删除。

    mysql> SELECT version_tokens_delete('tok1;tok3');
    +------------------------------------+
    | version_tokens_delete('tok1;tok3') |
    +------------------------------------+
    | 2 version tokens deleted.          |
    +------------------------------------+
    

    NULL参数被视为空字符串,对标记列表没有影响。

    version_tokens_delete() 删除其参数中命名的标记(如果存在)。(删除不存在的标记不会报错。)要清除标记列表而不知道列表中有哪些标记,可以传递NULL或一个不包含任何标记的字符串给version_tokens_set()

    mysql> SELECT version_tokens_set(NULL);
    +------------------------------+
    | version_tokens_set(NULL)     |
    +------------------------------+
    | Version tokens list cleared. |
    +------------------------------+
    mysql> SELECT version_tokens_set('');
    +------------------------------+
    | version_tokens_set('')       |
    +------------------------------+
    | Version tokens list cleared. |
    +------------------------------+
    
  • version_tokens_edit(*token_list*)

    使用token_list参数修改服务器的版本标记列表,并返回指示操作结果的二进制字符串。token_list是一个以分号分隔的*name*=*value*对列表,指定要定义的每个标记的名称及其值。如果标记存在,则其值将使用给定值更新。如果标记不存在,则将使用给定值创建标记。如果参数为NULL或一个不包含任何标记的字符串,则标记列表保持不变。

    mysql> SELECT version_tokens_set('tok1=value1;tok2=value2');
    +-----------------------------------------------+
    | version_tokens_set('tok1=value1;tok2=value2') |
    +-----------------------------------------------+
    | 2 version tokens set.                         |
    +-----------------------------------------------+
    mysql> SELECT version_tokens_edit('tok2=new_value2;tok3=new_value3');
    +--------------------------------------------------------+
    | version_tokens_edit('tok2=new_value2;tok3=new_value3') |
    +--------------------------------------------------------+
    | 2 version tokens updated.                              |
    +--------------------------------------------------------+
    
  • version_tokens_set(*token_list*)

    token_list参数中定义的令牌替换服务器的版本令牌列表,并返回指示操作结果的二进制字符串。token_list是一个以分号分隔的*name*=*value*对列表,指定要定义的每个令牌的名称及其值。如果参数为NULL或包含零个令牌的字符串,则清除令牌列表。

    mysql> SELECT version_tokens_set('tok1=value1;tok2=value2');
    +-----------------------------------------------+
    | version_tokens_set('tok1=value1;tok2=value2') |
    +-----------------------------------------------+
    | 2 version tokens set.                         |
    +-----------------------------------------------+
    
  • version_tokens_show()

    将服务器的版本令牌列表作为包含以分号分隔的*name*=*value*对列表的二进制字符串返回。

    mysql> SELECT version_tokens_show();
    +--------------------------+
    | version_tokens_show()    |
    +--------------------------+
    | tok2=value2;tok1=value1; |
    +--------------------------+
    

以下函数允许锁定和解锁版本令牌:

  • version_tokens_lock_exclusive(*token_name*[, *token_name*] ..., *timeout*)

    获取由名称指定为字符串的一个或多个版本令牌的独占锁,在给定的超时值内超时并出现错误,如果在给定的超时值内未获得锁。

    mysql> SELECT version_tokens_lock_exclusive('lock1', 'lock2', 10);
    +-----------------------------------------------------+
    | version_tokens_lock_exclusive('lock1', 'lock2', 10) |
    +-----------------------------------------------------+
    |                                                   1 |
    +-----------------------------------------------------+
    
  • version_tokens_lock_shared(*token_name*[, *token_name*] ..., *timeout*)

    获取由名称指定为字符串的一个或多个版本令牌的共享锁,在给定的超时值内超时并出现错误,如果在给定的超时值内未获得锁。

    mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 10);
    +--------------------------------------------------+
    | version_tokens_lock_shared('lock1', 'lock2', 10) |
    +--------------------------------------------------+
    |                                                1 |
    +--------------------------------------------------+
    
  • version_tokens_unlock()

    释放使用version_tokens_lock_exclusive()version_tokens_lock_shared()在当前会话中获取的所有锁。

    mysql> SELECT version_tokens_unlock();
    +-------------------------+
    | version_tokens_unlock() |
    +-------------------------+
    |                       1 |
    +-------------------------+
    

锁定函数具有以下特征:

  • 返回值为非零表示成功。否则,将发生错误。

  • 令牌名称为字符串。

  • 与操作服务器令牌列表的函数的参数处理相反,不会忽略围绕令牌名称参数的空白,并且允许使用=;字符。

  • 可以锁定不存在的令牌名称。这不会创建令牌。

  • 超时值是表示在超时前等待获取锁的时间(以秒为单位)的非负整数。如果超时为 0,则不会等待,如果无法立即获取锁,则函数会产生错误。

  • 版本令牌锁定函数基于第 7.6.9.1 节,“锁定服务”中描述的锁定服务。

版本令牌系统变量

版本令牌支持以下系统变量。除非安装了版本令牌插件(请参阅第 7.6.6.2 节,“安装或卸载版本令牌”),否则这些变量不可用。

系统变量:

  • version_tokens_session

    命令行格式 --version-tokens-session=value
    系统变量 version_tokens_session
    范围 全局,会话
    动态
    SET_VAR提示适用
    类型 字符串
    默认值 NULL

    此变量的会话值指定客户端版本令牌列表,并指示客户端会话需要服务器版本令牌列表具有的令牌。

    如果version_tokens_session变量为NULL(默认值)或具有空值,则任何服务器版本令牌列表都匹配。(实际上,空值会禁用匹配要求。)

    如果version_tokens_session变量具有非空值,则会导致会话发送到服务器的任何语句的值与服务器版本令牌列表不匹配时出错。在以下情况下会发生不匹配:

    • version_tokens_session值中的令牌名称不在服务器令牌列表中。在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND错误。

    • version_tokens_session值中的令牌值与服务器令牌列表中相应令牌的值不同。在这种情况下,会发生ER_VTOKEN_PLUGIN_TOKEN_MISMATCH错误。

    服务器版本令牌列表包含一个未在version_tokens_session值中命名的令牌并不构成不匹配。

    假设一个管理应用程序已将服务器令牌列表设置如下:

    mysql> SELECT version_tokens_set('tok1=a;tok2=b;tok3=c');
    +--------------------------------------------+
    | version_tokens_set('tok1=a;tok2=b;tok3=c') |
    +--------------------------------------------+
    | 3 version tokens set.                      |
    +--------------------------------------------+
    

    客户端通过设置其version_tokens_session值来注册服务器需要匹配的令牌。然后,对于客户端发送的每个后续语句,服务器会将其令牌列表与客户端version_tokens_session值进行比较,如果不匹配则产生错误:

    mysql> SET @@SESSION.version_tokens_session = 'tok1=a;tok2=b';
    mysql> SELECT 1;
    +---+
    | 1 |
    +---+
    | 1 |
    +---+
    
    mysql> SET @@SESSION.version_tokens_session = 'tok1=b';
    mysql> SELECT 1;
    ERROR 3136 (42000): Version token mismatch for tok1\. Correct value a
    

    第一个SELECT成功,因为客户端令牌tok1tok2存在于服务器令牌列表中,并且每个令牌在服务器列表中具有相同的值。第二个SELECT失败,因为虽然tok1存在于服务器令牌列表中,但其值与客户端指定的值不同。

    此时,除非服务器令牌列表发生变化以匹配,否则客户端发送的任何语句都会失败。假设管理应用程序将服务器令牌列表更改如下:

    mysql> SELECT version_tokens_edit('tok1=b');
    +-------------------------------+
    | version_tokens_edit('tok1=b') |
    +-------------------------------+
    | 1 version tokens updated.     |
    +-------------------------------+
    mysql> SELECT version_tokens_show();
    +-----------------------+
    | version_tokens_show() |
    +-----------------------+
    | tok3=c;tok1=b;tok2=b; |
    +-----------------------+
    

    现在客户端的version_tokens_session值与服务器令牌列表匹配,客户端可以再次成功执行语句:

    mysql> SELECT 1;
    +---+
    | 1 |
    +---+
    | 1 |
    +---+
    
  • version_tokens_session_number

    命令行格式 --version-tokens-session-number=#
    系统变量 version_tokens_session_number
    范围 全局,会话
    动态
    SET_VAR提示适用
    类型 整数
    默认值 0

    此变量仅供内部使用。

7.6.7 克隆插件

原文:dev.mysql.com/doc/refman/8.0/en/clone-plugin.html

7.6.7.1 安装克隆插件

7.6.7.2 本地克隆数据

7.6.7.3 克隆远程数据

7.6.7.4 克隆和并发 DDL

7.6.7.5 克隆加密数据

7.6.7.6 克隆压缩数据

7.6.7.7 用于复制的克隆

7.6.7.8 克隆操作期间创建的目录和文件

7.6.7.9 处理远程克隆操作失败

7.6.7.10 监控克隆操作

7.6.7.11 停止克隆操作

7.6.7.12 克隆系统变量参考

7.6.7.13 克隆系统变量

7.6.7.14 克隆插件限制

克隆插件,引入于 MySQL 8.0.17,允许在本地或从远程 MySQL 服务器实例克隆数据。克隆数据是存储在 InnoDB 中的数据的物理快照,包括模式、表、表空间和数据字典元数据。克隆数据包括一个完全功能的数据目录,允许使用克隆插件进行 MySQL 服务器的配置。

图 7.1 本地克隆操作

CLONE LOCAL 语句将本地 MySQL 服务器实例上的数据目录克隆到另一个本地目录,称为克隆目录。

本地克隆操作将数据从启动克隆操作的 MySQL 服务器实例克隆到运行 MySQL 服务器实例的同一服务器或节点上的目录。

图 7.2 远程克隆操作

从本地接收方 MySQL 服务器实例发出的 CLONE INSTANCE 语句将远程捐赠方 MySQL 服务器实例上的数据目录克隆到本地接收方 MySQL 服务器实例上的数据目录。

远程克隆操作涉及本地 MySQL 服务器实例(“接收方”),在该实例上启动克隆操作,并远程 MySQL 服务器实例(“捐赠方”),源数据位于该实例上。当在接收方上启动远程克隆操作时,克隆数据通过网络从捐赠方传输到接收方。默认情况下,远程克隆操作会在从捐赠方克隆数据之前,从接收方数据目录中删除现有的用户创建的数据(模式、表、表空间)和二进制日志。可选地,您可以将数据克隆到接收方的不同目录,以避免从当前接收方数据目录中删除数据。

通过本地克隆操作克隆的数据与通过远程克隆操作克隆的数据没有任何区别。这两种操作都会克隆相同的数据集。

克隆插件支持复制。除了克隆数据外,克隆操作还会从捐赠者中提取和传输复制坐标,并在接收者上应用这些坐标,从而使克隆插件能够为配置组复制成员和副本提供服务。使用克隆插件进行配置比复制大量事务要快得多且更有效(请参阅第 7.6.7.7 节,“用于复制的克隆”)。组复制成员还可以配置为使用克隆插件作为恢复的替代方法,以便成员自动选择从种子成员检索组数据的最有效方式。有关更多信息,请参阅第 20.5.4.2 节,“用于分布式恢复的克隆”。

克隆插件支持克隆加密和页面压缩的数据。请参阅第 7.6.7.5 节,“克隆加密数据”,以及第 7.6.7.6 节,“克隆压缩数据”。

在使用克隆插件之前,必须先安装它。有关安装说明,请参阅第 7.6.7.1 节,“安装克隆插件”。有关克隆说明,请参阅第 7.6.7.2 节,“本地数据克隆”,以及第 7.6.7.3 节,“远程数据克隆”。

提供了用于监视克隆操作的性能模式表和工具。请参阅第 7.6.7.10 节,“监视克隆操作”。

原文:dev.mysql.com/doc/refman/8.0/en/clone-plugin-installation.html

7.6.7.1 安装克隆插件

本节描述了如何安装和配置克隆插件。对于远程克隆操作,克隆插件必须安装在捐赠者和接收者 MySQL 服务器实例上。

有关安装或卸载插件的一般信息,请参见 Section 7.6.1, “Installing and Uninstalling Plugins”。

要使服务器可用,插件库文件必须位于 MySQL 插件目录中(由 plugin_dir 系统变量命名的目录)。如有必要,在服务器启动时设置 plugin_dir 的值,告诉服务器插件目录的位置。

插件库文件基本名称为 mysql_clone.so。文件名后缀因平台而异(例如,Unix 和类 Unix 系统使用 .so,Windows 使用 .dll)。

要在服务器启动时加载插件,请使用 --plugin-load-add 选项命名包含插件的库文件。使用此插件加载方法,每次服务器启动时都必须提供该选项。例如,将以下行放入您的 my.cnf 文件中,根据需要调整插件库文件名扩展名以适应您的平台。(插件库文件名扩展名取决于您的平台。Unix 和类 Unix 系统通常使用 .so,Windows 使用 .dll。)

[mysqld]
plugin-load-add=mysql_clone.so

修改 my.cnf 后,重新启动服务器以使新设置生效。

注意

--plugin-load-add 选项在升级过程中重新启动服务器时无法用于加载克隆插件。例如,在从先前的 MySQL 版本升级到 MySQL 8.0 后,尝试使用 plugin-load-add=mysql_clone.so 重新启动服务器会导致以下错误:[ERROR] [MY-013238] [Server] Error installing plugin 'clone': Cannot install during upgrade。解决方法是在尝试使用 plugin-load-add=mysql_clone.so 启动服务器之前先升级服务器。

或者,要在运行时加载插件,请使用以下语句,根据需要调整平台的 .so 后缀:

INSTALL PLUGIN clone SONAME 'mysql_clone.so';

INSTALL PLUGIN 加载插件,并在 mysql.plugins 系统表中注册,以使插件在每次正常服务器启动时自动加载,无需 --plugin-load-add

要验证插件安装情况,请检查信息模式PLUGINS表,或者使用SHOW PLUGINS语句(参见 Section 7.6.2, “Obtaining Server Plugin Information”)。例如:

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
       FROM INFORMATION_SCHEMA.PLUGINS
       WHERE PLUGIN_NAME = 'clone';
+------------------------+---------------+
| PLUGIN_NAME            | PLUGIN_STATUS |
+------------------------+---------------+
| clone                  | ACTIVE        |
+------------------------+---------------+

如果插件初始化失败,请检查服务器错误日志以获取克隆或插件相关的诊断消息。

如果插件之前已经使用INSTALL PLUGIN注册过,或者使用--plugin-load-add加载过,您可以在服务器启动时使用--clone选项来控制插件的激活状态。例如,要在启动时加载插件并防止在运行时被移除,可以使用以下选项:

[mysqld]
plugin-load-add=mysql_clone.so
clone=FORCE_PLUS_PERMANENT

如果您希望防止服务器在没有克隆插件的情况下运行,请使用--clone并设置值为FORCEFORCE_PLUS_PERMANENT,以强制服务器启动失败,如果插件初始化失败。

有关插件激活状态的更多信息,请参阅 Controlling Plugin Activation State。

原文:dev.mysql.com/doc/refman/8.0/en/clone-plugin-local.html

7.6.7.2 本地克隆数据

克隆插件支持以下语法用于本地克隆数据;即从本地 MySQL 数据目录克隆数据到同一服务器或节点上的另一个目录:

CLONE LOCAL DATA DIRECTORY [=] '*clone_dir*';

要使用CLONE语法,必须安装克隆插件。有关安装说明,请参见第 7.6.7.1 节,“安装克隆插件”。

执行CLONE LOCAL DATA DIRECTORY语句需要BACKUP_ADMIN权限。

mysql> GRANT BACKUP_ADMIN ON *.* TO '*clone_user*';

其中*clone_user*是执行克隆操作的 MySQL 用户。您选择执行克隆操作的用户可以是具有BACKUP_ADMIN权限的任何 MySQL 用户。

以下示例演示了本地克隆数据的操作:

mysql> CLONE LOCAL DATA DIRECTORY = '*/path/to/clone_dir*';

其中/path/to/clone_dir是数据被克隆到的本地目录的完整路径。需要绝对路径,并且指定的目录(“clone_dir”)不得存在,但指定路径必须是一个已存在的路径。MySQL 服务器必须具有必要的写访问权限以创建目录。

注意

本地克隆操作不支持克隆存储在数据目录之外的用户创建的表或表空间。尝试克隆这样的表或表空间会导致以下错误:ERROR 1086 (HY000): File '/path/to/tablespace_name.ibd' already exists. 尝试克隆具有与源表空间相同路径的表空间会导致冲突,因此被禁止。

所有其他用户创建的InnoDB表和表空间,InnoDB系统表空间,重做日志和撤销表空间都会被克隆到指定目录。

如果需要,您可以在克隆操作完成后在克隆目录上启动 MySQL 服务器。

$> mysqld_safe --datadir=*clone_dir*

其中clone_dir是数据被克隆到的目录。

有关监视克隆操作状态和进度的信息,请参见第 7.6.7.10 节,“监视克隆操作”。

原文:dev.mysql.com/doc/refman/8.0/en/clone-plugin-remote.html

7.6.7.3 克隆远程数据

克隆插件支持以下语法用于克隆远程数据;即从远程 MySQL 服务器实例(捐赠者)克隆数据并将其传输到发起克隆操作的 MySQL 实例(接收方)。

CLONE INSTANCE FROM '*user*'@'*host*':*port*
IDENTIFIED BY '*password*'
[DATA DIRECTORY [=] '*clone_dir*']
[REQUIRE [NO] SSL];

其中:

  • *user*是在捐赠者 MySQL 服务器实例上的克隆用户。

  • *password**user*的密码。

  • *host*是捐赠者 MySQL 服务器实例的主机名地址。不支持 Internet 协议版本 6(IPv6)地址格式。可以使用 IPv6 地址的别名。IPv4 地址可以直接使用。

  • *port*是捐赠者 MySQL 服务器实例的端口号。(不支持由mysqlx_port指定的 X 协议端口。也不支持通过 MySQL 路由器连接到捐赠者 MySQL 服务器实例。)

  • DATA DIRECTORY [=] '*clone_dir*'是一个可选子句,用于指定您正在克隆的数据在接收方的目录。如果不想从接收方数据目录中删除现有的用户创建数据(模式、表、表空间)和二进制日志,则使用此选项。需要绝对路径,并且目录不能存在。MySQL 服务器必须具有必要的写访问权限以创建目录。

    当不使用可选的DATA DIRECTORY [=] '*clone_dir*'子句时,克隆操作会从接收方数据目录中删除用户创建的数据(模式、表、表空间)和二进制日志,将新数据克隆到接收方数据目录,并在之后自动重新启动服务器。

  • [REQUIRE [NO] SSL]明确指定在通过网络传输克隆数据时是否使用加密连接。如果无法满足明确规定,将返回错误。如果未指定 SSL 子句,默认情况下,克隆尝试建立加密连接,如果安全连接尝试失败,则退回到不安全连接。无论是否指定了此子句,克隆加密数据时都需要安全连接。有关更多信息,请参见为克隆配置加密连接。

注意

默认情况下,位于捐赠者 MySQL 服务器实例数据目录中的用户创建的InnoDB表和表空间将被克隆到接收者 MySQL 服务器实例的数据目录中。如果指定了DATA DIRECTORY [=] '*clone_dir*'子句,则它们将被克隆到指定目录。

用户创建的InnoDB表和表空间,如果位于捐赠 MySQL 服务器实例上的数据目录之外,则会被克隆到接收 MySQL 服务器实例上的相同路径。如果表或表空间已经存在,则会报告错误。

默认情况下,InnoDB系统表空间、重做日志和撤销表空间会被克隆到在捐赠端配置的相同位置(由innodb_data_home_dirinnodb_data_file_pathinnodb_log_group_home_dirinnodb_undo_directory定义)。如果指定了DATA DIRECTORY [=] '*clone_dir*'子句,则这些表空间和日志会被克隆到指定目录。

远程克隆先决条件

要执行克隆操作,克隆插件必须在捐赠端和接收端的 MySQL 服务器实例上处于活动状态。有关安装说明,请参阅 Section 7.6.7.1, “Installing the Clone Plugin”。

在捐赠端和接收端需要一个 MySQL 用户来执行克隆操作(“克隆用户”)。

  • 在捐赠端,克隆用户需要BACKUP_ADMIN权限,以便在克隆操作期间访问和传输来自捐赠端的数据,并阻止并发的 DDL。在 MySQL 8.0.27 之前,克隆操作期间会在捐赠端阻止并发的 DDL。从 MySQL 8.0.27 开始,默认情况下在捐赠端允许并发的 DDL。请参阅 Section 7.6.7.4, “Cloning and Concurrent DDL”。

  • 在接收端,克隆用户需要CLONE_ADMIN权限来替换接收端数据,在克隆操作期间阻止 DDL,并自动重新启动服务器。CLONE_ADMIN权限隐含包括BACKUP_ADMINSHUTDOWN权限。

包括创建克隆用户和授予所需权限的说明在接下来的远程克隆示例中。

当执行CLONE INSTANCE语句时,会检查以下先决条件:

  • 克隆插件在 MySQL 8.0.17 及更高版本中受支持。捐赠端和接收端必须是相同的 MySQL 服务器系列,例如 8.0.37 和 8.0.41。在 8.0.37 之前的版本中,它们必须是相同的点发布版本。

    mysql> SHOW VARIABLES LIKE 'version';
     +---------------+--------+
    | Variable_name | Value  |
    +---------------+--------+
    | version       | 8.0.36 |
    +---------------+--------+
    

    从捐赠 MySQL 服务器实例克隆到相同版本和发布版本的热修复 MySQL 服务器实例在 MySQL 8.0.26 中得到支持。

    从系列内不同的点发布版本克隆是从 MySQL 8.0.37 开始支持的。对于早于 8.0.37 的版本,仍然适用先前的限制。例如,不允许将 8.0.36 克隆到 8.0.42 或反之亦然。

  • 捐赠者和接收方 MySQL 服务器实例必须在相同的操作系统和平台上运行。例如,如果捐赠者实例在 Linux 64 位平台上运行,则接收方实例也必须在该平台上运行。请参考您的操作系统文档以了解如何确定您的操作系统平台。

  • 接收方必须有足够的磁盘空间来存储克隆的数据。默认情况下,在克隆捐赠者数据之前,接收方会删除用户创建的数据(模式、表、表空间)和二进制日志,因此您只需要足够的空间来存储捐赠者数据。如果您使用DATA DIRECTORY子句克隆到命名目录,则必须有足够的磁盘空间来存储现有接收方数据和克隆的数据。您可以通过检查文件系统上的数据目录大小和驻留在数据目录之外的任何表空间的大小来估算数据大小。在估算捐赠者的数据大小时,请记住只有InnoDB数据会被克隆。如果您在其他存储引擎中存储数据,请相应调整数据大小的估算。

  • InnoDB允许在数据目录之外创建一些表空间类型。如果捐赠者 MySQL 服务器实例具有驻留在数据目录之外的表空间,则克隆操作必须能够访问这些表空间。您可以查询信息模式FILES表来识别驻留在数据目录之外的表空间。驻留在数据目录之外的文件具有指向数据目录以外目录的完全限定路径。

    mysql> SELECT FILE_NAME FROM INFORMATION_SCHEMA.FILES;
    
  • 在捐赠者上激活的插件,包括任何密钥环插件,也必须在接收方上激活。您可以通过发出SHOW PLUGINS语句或查询信息模式PLUGINS表来识别活动插件。

  • 捐赠者和接收方必须具有相同的 MySQL 服务器字符集和校对规则。有关 MySQL 服务器字符集和校对规则配置的信息,请参见第 12.15 节,“字符集配置”。

  • 捐赠者和接收者必须具有相同的innodb_page_sizeinnodb_data_file_path设置。捐赠者和接收者的innodb_data_file_path设置必须指定相同数量的等效大小的数据文件。您可以使用SHOW VARIABLES语法检查变量设置。

    mysql> SHOW VARIABLES LIKE 'innodb_page_size';
    mysql> SHOW VARIABLES LIKE 'innodb_data_file_path';
    
  • 如果克隆加密或页面压缩数据,则捐赠者和接收者必须具有相同的文件系统块大小。对于页面压缩数据,接收方文件系统必须支持稀疏文件和孔打孔,以便在接收方上进行孔打孔。有关这些功能以及如何识别使用这些功能的表和表空间的信息,请参见 Section 7.6.7.5,“克隆加密数据”和 Section 7.6.7.6,“克隆压缩数据”。要确定您的文件系统块大小,请参考您的操作系统文档。

  • 如果要克隆加密数据,则需要安全连接。请参见为克隆配置加密连接。

  • 接收方的clone_valid_donor_list设置必须包括捐赠者 MySQL 服务器实例的主机地址。您只能从有效捐赠者列表中的主机克隆数据。需要具有SYSTEM_VARIABLES_ADMIN权限的 MySQL 用户来配置此变量。在本节之后的远程克隆示例中提供了设置clone_valid_donor_list变量的说明。您可以使用SHOW VARIABLES语法检查clone_valid_donor_list设置。

    mysql> SHOW VARIABLES LIKE 'clone_valid_donor_list';
    
  • 不得运行其他克隆操作。一次只允许进行单个克隆操作。要确定是否正在运行克隆操作,请查询clone_status表。请参见使用性能模式克隆表监视克隆操作。

  • 克隆插件以 1MB 数据包加元数据的方式传输数据。因此,捐赠者和接收方 MySQL 服务器实例上最低要求的max_allowed_packet值为 2MB。小于 2MB 的max_allowed_packet值会导致错误。使用以下查询检查您的max_allowed_packet设置:

    mysql> SHOW VARIABLES LIKE 'max_allowed_packet';
    

还有以下先决条件:

  • 捐赠者上的撤销表空间文件名必须是唯一的。当数据克隆到接收方时,无论在捐赠者上的位置如何,撤销表空间都会克隆到接收方的innodb_undo_directory位置或使用DATA DIRECTORY [=] '*clone_dir*'子句指定的目录。由于这个原因,捐赠者上重复的撤销表空间文件名是不允许的。从 MySQL 8.0.18 开始,在克隆操作期间遇到重复的撤销表空间文件名时会报告错误。在 MySQL 8.0.18 之前,克隆具有相同文件名的撤销表空间可能会导致接���方上的撤销表空间文件被覆盖。

    要查看捐赠者上的撤销表空间文件名以确保它们是唯一的,请查询INFORMATION_SCHEMA.FILES

    mysql> SELECT TABLESPACE_NAME, FILE_NAME FROM INFORMATION_SCHEMA.FILES
           WHERE FILE_TYPE LIKE 'UNDO LOG';
    

    有关删除和添加撤销表空间文件的信息,请参见 Section 17.6.3.4,“撤销表空间”。

  • 默认情况下,在数据克隆后,接收方 MySQL 服务器实例会自动重启(停止和启动)。要实现自动重启,接收方必须有一个监控进程来检测服务器的关闭。否则,在数据克隆后,克隆操作会因为以下错误而停止,并且接收方 MySQL 服务器实例会关闭:

    ERROR 3707 (HY000): Restart server failed (mysqld is not managed by supervisor process).
    

    此错误并不表示克隆失败。这意味着在数据克隆后,接收方 MySQL 服务器实例必须手动重新启动。在手动启动服务器后,您可以连接到接收方 MySQL 服务器实例,并检查性能模式克隆表,以验证克隆操作是否成功完成(请参见使用性能模式克隆表监控克隆操作)。RESTART语句也具有相同的监控进程要求。有关更多信息,请参见 Section 15.7.8.8,“RESTART Statement”。如果使用DATA DIRECTORY子句克隆到命名目录,则不适用此要求,因为在这种情况下不会执行自动重启。

  • 几个变量控制远程克隆操作的各个方面。在执行远程克隆操作之前,请查看这些变量并根据需要调整设置以适应您的计算环境。克隆变量设置在执行克隆操作的接收方 MySQL 服务器实例上。请参阅 Section 7.6.7.13, “克隆系统变量”。

克隆远程数据

以下示例演示了克隆远程数据的过程。默认情况下,远程克隆操作会在接收方上删除用户创建的数据(模式、表、表空间)和二进制日志,将新数据克隆到接收方数据目录,并在之后重新启动 MySQL 服务器。

本示例假定远程克隆的先决条件已满足。请参阅远程克隆先决条件。

  1. 使用管理员用户帐户登录到捐赠方 MySQL 服务器实例。

    1. 创建一个具有BACKUP_ADMIN权限的克隆用户。

      mysql> CREATE USER 'donor_clone_user'@'example.donor.host.com' IDENTIFIED BY '*password*';
      mysql> GRANT BACKUP_ADMIN on *.* to 'donor_clone_user'@'example.donor.host.com';
      
    2. 安装克隆插件:

      mysql> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
      
  2. 使用管理员用户帐户登录到接收方 MySQL 服务器实例。

    1. 创建一个具有CLONE_ADMIN权限的克隆用户。

      mysql> CREATE USER 'recipient_clone_user'@'example.recipient.host.com' IDENTIFIED BY '*password*';
      mysql> GRANT CLONE_ADMIN on *.* to 'recipient_clone_user'@'example.recipient.host.com';
      
    2. 安装克隆插件:

      mysql> INSTALL PLUGIN clone SONAME 'mysql_clone.so';
      
    3. 将捐赠方 MySQL 服务器实例的主机地址添加到clone_valid_donor_list变量设置中。

      mysql> SET GLOBAL clone_valid_donor_list = '*example.donor.host.com*:*3306*';
      
  3. 以前创建的克隆用户(recipient_clone_user'@'example.recipient.host.com)登录到接收方 MySQL 服务器实例,并执行CLONE INSTANCE语句。

    mysql> CLONE INSTANCE FROM 'donor_clone_user'@'example.donor.host.com':3306
           IDENTIFIED BY '*password*';
    

    数据克隆完成后,接收方 MySQL 服务器实例将自动重新启动。

    有关监视克隆操作状态和进度的信息,请参见 Section 7.6.7.10, “监视克隆操作”。

克隆到指定目录

默认情况下,远程克隆操作会在克隆数据之前从接收方数据目录中删除用户创建的数据(模式、表、表空间)和二进制日志。通过克隆到指定目录,您可以避免从当前接收方数据目录中删除数据。

克隆到指定目录的过程与克隆远程数据中描述的过程相同,唯一的例外是:CLONE INSTANCE语句必须包含DATA DIRECTORY子句。例如:

mysql> CLONE INSTANCE FROM '*user*'@'*example.donor.host.com*':*3306*
       IDENTIFIED BY '*password*'
       DATA DIRECTORY = '*/path/to/clone_dir*';

需要绝对路径,并且目录不能存在。MySQL 服务器必须具有必要的写访问权限以创建目录。

在克隆到命名目录时,接收方 MySQL 服务器实例在克隆数据后不会自动重新启动。如果要在命名目录上重新启动 MySQL 服务器,则必须手动执行:

$> mysqld_safe --datadir=*/path/to/clone_dir*

其中/path/to/clone_dir是接收方命名目录的路径。

为克隆配置加密连接

您可以配置远程克隆操作的加密连接,以保护在网络上传输时克隆的数据。默认情况下,当克隆加密数据时需要加密连接。(参见第 7.6.7.5 节,“克隆加密数据”。)

接下来的说明描述了如何配置接收方 MySQL 服务器实例以使用加密连接。假定捐赠方 MySQL 服务器实例已配置为使用加密连接。如果没有,请参考第 8.3.1 节,“配置 MySQL 使用加密连接”进行服务器端配置说明。

要配置接收方 MySQL 服务器实例以使用加密连接:

  1. 使捐赠方 MySQL 服务器实例的客户端证书和密钥文件可供接收方主机使用。可以通过安全通道将文件分发到接收方主机,或将它们放在对接收方主机可访问的挂载分区上。要提供的客户端证书和密钥文件包括:

    • ca.pem

      自签名证书颁发机构(CA)文件。

    • client-cert.pem

      客户端公钥证书文件。

    • client-key.pem

      客户端私钥文件。

  2. 在接收方 MySQL 服务器实例上配置以下 SSL 选项。

    • clone_ssl_ca

      指定自签名证书颁发机构(CA)文件的路径。

    • clone_ssl_cert

      指定客户端公钥证书文件的路径。

    • clone_ssl_key

      指定客户端私钥文件的路径。

    例如:

    clone_ssl_ca=/*path*/*to*/ca.pem
    clone_ssl_cert=/*path*/*to*/client-cert.pem
    clone_ssl_key=/*path*/*to*/client-key.pem
    
  3. 要求使用加密连接,请在接收方发出CLONE语句时包含REQUIRE SSL子句。

    mysql> CLONE INSTANCE FROM '*user*'@'*example.donor.host.com*':*3306*
           IDENTIFIED BY '*password*'
           DATA DIRECTORY = '*/path/to/clone_dir*'
           REQUIRE SSL;
    

    如果未指定 SSL 子句,则克隆插件默认尝试建立加密连接,如果加密连接尝试失败,则回退到非加密连接。

    注意

    如果您正在克隆加密数据,则默认情况下需要加密连接,无论是否指定了REQUIRE SSL子句。使用REQUIRE NO SSL会在尝试克隆加密数据时导致错误。

posted @ 2024-06-23 16:24  绝不原创的飞龙  阅读(6)  评论(0编辑  收藏  举报