首页 > 数据库 >麻了,一个操作把MySQL主从复制整崩了

麻了,一个操作把MySQL主从复制整崩了

时间:2023-05-10 18:12:32浏览次数:41  
标签:tmp binlog 主从复制 记录 -- 整崩 mysql MySQL 日志

前言

最近公司某项目上反馈mysql主从复制失败,被运维部门记了一次大过,影响到了项目的验收推进,那么究竟是什么原因导致的呢?而主从复制的原理又是什么呢?本文就对排查分析的过程做一个记录。

主从复制原理

我们先来简单了解下MySQL主从复制的原理。

  1. 主库master 服务器会将 SQL 记录通过 dump 线程写入到 二进制日志binary log 中;
  2. 从库slave 服务器开启一个 io thread 线程向服务器发送请求,向 主库master 请求 binary log。主库master 服务器在接收到请求之后,根据偏移量将新的 binary log 发送给 slave 服务器。
  3. 从库slave 服务器收到新的 binary log 之后,写入到自身的 relay log 中,这就是所谓的中继日志。
  4. 从库slave 服务器,单独开启一个 sql thread 读取 relay log 之后,写入到自身数据中,从而保证主从的数据一致。

以上是MySQL主从复制的简要原理,更多细节不展开讨论了,根据运维反馈,主从复制失败主要在IO线程获取二进制日志bin log超时,一看主数据库的binlog日志竟达到了4个G,正常情况下根据配置应该是不超过300M。

binlog写入机制

想要了解binlog为什么达到4个G,我们来看下binlog的写入机制。

binlog的写入时机也非常简单,事务执行过程中,先把日志写到 binlog cache ,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache

  1. 上图的write,是指把日志写入到文件系统的page cache,并没有把数据持久化到磁盘,所以速度比较快
  2. 上图的fsync,才是将数据持久化到磁盘的操作, 生成binlog日志中

生产上MySQL中binlog中的配置max_binlog_size为250M, 而max_binlog_size是用来控制单个二进制日志大小,当前日志文件大小超过此变量时,执行切换动作。,该设置并不能严格控制Binlog的大小,尤其是binlog比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性,可能不做切换日志的动作,只能将该事务的所有$QL都记录进当前日志,直到事务结束。一般情况下可采取默认值。

所以说怀疑是不是遇到了大事务,因而我们需要看看binlog中的内容具体是哪个事务导致的。

查看binlog日志

我们可以使用mysqlbinlog这个工具来查看下binlog中的内容,具体用法参考官网:https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html

  1. 查看binlog日志
./mysqlbinlog --no-defaults --base64-output=decode-rows -vv /mysqldata/mysql/binlog/mysql-bin.004816|more
  1. 以事务为单位统计binlog日志文件中占用的字节大小
./mysqlbinlog --no-defaults --base64-output=decode-rows -vv /mysqldata/mysql/binlog/mysql-bin.004816|grep GTID -B1|grep '^# at' | awk '{print $3}' | awk 'NR==1 {tmp=$1} NR>1 {print ($1-tmp, tmp, $1); tmp=$1}'|sort -n -r|more

生产中某个事务竟然占用4个G。

  1. 通过start-positionstop-position统计这个事务各个SQL占用字节大小
./mysqlbinlog --no-defaults --base64-output=decode-rows --start-position='xxxx' --stop-position='xxxxx' -vv /mysqldata/mysql/binlog/mysql-bin.004816 |grep '^# at'| awk '{print $3}' | awk 'NR==1 {tmp=$1} NR>1 {print ($1-tmp, tmp, $1); tmp=$1}'|sort -n -r|more

发现最大的一个SQL竟然占用了32M的大小,那超过10M的大概有多少个呢?

  1. 通过超过10M大小的数量
./mysqlbinlog --no-defaults --base64-output=decode-rows --start-position='xxxx' --stop-position='xxxxx' -vv /mysqldata/mysql/binlog/mysql-bin.004816|grep '^# at' | awk '{print $3}' | awk 'NR==1 {tmp=$1} NR>1 {print ($1-tmp, tmp, $1); tmp=$1}'|awk '$1>10000000 {print $0}'|wc -l

统计结果显示竟然有200多个,毛估一下,也有近4个G了

  1. 根据pos, 我们看下究竟是什么SQL导致的
./mysqlbinlog --no-defaults --base64-output=decode-rows --start-position='xxxx' --stop-position='xxxxx' -vv /mysqldata/mysql/binlog/mysql-bin.004816|grep '^# atxxxx' -C5| grep -v '###' | more

根据sql,分析了下,这个表正好有个blob字段,统计了下blob字段总合大概有3个G大小,然后我们业务上有个导入操作,这是一个非常大的事务,会频繁更新这表中记录的更新时间,导致生成binlog非常大。

问题: 明明只是简单的修改更新时间的语句,压根没有动blob字段,为什么生产的binlog这么大?因为生产的binlog采用的是row模式。

binlog的模式

binlog日志记录存在3种模式,而生产使用的是row模式,它最大的特点,是很精确,你更新表中某行的任何一个字段,会记录下整行的内容,这也就是为什么blob字段都被记录到binlog中,导致binlog非常大。此外,binlog还有statementmixed两种模式。

  1. STATEMENT模式 ,基于SQL语句的复制
  • 优点: 不需要记录每一行数据的变化,减少binlog日志量,节约IO,提高性能。
  • 缺点: 由于只记录语句,所以,在statement level下 已经发现了有不少情况会造成MySQL的复制出现问题,主要是修改数据的时候使用了某些定的函数或者功能的时候会出现。
  1. ROW模式,基于行的复制

5.1.5版本的MySQL才开始支持,不记录每条sql语句的上下文信息,仅记录哪条数据被修改了,修改成什么样了。

  • 优点: binlog中可以不记录执行的sql语句的上下文相关的信息,仅仅只需要记录那一条被修改。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。不会出现某些特定的情况下的存储过程或function,以及trigger的调用和触发无法被正确复制的问题
  • 缺点: 所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,会产生大量的日志内容。
  1. MIXED模式

从5.1.8版本开始,MySQL提供了Mixed格式,实际上就是StatementRow的结合。

Mixed模式下,一般的语句修改使用statment格式保存binlog。如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog

总结

最终分析下来,我们定位到原来是由于大事务+blob字段大致binlog非常大,最终我们采用了修改业务代码,将blob字段单独拆到一张表中解决。所以,在设计开发过程中,要尽量避免大事务,同时在数据库建模的时候特别考虑将blob字段独立成表。

欢迎关注个人公众号【JAVA旭阳】交流学习

标签:tmp,binlog,主从复制,记录,--,整崩,mysql,MySQL,日志
From: https://www.cnblogs.com/alvinscript/p/17388821.html

相关文章

  • mysql语句性能优化(一)
    1、对查询进行优化,应尽量避免全表扫描,首先应考虑在where及orderby涉及的列上建立索引2、应尽量避免在where子句中对字段进行null值判断,创建表时NULL是默认值,但大多数时候应该使用NOTNULL,或者使用一个特殊的值,如0,-1作为默认值3、应尽量避免在where子句中使用!=或<>......
  • mysql常用命令
    mysqlAccessdeniedforuserroot@localhost错误解决方法总结,安装后修改密码Mysql初始化root密码和允许远程访问 mysql命令:基本文本的,显示和使用的mysql数据库。前面已经简单的提过用法;比如登录等。mysqladmin命令,用来创建和维护mysql数据库的命令,......
  • MySQL 锁实践
    测试环境为MySQL5.7 隔离级别:REPEATABLE-READ自动提交:autocommitOFF创建测试表:CREATETABLE`t1`(`id`int(11)DEFAULTNULL,`name`varchar(10)DEFAULTNULL)ENGINE=InnoDBDEFAULTCHARSET=latin1insertintot1(id,name)values(1,"mirror");insertintot1......
  • MySQL的随机排序(random orderby)
    MySQL的随机排序(randomorderby)是指在查询数据库时,将结果集以随机的方式排列。这种排序方式可以用于有趣的应用场景,例如实现随机音乐播放、广告推荐等。要实现MySQL的随机排序,可以使用RAND()函数。RAND()函数可以生成0-1之间的随机数,将它作为排序的依据即可。SELECT*FROM`my......
  • 【完结撒花】MySQL(二十三)主从复制
    MySQL(二十三)主从复制1主从复制概述1.1如何提高数据库并发能力在实际工作中,常将Redis和MySQL配合使用,如果有请求的时候,首先在缓存中查找,如果存在就直接取出,不存在再访问数据库,这样就提升了读取的效率,减少了对后端数据库的访问压力,Redis缓存是高并发架构非常重要的一环......
  • mysql中删除时报错Cannot truncate a table referenced in a foreign key constraint
    在Mysql使用Truncate截断表时,提示Cannottruncateatablereferencedinaforeignkeyconstraint(monitoritem,CONSTRAINTmonitortaskpollutant_monitortask_fk)。这是因为存在外键约束导致的无法删除,我们可以先关闭外键约束,删除后再启动外键约束。1、检查外键约束SELE......
  • mysql创建systemd管理项
    vim/usr/lib/systemd/system/mysqld.service写入system配置:[Unit]Description=MySQLServerDocumentation=mysqld##mysql参考手册Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.htmlAfter=network.targetAfter=syslog.target[Install]WantedBy=mul......
  • 服务器配置——mysql安装
    1.安装MySQL打开终端获取root权限suroot下载安装mysql官方YumRepository[root@localhost~]#wget-i-chttp://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpmyum安装 [root@localhost~]#yum-yinstallmysql57-community-release-el7-10.noarch.r......
  • mysql 字段逗号分割行转列操作
    一、需求某字段的值为7654,7698,7782,7788期望的效果: 二、实现语句SELECTSUBSTRING_INDEX(SUBSTRING_INDEX('7654,7698,7782,7788',',',help_topic_id+1),',',-1)ASnumFROMmysql.help_topicWHEREhelp_topic_id<LENGTH('7654,7698,7782,7788......
  • MySQL学习
    1、初始MySQLJavaEE:企业级java开发Web前端(页面:展示,数据!)后台(连接点:连接数据库JDBC,连接前端(控制,控制视图跳转,和给前端传递数据)(Spring等框架实现)数据库(存数据,Txt,Excel,word)1.1、为什么学习数据库1.岗位需求2.现在的世界,大数据时代~,得数据库者的天下3.被迫需求:存数据4.数据......