23怎么保证数据不丢
binlog的写入机制
事务执行过程中,先把日志写到binlog cache,事务提交,binlog cache写入文件。
每个线程分配binlog cache内存,binlog_cache_size控制大小,超过了这个参数规定的大小,就要暂存到磁盘。
sync_binlog
- sync_binlog=0的时候,表示每次提交事务都只write(写缓存),不fsync(写磁盘)
- sync_binlog=1的时候,表示每次提交事务都会执行 fsync;
- 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
- 0,事务提交只写入redo log buffer; 后台线程处理 风险:mysql重启会丢失数据
- 1,事务提交直接持久化到磁盘; 在事务prepare时就写入磁盘
- 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的效果好
- binlog_group_commit_sync_delay 参数,表示延迟多少微秒后才调用fsync;
- binlog_group_commit_sync_no_delay_count 参数,表示累积多少次以后才调用fsync。
WAL机制主要得益于两个方面:
- redo log和 binlog顺序写,磁盘的顺序写比随机写速度要快;
- 组提交机制,可以大幅度降低磁盘的IOPS消耗。
mysql IO瓶颈优化
- 设置 binlog_group_commit_sync_delay 和binlog_group_commit_sync_no_delay_count 参数,减少 binlog 的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。
- 将 sync_binlog 设置为大于 1 的值(比较常见是 100~1000)。这样做的风险是,主机掉电时会丢 binlog 日志。
- 将 innodb_flush_log_at_trx_commit 设置为 2。这样做的风险是,主机掉电的时候会丢数据。
什么时候会把线上生产库设置成“非双 1”。
- 业务高峰期。一般如果有预知的高峰期,DBA 会有预案,把主库设置成“非双 1”。
- 备库延迟,为了让备库尽快赶上主库。
- 用备份恢复主库的副本,应用binlog的过程,这个跟上一种场景类似。
- 批量导入数据的时候。
一般情况下,把生产库改成“非双 1”配置,是设置
innodb_flush_logs_at_trx_commit=2、sync_binlog=1000。