23怎么保证数据不丢

binlog的写入机制

事务执行过程中,先把日志写到binlog cache,事务提交,binlog cache写入文件。
每个线程分配binlog cache内存,binlog_cache_size控制大小,超过了这个参数规定的大小,就要暂存到磁盘。

sync_binlog

  1. sync_binlog=0的时候,表示每次提交事务都只write(写缓存),不fsync(写磁盘)
  2. sync_binlog=1的时候,表示每次提交事务都会执行 fsync;
  3. sync_binlog=N(N>1) 的时候,表示每次提交事务都write,但累积N个事务后才fsync。

将sync_binlog设置较大值可提升性能,但主机异常重启会丢失binlog
实际业务场景,考虑到丢失日志量的可控性,一般不建议将这个参数设成0,比较常见的是将其设置为100~1000

binlog 是mysql高可用方案的基础:如多节点、半同步、MySQL group replication等

redo log的写入机制

redo log buffer多线程共享,bin log buffer 每个线程一份

redo log三种存储状态

  • redo logbuffer
  • 磁盘pagecache
    write命令 从 redo log buffer 写入pagecache
    不是写入磁盘速度较快
  • 磁盘物理文件
    fsync命令从pagecache 持久化到物理文件
    慢得多

innodb_flush_log_at_trx_commit

  1. 0,事务提交只写入redo log buffer; 后台线程处理 风险:mysql重启会丢失数据
  2. 1,事务提交直接持久化到磁盘; 在事务prepare时就写入磁盘
  3. 2,事务提交只写到page cache; 后台线程处理 风险:断电丢数据

写入时机

  • InnoDB后台线程,每秒一次把redo log buffer中的日志写入page cache,再调动fsync持久化到磁盘
  • redo log buffer占用达到innodb_log_buffer_size一半时,后台线程主动写盘
  • 并行事务提交,顺带将这个事务的redo log buffer持久化到磁盘。

组提交(group commit)机制

MySQL看到的TPS是每秒两万的话,每秒就会写四万次磁盘。但是,用工具测试出来,磁盘能力也就两万左右,怎么能实现两万的TPS?

一次组内fsync提交的redo log越多性能越高

提升binlog组提交的效果

binlog 的write和 fsync间的间隔时间短,导致能集合到一起持久化的 binlog 比较少,因此 binlog 的组提交的效果通常不如redo log的效果好

  1. binlog_group_commit_sync_delay 参数,表示延迟多少微秒后才调用fsync;
  2. binlog_group_commit_sync_no_delay_count 参数,表示累积多少次以后才调用fsync。

WAL机制主要得益于两个方面:

  1. redo log和 binlog顺序写,磁盘的顺序写比随机写速度要快;
  2. 组提交机制,可以大幅度降低磁盘的IOPS消耗。

mysql IO瓶颈优化

  1. 设置 binlog_group_commit_sync_delay 和binlog_group_commit_sync_no_delay_count 参数,减少 binlog 的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。
  2. 将 sync_binlog 设置为大于 1 的值(比较常见是 100~1000)。这样做的风险是,主机掉电时会丢 binlog 日志。
  3. 将 innodb_flush_log_at_trx_commit 设置为 2。这样做的风险是,主机掉电的时候会丢数据。

什么时候会把线上生产库设置成“非双 1”。

  1. 业务高峰期。一般如果有预知的高峰期,DBA 会有预案,把主库设置成“非双 1”。
  2. 备库延迟,为了让备库尽快赶上主库。
  3. 用备份恢复主库的副本,应用binlog的过程,这个跟上一种场景类似。
  4. 批量导入数据的时候。
    一般情况下,把生产库改成“非双 1”配置,是设置
    innodb_flush_logs_at_trx_commit=2、sync_binlog=1000。