介绍与团队内的同事交流,讨论MySQL数据库系统中的数据安全问题,主要针对MySQL丢失数据、主从不一致、业务级使用的场景它不合适导致主备数据库数据结构不同。本文是根据以上讨论和总结得出的思维导图。思维导图内容显示OSBBU:数据库服务器必须配备BBU,BBU在供电出现问题时为RAID控制器缓存供电。当断电时,BBU电源可以将控制器中的缓存中的数据保存一段时间(取决于BBU型号)。用户只需在BBU电量耗尽前恢复正常供电,即可将缓存中的数据完整写回RAID,避免断电造成数据丢失,防止OS异常断电导致数据无法放入磁盘。禁用缓存,MySQLO_DIRECT模式可以跳过单机pagecache写入数据(1)redologinnodb_flush_log_at_timeout<5.6.6:每秒将redologbuffer中的数据刷新到磁盘>=5.6.6:将数据刷新到磁盘每innodb_flush_log_at_timeout秒(2)binlogsync_binlog=1(3)innodb缓冲区数据的不同刷新方法的图形显示。图片来自hatemysql.com。(4)MySQL数据传输的InnoDB传输路径,图片来自李春hatemysql.com。主从不一致主库insert后回滚,主备库自增主键不一致使用replaceinto操作,导致主备库自增主键不一致setsessionsql_log_bin=0common业务架构中双写“丢失”数据场景(1)slave_skip_counter不合理slave_skip_counter=1slave_skip_counter>1(2)DBCrash,OS正常innodb_flush_log_at_trx_commit=0事务提交时,缓存不刷新,系统刷新频率为1s,所以1s的数据会丢失。innodb_flush_log_at_trx_commit=1当事务提交时,会被flush到磁盘,保证事务是放在磁盘上的,不会丢失数据。innodb_flush_log_at_trx_commit=2事务提交时flush到os缓存,系统不崩溃,数据不丢失。(3)DB正常,OSCrash有BBUinnodb_flush_log_at_trx_commit=0。提交事务时,不会刷新缓存。系统刷新频率为1s,所以1s的数据会丢失。innodb_flush_log_at_trx_commit=1当事务提交时,会被flush到磁盘,保证事务是放在磁盘上的,不会丢失数据。innodb_flush_log_at_trx_commit=2事务提交时flush到os缓存,系统不崩溃,数据不丢失。(4)slave非实时写入redo和binlog丢失数据。从机上会有三个文件来保证事件的正确重放:relaylog、relayloginfo、masterinfo。(5)异步模式事务T1写入binlogbuffer;dumper线程通知slave有一个新的事务T1;binlog缓冲区执行检查点;由于网络不稳定,slave没有收到t1;master挂了,slave被提升为新的master。t1丢失了。(6)semisysncafter_commit例如主库操作updatet1setval=1whereid=10将val从5变为1sessionsession1在主库中提交updatet1setval=1whereid=10;commit;主库将数据持久化到innodb,按照二阶段提交提交日志binlog;将日志同步到slave,等待slave返回ack信息,实际等待时间以rpl_semi_sync_master_timeout为准。若超过设定时间则超时,主库返回写入成功信息给客户端。收到slave的ack信息后,返回成功给OK客户端。分析:在第四步之前,master还没有收到slave的ack信息。此时,由于事务已经提交,所以除了session1之外的其他session都可以看到val=1。主库服务器宕机或主库实例崩溃,此时发生HA切换。主库没有收到从库的ack信息,从库收到日志放到磁盘上,应用了binlog更新。t1.val=1,业务切换到slave时,可以获取到一致的数据。如果slave还没有收到binlog,主库down了,因为主库已经提交了,此时主库t1.val为1,从库t1.val为5,master和backup是不一致。after_sync,例如主库操作updatet1setval=1whereid=10将val从5变为1。sessionsession1在主库中提交:updatet1setval=1whereid=10;commit;主库将事务写入binlog。无需提交,同步binlog到slave。等待slave返回ack信息,实际等待时间以rpl_semi_sync_master_timeout为准,如果超时master转为异步模式。主库收到slave的ack信息后,提交并返回成功给OK客户端。分析:如果在第三步等待slaveack的过程中,主库崩溃(此时t1.val=5),HA切换到slave,应用查询slave。如果slave收到binlog并向master发送ack,则t1.val=1。如果slave响应了主库,但是主库crash了,因为主库还没有提交t1.val=1,slavet1.val=5,但是主库启动恢复后,t1.val会变成5个,master和backup还是一样的。如果slave没有收到事务响应master库,此时t1.val=5,不管是哪个状态,对所有client数据库都是一致的,事务不会丢失。知识点:两阶段提交的第一阶段是先准备,然后同步写redolog,第二阶段同步写binlog,然后commit。如果在写commitflag的时候crash了,恢复enter的时候会重新写commitflag。HA切换(6)主从binlog_formatROW(最安全)MIXED(不推荐)STATEMENT(不推荐)sync_binlog=0:由os系统的刷新机制控制,刷新数据到磁盘的频率=1:刷新到磁盘每隔commit>1:每N次commit都要开启innodb_support_xa版本刷新到磁盘,保证binlog提交的顺序。否则,乱序的binlog会导致recovery或者slaveapply时出现问题,后面会被丢弃。始终支持两阶段提交。crashsafecrash-safe是在InnoDB事务表中保存relay-info.log信息。这时,可以通过执行relaylog中的事务,将relayinfo写在一个事务中来获得原子性保证。这样就避免了执行的binlog站点和relayloginfo中写入的站点信息不一致。IOthreadmaster-info-repository=TABLEsync_master_info=N:每N个事件刷新表SQLthreadrelay-log-info-repository=TABLEsync_relay_info=N:从库宕机时每N个事件刷新表relay-log-recovery,如果relay-log损坏,部分relay-log未处理,所有未执行的relay-log会自动丢弃,重新从master获取日志,保证relay-log的完整性。relay_log_info_repository=TABLErelay_log_recovery=1http://mysqlserverteam.com/relay-log-recovery-when-sql-threads-position-is-unavailable/semi_sync提交后:master将每个事务写入二进制日志并将其保存到磁盘,andCommit(提交)事务,然后将事务发送到从库,开始等待从库的响应。响应后master将结果返回给client,client可以继续。sync后:master将每笔事务写入binarylog并保存在磁盘上,并将事务发送给slave库,开始等待slave的响应。确认slave的响应后,将事务提交(commit)到存储引擎,并将结果返回给客户端,客户端才能继续。GTID相比站点复制,可以降低出现不一致的概率
