MySQL Binlog 入门

643次阅读  |  发布于1年以前

什么是 binlog( binary log)

binlog 是一个二进制格式的文件,用于记录用户对数据库更新的 SQL 语句信息,例如更改数据库表和更改内容的 SQL 语句都会记录到 binlog 里,但是对库表等内容的查询不会记录。默认情况下,binlog 日志是二进制格式的,不能使用查看文本工具的命令(比如,cat,vi 等)查看,而使用 mysqlbinlog 解析查看。

Log_name (文件的名称) The name of the file that is being listed. Pos (事件开始位置) The position at which the event occurs. Event_type(事件类型) An identifier that describes the event type. Server_id The server ID of the server on which the event originated. End_log_pos (下个事件开始位置) The position at which the next event begins, which is equal to Pos plus the size of the event. Info(有关事件类型的详细信息) More detailed information about the event type. The format of this information depends on the event type.

为什么要有 binlog

主要作用是用于数据库的主从复制及数据的增量恢复。

主从复制

MySQL 上下分为 SQL 层和引擎层,不同存储引擎中的日志格式是不同的,由于要对多引擎支持,必须在 SQL 层设计逻辑日志以透明化不同存储引擎,而这个逻辑日志就是 binlog 。

当有数据修改请求时,primary 会产生包含该修改操作的 binlog,并发送给 replica,replica 通过回放该 binlog 以执行和 primary 同样的修改。此外还可用于备份点还原。

单纯的 binlog 只能用于归档,不具备 crash-safe 的能力 InnoDB 引擎为了解决 crash-safe,利用 binlog+redo log 实现了 crash-safe 能力

增量恢复

恢复方式:mysql 将保存在 binlog 日志中指定段落区间的 sql 语句逐个重新执行一次。

WAL 技术:Write-Ahead Logging 中文解释为预写日志技术。在 mysql 体现在写操作时不是立刻更新到磁盘,

而是先落在日志系统.

对支持事务的引擎如 InnoDB 而言,必须要提交了事务才会记录 binlog 。binlog 什么时候刷新到磁盘跟参数 sync_binlog 相关。

如果 sync_binlog=0 或 sync_binlog 大于 1,当发生电源故障或操作系统崩溃时,可能有一部分已提交但其 binlog 未被同步到磁盘的事务会被丢失,恢复程序将无法恢复这部分事务.

通过使用 mysqlbinlog 工具来恢复数据

事务 binlog event 写入流程

binlog cache :它是用于缓存 binlog event 的内存,大小由 binlog_cache_size 控制
binlog cache 临时文件:是一个临时磁盘文件,存储由于 binlog cache 不足溢出的 binlog event,该文件名字由 ”ML” 打头,由参数 max_binlog_cache_size 控制该文件大小
binlog file :代表 binglog 文件,由 max_binlog_size 指定大小
binlog event :代表 binlog 中的记录,如 MAP_EVENT/QUERY EVENT/XID EVENT/WRITE EVENT 等

binlog 的写入机制:事务执行的过程中,先把日志写到 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中。大致流程如下:

binlog 写入 cache 和临时文件

bool IO_CACHE_binlog_cache_storage::write(const unsigned char *buffer,
                                          my_off_t length) {
  return my_b_safe_write(&m_io_cache, buffer, length);
}

int my_b_safe_write(IO_CACHE *info, const uchar *Buffer, size_t Count) {
  if (info->type == SEQ_READ_APPEND) return my_b_append(info, Buffer, Count);
  return my_b_write(info, Buffer, Count);
}

// 如果 binlog cache 缓存当前写入的位置加上本次写入的总量大于了 binlog cache的内存地址的边界
// 则我们需要进行通过*(info)->write_function将 binlog cache 的内容写到磁盘了
// 这样才能腾出空间给新的 binlog event 存放。这个回调函数就是_my_b_write。
#define my_b_write(info, Buffer, Count)                         \
  ((info)->write_pos + (Count) <= (info)->write_end             \
       ? (memcpy((info)->write_pos, (Buffer), (size_t)(Count)), \
          ((info)->write_pos += (Count)), 0)                    \
       : (*(info)->write_function)((info), (uchar *)(Buffer), (Count)))

int _my_b_write(IO_CACHE *info, const uchar *Buffer, size_t Count) {
  size_t rest_length, length;
  my_off_t pos_in_file = info->pos_in_file;
  // 如果超过临时文件大小设置,则报错
  if (pos_in_file + info->buffer_length > info->end_of_file) {
    errno = EFBIG;
    set_my_errno(EFBIG);
    return info->error = -1;
  }

  // 首先将 binlog 内容拷贝至内存 cache,将 cache 填满
  rest_length = (size_t)(info->write_end - info->write_pos);
  memcpy(info->write_pos, Buffer, (size_t)rest_length);
  Buffer += rest_length;
  Count -= rest_length;
  info->write_pos += rest_length;

  if (my_b_flush_io_cache(info, 1)) return 1;
  if (Count >= IO_SIZE) { /* Fill first intern buffer */
    length = Count & (size_t) ~(IO_SIZE - 1);
    ...
    if (mysql_file_write(info->file, Buffer, length, info->myflags | MY_NABP))
      return info->error = -1;
    ...
    Count -= length;
    Buffer += length;
    info->pos_in_file += length;
  }
  memcpy(info->write_pos, Buffer, (size_t)Count);
  info->write_pos += Count;
  return 0;
}

总结

通过本篇 binlog 入门了解什么是 binlog 以及 binlog 的基础的使用场景、理解 binlog 日志是如何产生的。

参考资料

Copyright© 2013-2019

京ICP备2023019179号-2