MySQL 在哪些场景下不会写 binlog

背景

在 MySQL 中,慢日志不仅可以记录在文件中,还可以记录在表中。具体是记录在文件还是表中是由/* by yours.tools - online tools website : yours.tools/zh/imageformats.html */ log_output参数决定的。

该参数默认为/* by yours.tools - online tools website : yours.tools/zh/imageformats.html */ FILE,即慢日志默认会记录在文件中。如果参数中包含TABLE,则慢日志还会记录在mysql.slow_log中,而mysql.slow_log使用的是 CSV 存储引擎。

最初研究这一问题,是为了确认在主从复制以及组复制(MGR)环境下,mysql.slow_log表中的慢日志是否会同步到其他节点。

随着分析的深入,发现 MySQL 实际上提供了多种机制和开关,用于确保操作不会写入 binlog。

由于 ROW 格式 是目前最常用的 binlog 格式,本文将从 ROW 模式下 MySQL 判断操作是否写入 binlog 的实现逻辑 入手,逐步引出相关控制开关,并分析它们各自的使用场景。

ROW 格式下判断操作是否写入 binlog 的实现逻辑

在 ROW 格式下,将数据变化记录到 binlog 的核心是在binlog_log_row函数中实现的:

int binlog_log_row(TABLE *table, const uchar *before_record,
                   const uchar *after_record, Log_func *log_func) {
bool error = false;
  THD *const thd = table->in_use;
// 判断当前操作是否需要写入 binlog
if (check_table_binlog_row_based(thd, table)) {
    ...
    if (likely(!(error = write_locked_table_maps(thd)))) {
      boolconst has_trans = thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
                             table->file->has_transactions();
      // 根据操作类型,将行镜像写入 binlog
      error = (*log_func)(thd, table, has_trans, before_record, after_record);
    }
  }

return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
}

首先调用 check_table_binlog_row_based 判断当前操作是否需要写入 binlog,若需要,则会针对不同的操作类型,调用不同的函数来处理。具体来说:

  • INSERT:Write_rows_log_event::binlog_row_logging_function
  • UPDATE:Update_rows_log_event::binlog_row_logging_function
  • DELETE:Delete_rows_log_event::binlog_row_logging_function

接下来,重点看看check_table_binlog_row_based函数的处理逻辑。

static bool check_table_binlog_row_based(THD *thd, TABLE *table) {
if (table->s->cached_row_logging_check == -1) {
    int const check(table->s->tmp_table == NO_TMP_TABLE &&
                    !table->no_replicate &&
                    binlog_filter->db_ok(table->s->db.str));
    table->s->cached_row_logging_check = check;
  }

  assert(table->s->cached_row_logging_check == 0 ||
         table->s->cached_row_logging_check == 1);

return (thd->is_current_stmt_binlog_format_row() &&
          table->s->cached_row_logging_check &&
          (thd->variables.option_bits & OPTION_BIN_LOG) &&
          mysql_bin_log.is_open());
}

要返回 false,只需满足以下任意一个条件:

  • 当前 SQL 语句不能以 ROW 格式记录到 binlog 中:thd->is_current_stmt_binlog_format_row()为 false,例如 DDL 语句。
  • 表不允许写入 binlog:table->s->cached_row_logging_check为 false。
  • 当前线程未启用 binlog:thd->variables.option_bits & OPTION_BIN_LOG为 false。
  • binlog 未打开:mysql_bin_log.is_open() 为 false。

因为第一个条件和第四个条件为 false 的情况并不常见,下面将重点分析table->s->cached_row_logging_checkthd->variables.option_bits & OPTION_BIN_LOG为 false 时的场景。

cached_row_logging_check 为 false 的场景

table->s->cached_row_logging_check的赋值逻辑如下:

  if (table->s->cached_row_logging_check == -1) {
    int const check(table->s->tmp_table == NO_TMP_TABLE &&
                    !table->no_replicate &&
                    binlog_filter->db_ok(table->s->db.str));
    table->s->cached_row_logging_check = check;
  }

要使其为 false,必须满足以下任意一个条件:

  1. 当前表是临时表: table->s->tmp_table == NO_TMP_TABLE为 false。
  2. 库名不满足 --replicate-do-db、--replicate-ignore-db 复制规则:binlog_filter->db_ok(table->s->db.str)为 false。
  3. 表设置了 no_replicate。该属性是在open_table_from_share()函数中根据表的类型和存储引擎能力标志设置的。

no_replicate 的设置逻辑如下:

  if ((share->table_category == TABLE_CATEGORY_LOG) ||
      (share->table_category == TABLE_CATEGORY_RPL_INFO) ||
      (share->table_category == TABLE_CATEGORY_GTID)) {
    outparam->no_replicate = true;
  } else if (outparam->file) {
    const handler::Table_flags flags = outparam->file->ha_table_flags();
    outparam->no_replicate =
        !(flags & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) ||
        (flags & HA_HAS_OWN_BINLOGGING);
  } else {
    outparam->no_replicate = false;
  }

可以看到,no_replicate 会在以下几种情况设置为 true。

一、特殊类别的表。包括:

  • TABLE_CATEGORY_LOG 类别的表,具体包括 mysql.general_log, mysql.slow_log。
  • TABLE_CATEGORY_RPL_INFO 类别的表,具体包括 mysql.slave_relay_log_info,mysql.slave_master_info,mysql.slave_worker_info。
  • TABLE_CATEGORY_GTID 类别的表,具体包括 mysql.gtid_executed。

二、根据存储引擎的能力标志判断。

这些标志是每个存储引擎单独设置的,一般是在m_int_table_flagstable_flags函数中定义的,主要是用来向 Server 层声明:这个存储引擎的表,支持哪些能力/约束。与复制相关的标志有三个:

  • HA_BINLOG_STMT_CAPABLE:支持 STATEMENT 格式 binlog。
  • HA_BINLOG_ROW_CAPABLE:支持 ROW 格式 binlog
  • HA_HAS_OWN_BINLOGGING:该引擎自己管理 binlog(如 NDB Cluster)。

在 MySQL 支持的存储引擎中,只有 perfschema(对应 performance_schema)和 temptable(MySQL 8.0 引入的内部临时表存储引擎,主要用来替代老的 MEMORY/MyISAM 内部临时表)不会设置 HA_BINLOG_STMT_CAPABLE 或 HA_BINLOG_ROW_CAPABLE。

所以,针对 performance_schema 表的操作不会写入 binlog。

# ls mysql-8.4.3/storage/
archive  blackhole  csv  example  federated  heap  innobase  myisam  myisammrg  ndb  perfschema  secondary_engine_mock  temptable

OPTION_BIN_LOG 为 false 的场景

thd->variables保存当前线程的会话级系统变量状态。其中,option_bits 是一个位图(bitmap),用于记录多个线程级选项标志,OPTION_BIN_LOG 则表示是否将当前线程的操作写入 binlog。

以下是几种典型场景。

一、显式关闭会话级 binlog

SET SESSION sql_log_bin = 0;

该参数对应的回调函数是fix_sql_log_bin_after_update

sql_log_bin = 1时,打开 OPTION_BIN_LOG,反之,则清除 OPTION_BIN_LOG。

static bool fix_sql_log_bin_after_update(sys_var *, THD *thd,
                                         enum_var_type type [[maybe_unused]]) {
  assert(type == OPT_SESSION);

  if (thd->variables.sql_log_bin)
    thd->variables.option_bits |= OPTION_BIN_LOG;
  else
    thd->variables.option_bits &= ~OPTION_BIN_LOG;

  return false;
}

二、从库未启用 log_replica_updates

当实例作为从库运行,且未开启 log_replica_updates 时,从库 SQL 线程重放的操作默认不写 binlog。

void set_slave_thread_options(THD *thd) {
  ...
  ulonglong options = thd->variables.option_bits | OPTION_BIG_SELECTS;
  if (opt_log_replica_updates)
    options |= OPTION_BIN_LOG;
  else
    options &= ~OPTION_BIN_LOG;
  ...
}

三、使用Disable_binlog_guard临时关闭 binlog

Disable_binlog_guard用于在特定代码块内临时关闭 binlog,并在离开作用域时自动恢复原状态。

class Disable_binlog_guard {
 public:
explicit Disable_binlog_guard(THD *thd)
      : m_thd(thd),
        m_binlog_disabled(thd->variables.option_bits & OPTION_BIN_LOG) {
    thd->variables.option_bits &= ~OPTION_BIN_LOG;
  }

  ~Disable_binlog_guard() {
    if (m_binlog_disabled) m_thd->variables.option_bits |= OPTION_BIN_LOG;
  }

private:
  THD *const m_thd;
constbool m_binlog_disabled;
};

Disable_binlog_guard 被调用的场景有:

3.1 实例初始化(--initialize

static bool handle_bootstrap_impl(handle_bootstrap_args *args) {
  ...
if (opt_initialize) {
    assert(thd->system_thread == SYSTEM_THREAD_SERVER_INITIALIZE);

    sysd::notify("STATUS=Initialization of MySQL system tables in progress\n");
    
    const Disable_binlog_guard disable_binlog(thd);
    const Disable_sql_log_bin_guard disable_sql_log_bin(thd);

    Compiled_in_command_iterator comp_iter;
    rc = process_iterator(thd, &comp_iter, true);

    thd->system_thread = SYSTEM_THREAD_INIT_FILE;

    sysd::notify("STATUS=Initialization of MySQL system tables ",
                 rc ? "unsuccessful" : "successful", "\n");

    if (rc != 0) {
      returntrue;
    }
  }
  ...
returnfalse;
}

3.2 实例升级

bool upgrade_system_schemas(THD *thd) {
Disable_autocommit_guard autocommit_guard(thd);
  Bootstrap_error_handler bootstrap_error_handler;

Server_option_guard<bool> acl_guard(&opt_noacl, true);
Server_option_guard<bool> general_log_guard(&opt_general_log, false);
Server_option_guard<bool> slow_log_guard(&opt_slow_log, false);
Disable_binlog_guard disable_binlog(thd);
Disable_sql_log_bin_guard disable_sql_log_bin(thd);
  ...
  bootstrap_error_handler.set_log_error(false);
bool err =
      fix_mysql_tables(thd) || fix_sys_schema(thd) || upgrade_help_tables(thd);
if (!err) {
    /*
      Initialize structures necessary for federated server from mysql.servers
      table.
    */
    servers_init(thd);
    err = (DBUG_EVALUATE_IF("force_fix_user_schemas", true,
                            dd::bootstrap::DD_bootstrap_ctx::instance()
                                .is_server_upgrade_from_before(
                                    bootstrap::SERVER_VERSION_80011))
               ? check.check_all_schemas(thd)
               : check.check_system_schemas(thd)) ||
          check.repair_tables(thd) ||
          dd::tables::DD_properties::instance().set(
              thd, "MYSQLD_VERSION_UPGRADED", MYSQL_VERSION_ID);
  }
  ...
return dd::end_transaction(thd, err);
}

3.3 CREATE SERVER, ALTER SERVER 和 DROP SERVER 操作。

3.4 INSTALL COMPONENT, UNINSTALL COMPONENT 操作。

3.5 INSTALL PLUGIN, UNINSTALL PLUGIN 操作。

3.6 一些内部操作,例如 ALTER TABLE 过程中创建/删除临时表、DROP DATABASE 时清理数据库对象、更新数据字典表、后台线程自动更新列直方图。

除了上面介绍的这些场景,通过将 thd->lex->no_write_to_binlog 设置为truethd->lex表示当前 SQL 语句的语法解析上下文),可以在语句级别控制该语句不写入 binlog。

NO_WRITE_TO_BINLOG 为 true 的场景

以下场景会将 no_write_to_binlog 设置为 true。

  1. SHUTDOWN、RESTART 命令。
  2. RESET 系列命令,包括:RESET MASTER, RESET SLAVE, RESET PERSIST。
  3. 显式指定NO_WRITE_TO_BINLOGLOCAL。部分维护类 SQL 命令(OPTIMIZE, ANALYZE, REPAIR, FLUSH)支持在语句中显式指定不写 binlog,如,
OPTIMIZE NO_WRITE_TO_BINLOG TABLE t1;
ANALYZE LOCAL TABLE t1;
REPAIR NO_WRITE_TO_BINLOG TABLE t1;
FLUSH LOCAL PRIVILEGES;

需要注意的是,对于FLUSH命令,即使未显式指定NO_WRITE_TO_BINLOG,以下命令默认也不会写入 binlog:NO_WRITE_TO_BINLOG,FLUSH LOGS、FLUSH BINARY LOGS、FLUSH TABLES WITH READ LOCK、FLUSH TABLES tbl_name ... FOR EXPORT。

总结

虽然上面列举的场景较多,但实际上并不需要大家刻意去记。

简单来说,

  • 凡是 MySQL 内部自动执行的操作(即非用户手动执行的操作),通常不会写入 binlog。 典型场景包括:实例初始化与升级、mysql.slow_log表的写入、数据字典的维护、performance_schema表数据的更新等。

  • 对 mysql 库下的表进行 DML 操作,只要不属于上面提到的特殊类别的表,基本都会写入 binlog。

    但若执行的是 DDL 操作(如 truncate),基本都会写入 binlog。

  • 对 performance_schema 中的表进行 DML、DDL 操作会提示权限不足,即便是用 root 用户执行。但部分表允许执行 truncate 操作,且 truncate 操作不会写入 binlog。

根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
本系统采用微信小程序作为前端交互界面,结合Spring Boot与Vue.js框架实现后端服务及管理后台的构建,形成一套完整的电子商务解决方案。该系统架构支持单一商户独立运营,亦兼容多商户入驻的平台模式,具备高度的灵活性与扩展性。 在技术实现上,后端以Java语言为核心,依托Spring Boot框架提供稳定的业务逻辑处理与数据接口服务;管理后台采用Vue.js进行开发,实现了直观高效的操作界面;前端微信小程序则为用户提供了便捷的移动端购物体验。整套系统各模块间紧密协作,功能链路完整闭环,已通过严格测试与优化,符合商业应用的标准要求。 系统设计注重业务场景的全面覆盖,不仅包含商品展示、交易流程、订单处理等核心电商功能,还集成了会员管理、营销工具、数据统计等辅助模块,能够满足不同规模商户的日常运营需求。其多店铺支持机制允许平台方对入驻商户进行统一管理,同时保障各店铺在品牌展示、商品销售及客户服务方面的独立运作空间。 该解决方案强调代码结构的规范性与可维护性,遵循企业级开发标准,确保了系统的长期稳定运行与后续功能迭代的可行性。整体而言,这是一套技术选型成熟、架构清晰、功能完备且可直接投入商用的电商平台系统。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
<think> 首先,用户的问题是:“我想查找需要MySQL强制生成binlog场景 请问需要MySQL强制生成binlog场景”。这涉及到MySQLbinlog(binary log)的使用场景。 从系统级指令中,我需要: - 使用$...$ 格式的行内数学表达式。 - 独立公式用$$...$$ 格式并单独成段。 - 确保LaTeX语法正确。 - 用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,如[^1]。 - 回答结构清晰,逐步解决问题,保证真实可靠。 用户提供了几个引用: - 引用[1]:解释binlog记录MySQL变化,主从复制异步。 - 引用[2]:介绍binlog模式:statement、row、mixed。 - 引用[3]:关于MySQL表引擎和SHOW TABLE命令。 用户的问题是关于“强制生成binlog场景”,意思是当MySQL可能不生成binlog时,如何强制它生成。binlog默认是启用的,但有些场景下可能被禁用或需要强制生成。 关键点: - binlog用于复制、数据恢复、审计等。 - 默认情况下,如果配置了log_bin=ON,binlog会自动生成。 - “强制生成”可能指的是在特定操作中确保binlog入,如在某些DDL操作或特定配置下。 可能的场景: 1. **主从复制**:binlog是必须的,用于将数据从主库同步到从库。 2. **数据恢复**:使用binlog进行时间点恢复。 3. **审计和日志**:需要binlog记录所有更改。 4. **特定操作**:如当使用某些引擎或设置时,binlog可能不被入,需要强制启用。 从引用[2],binlog模式(statement/row/mixed)会影响生成方式,但不直接涉及强制生成。 用户提到的“强制生成”,可能指的是: - 当log_bin设置为OFF时,如何强制启用。 - 或在某些操作中确保binlog被记录。 常见场景: - **启用binlog**:如果log_bin=OFF,需要设置on来强制生成。 - **使用特定存储引擎**:如MyISAM或InnoDB,binlog行为不同;但现代MySQL通常支持。 - **DDL语句**:如ALTER TABLE,这些操作通常被记录在binlog。 - **复制场景**:在设置主从时,必须确保binlog开启。 - **事务性操作**:对于非事务性引擎,binlog可能不记录某些操作。 在MySQL中,binlog默认是启用的,但如果配置为禁用,需要手动启用。强制生成的场景可能包括: - 当需要高可用性时,确保复制工作。 - 在灾难恢复计划中。 - 当使用某些工具如mysqlbinlog时。 回答结构: 1. 解释binlog的作用。 2. 描述默认行为。 3. 列举需要强制生成binlog场景。 4. 提供如何强制启用或确保生成的步骤。 5. 生成相关问题。 确保使用引用: - 引用[1]提到binlog用于复制。 - 引用[2]提到binlog模式。 - 引用[3]关于表引擎,可能与binlog相关,因为引擎影响binlog行为。 例如: - 在复制场景中,binlog是核心[^1]。 - binlog模式可以是statement、row或mixed[^2]。 - 对于引擎,如InnoDB支持事务,binlog更可靠。 强制生成的场景: 1. **设置主从复制**:必须强制启用binlog。 2. **数据恢复需求**:如使用Point-In-Time Recovery (PITR)。 3. **审计合规**:需要记录所有变化。 4. **特定引擎操作**:如当使用非事务引擎(如MyISAM)时,可能需要确保binlog记录。 5. **当log_bin被禁用**时,手动启用。 如何强制启用: - 在配置文件中设置log_bin=ON。 - 运行时设置,但通常需要重启。 在回答中,自然添加引用。 最后,生成相关问题。 完整回答框架: - 引言:解释binlog。 - 场景列表。 - 如何实现。 - 相关问题。 使用中文。 </think>### MySQL强制生成binlog场景分析 MySQLbinlog(二进制日志)用于记录所有数据库的更改操作(如INSERT、UPDATE、DELETE等),是复制、数据恢复和审计的核心机制[^1]。默认情况下,如果服务器配置了`log_bin=ON`,binlog会自动生成。但在某些场景下,binlog可能被禁用(如`log_bin=OFF`),或者特定操作不被记录,这时需要“强制生成”binlog,即通过配置或命令确保binlog入。以下是需要强制生成binlog的常见场景,基于MySQL的工作原理和实际需求。 #### 1. **主从复制场景** 在主从复制架构中,主库必须生成binlog,以便从库通过读取binlog来同步数据[^1]。如果binlog被禁用,复制将失败。强制生成的场景包括: - **新主库设置**:当提升一个从库为主库时,必须强制启用binlog以确保后续操作被记录。 - **binlog模式切换**:如果使用mixed模式(statement和row混合),某些操作可能不被完整记录;需强制切换到row模式以确保所有数据变化被入[^2]。 - **解决复制延迟**:在高并发环境中,主库可能异步处理binlog入,导致延迟;通过设置`sync_binlog=1`强制每个事务后同步入磁盘,避免数据丢失。 如何强制生成: - 修改配置文件`my.cnf`,添加: ``` log_bin = /path/to/binlog binlog_format = ROW # 强制使用row模式确保所有变化被记录[^2] sync_binlog = 1 # 强制每次事务后同步binlog ``` - 重启MySQL服务生效。 #### 2. **数据恢复与备份场景** binlog用于时间点恢复(Point-In-Time Recovery, PITR),当数据库发生误操作或崩溃时,需基于binlog恢复数据。强制生成的场景包括: - **灾难恢复计划**:在定期备份中,如果binlog未启用,无法恢复备份后的数据;需强制开启binlog作为恢复链的一部分。 - **大事务处理**:对于批量数据操作(如百万级DELETE),默认binlog可能被截断;通过设置`binlog_row_image=FULL`强制记录完整行变化。 - **使用非事务引擎**:如MyISAM引擎不支持事务,binlog可能不记录某些操作;强制切换到事务引擎(如InnoDB)或确保binlog启用[^3]。 如何强制生成: - 运行命令启用binlog(需super权限): ```sql SET GLOBAL log_bin = ON; SET GLOBAL binlog_format = 'ROW'; ``` - 结合工具如`mysqlbinlog`解析binlog进行恢复。 #### 3. **审计与合规性场景** 在需要严格审计数据库操作的场景(如金融或医疗行业),binlog作为操作日志必须强制生成以满足合规要求。场景包括: - **法规遵从**:如GDPR或HIPAA要求记录所有数据变更,如果binlog被禁用,需强制启用。 - **安全审计**:当检测到可疑操作时,临时强制生成binlog以追踪变更历史。 - **DDL操作记录**:ALTER TABLE等DDL语句可能不被某些binlog模式记录;需设置`binlog_format=ROW`强制入[^2]。 如何强制生成: - 在配置文件中添加: ``` log_bin = ON expire_logs_days = 7 # 保留日志天数,避免自动清除 ``` - 使用`SHOW BINARY LOGS`命令验证binlog生成状态[^3]。 #### 4. **特定引擎或配置场景** 存储引擎和服务器配置可能影响binlog生成,需强制干预: - **引擎迁移**:如从MyISAM迁移到InnoDB时,需确保binlog记录迁移过程;使用`ALTER TABLE ... ENGINE=InnoDB`并强制启用binlog[^3]。 - **只读模式下的入**:如果服务器被设置为只读(`read_only=ON`),binlog可能不记录变更;需临时禁用只读模式并强制生成binlog。 - **临时关闭binlog后的恢复**:在维护时可能禁用binlog(如SET SQL_LOG_BIN=0),结束后需强制重新启用。 如何强制生成: - 检查引擎状态: ```sql SHOW TABLE STATUS FROM db_name; -- 确认引擎类型[^3] ``` - 动态设置: ```sql SET SQL_LOG_BIN = 1; -- 强制启用当前会话的binlog入 ``` ### 总结 强制生成binlog的关键是确保`log_bin=ON`,并结合模式(如row格式)和同步设置。这些场景多源于高可用性、数据安全或合规需求。实际操作前,建议备份配置并使用`SHOW VARIABLES LIKE 'log_bin'`验证状态。MySQLbinlog机制虽强大,但需合理配置以避免性能开销[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值