• 1
  • 2
  • 3
  • 4
  • 5
mysql数据库问题 首 页  »  帮助中心  »  数据库  »  mysql数据库问题
mysql :你不懂我,我不怪你
发布日期:2016-4-15 21:4:9

  mysql :你不懂我,我不怪你

  业界的许多问都对mysql 趋之若鹜,甚是喜欢,因为安装包小,小巧玲珑,安装简单、使用简单,比较容易上手,开源,功能强劲、持续改进。但是你却因为不理解她误以为她 “不专一”(主从不一致,其实是可以主从一致的),逐渐对她若离若弃。 她在灯火阑珊处翘首以盼你的蓦然回首,你却冷冷的一笑而过,她只能说:“你不懂我,我不怪你”。其实不怪你才怪。

  下面我就带你去认知mysql carsh_safe replication 的内心世界

  crash-safe replication 定义

  当master/salve 任何一个节点发生宕机等意外情况,服务器重启后master/salve数据 仍然保持一致性。

  包含

  master crash-safe replication

  slave crash-safe replication

  master crash-safe replication

  需要配置3个参数。

  innodb-flush-log-at-trx-commit=1

  sync_binlog=1

  innodb-xa-support=1

  详解:

  master crash-safe replication 只要保证每个提交事务的 重做日志 和其二进制的持久性就ok

  为了保证持久性,所以必须要保证 每提交一个事务 都要 持久化 redo log 到 重做日志文件 以及 bin log 到 二进制日志文件(保证主库传递到从库数据一致性)。并且要确保 每commit 一个事务时 保存2个文件的原子性,由于是不同的文件需要开启分布式事务。

  sync_binlog=1

  每commit 一个事务 保存其二进制日志到二进制文件,保证主库传递到从库数据一致性

  innodb-flush-log-at-trx-commit=1

  每commit 一个事务 都要调用fsync 把其产生的redo log 信息保存到 磁盘上的 重做日志文件上。从而保证事务的持久性。发生故障重启mysql server 通过redo log进行恢复。

  innodb-xa-support=1

  开启分布式事务

  slave crash-safe replication

  需要配置3个参数

  innodb-flush-log-at-trx-commit=1

  relay_log_recovery=on

  relay_log_info_repository=table

  slave 非正常关闭 经常会出现的问题:

  不断的1062 主键冲突错误

  主从数据不一致

  是不是经常碰到slave 宕掉后,复制报1062 主键冲突。可能你会直接执行 SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1 跳过一个错误。为什么想过没有呢 ?小编一向认为 为什么 要比 是什么来的重要,我们要知其然知其所以然,这样才可以避免错误。下面就随俺理理吧

  SQL thrend 主要做2件事

  1: 回放 relay log 中事务信息

  2: 更新 relay_log.info文件里的信息。确保在下次重启服务,让SQL thrend 晓得从那个relay log 文件 的那个位置继续开始回放

  为什么:

  问题就出现在第二个步骤上,跟新 relay_log.info 文件是缓存写,其中 由 参数 sync_relay_log_info 控制写到 relay_log.info文件的时机。其默认值是1000,意思是 每执行10000个 relay log 中的事务才写一次盘。就算是把sync_relay_log_info=1 也是有可能重复执行1个事物的。并且这样频繁的刷盘,会导致系统性能严重下降不可取。

  salve 报 1062 场景实例解析:

  假设 slave 上现在SQL thread 已经回放了95000 个事务,此时的 relay_log.info文件 记录的位置是30500【第90000 个事务位置】那么此时salve 宕机了,重启后 SQL thread 读取 relay_log.info 得到已经执行到 某个 relay log 文件 的30500 位置 即 第90000 个事务位置,然后又重新执行90000-95000 的事务,又因为有主键约束自然就报 主键冲突了。

  主从数据不一致 ,why?

  同样是上面的问题,如果没有主键约束,insert 数据就会重复执行,从库就会多出重新执行的 insert 数据。

  一般 bin log 都是基于row 的, insert 不是幂等的 ,update 是幂等的。幂等:f(x)=f(f(x)) 也就是此时导致master/salve 不一致的都是insert 语句且表中没有主键

  解决方案:

  MySQL 5.6 crash safe :

  relay_log_info_repository=table,relay-info.log的信息保存在InnoDB的事务表

  伪代码:

  BEGIN;

  apply log event;

  apply log event;

  UPDATE mysql.slave_relay_log_info

  SET Master_log_pos = Exec_Master_Log_Pos,

  Master_log_name = Relay_Master_Log_File,

  Relay_log_name = Relay_Log_File,

  Relay_log_pos = Relay_Log_Pos;

  COMMIT

  这样就使得 执行 relay log 中的 log event 与 更新 relay_log.info 都是跟新表并且都在同一个事物中 ,也就保证的原子性。要么都更新,要么都不更新。

  IO thread

  接收binary log event

  更新master-info.log

  缓存写

  sync_master_info

  解决方案

  relay_log_recovery=on

  确保binary log还在master服务器上

  这与SQL thread 一个道理 ,会重复接受binary log event,解决的方法是relay_log_recovery=on 配合 之前的 relay_log_info_repository=table 即每次重启服务IO thread会读取mysql.slave_relay_log_info表中的Master_log_name Master_log_pos 即 IO thread 会重新到master 上从指定 二进制文件 Master_log_name的指定位置Master_log_pos 继续拉数据,前提是master 对应的二进制的文件还在。