prefacio
Recientemente, un proyecto de la empresa reportó que la replicación maestro-esclavo de mysql falló, y fue registrado como un error mayor por parte del departamento de operación y mantenimiento, lo que afectó la aceptación del proyecto, entonces ¿cuál fue la causa? ¿Y cuál es el principio de replicación maestro-esclavo? Este artículo hace un registro del proceso de investigación y análisis.
Principio de replicación maestro-esclavo
Primero comprendamos brevemente el principio de la replicación maestro-esclavo de MySQL.
- El servidor de la biblioteca principal
master
escribirá registros SQL en el registro binario a través dedump
subprocesosbinary log
; slave
Abra unio thread
hilo desde el servidor de la biblioteca para enviar una solicitud al servidor ymaster
una solicitud a la biblioteca principalbinary log
. Después de que elmaster
servidor de la biblioteca principal reciba la solicitud,binary log
enviará alslave
servidor de acuerdo con el desplazamiento.- Después de
slave
recibir una nueva del servidor de la biblioteca , se escribe en su propio registro , que es el llamado registro de retransmisión.binary log
relay log
- Desde el
slave
servidor de la biblioteca, después de abrir unasql thread
lecturarelay log
, escríbala en sus propios datos, para garantizar la coherencia de los datos maestro-esclavo.
Lo anterior es un breve principio de la replicación maestro-esclavo de MySQL, y no se discutirán más detalles.De acuerdo con los comentarios de operación y mantenimiento, la falla de la replicación maestro-esclavo se debe principalmente al tiempo de espera del subproceso IO para obtener el binario log. Es normal ver que el registro de la base de datos maestra ha llegado a bin log
4G binlog
. Bajo las circunstancias, de acuerdo con la configuración, no debe exceder los 300M.
mecanismo de escritura binlog
Para entender binlog
por qué llega a 4G, echemos un vistazo al mecanismo de escritura binlog.
binlog
El tiempo de escritura también es muy simple.Durante la ejecución de la transacción, el registro se escribe primero binlog cache
, y cuando se confirma la transacción, se binlog cache
escribe binlog
en el archivo. Debido a que una transacción binlog
no se puede desensamblar, no importa cuán grande sea la transacción, debe escribirse de una sola vez, por lo que el sistema asignará un bloque de memoria para cada subproceso binlog cache
.
- La figura anterior
write
se refiere a escribir el registro en el sistema de archivospage cache
y no conserva los datos en el disco, por lo que la velocidad es relativamente rápida. - La figura anterior
fsync
es la operación de persistir datos en el disco y generarbinlog
registros
En producción, binlog
la configuración en MySQL max_binlog_size
es 250M, max_binlog_size
pero se usa para controlar el tamaño de un solo registro binario. Cuando el tamaño del archivo de registro actual supera esta variable, se ejecutará la acción de cambio. , esta configuración no puede controlar estrictamente el tamaño del Binlog, especialmente binlog
cuando está cerca del valor máximo y se encuentra con una transacción relativamente grande, para garantizar la integridad de la transacción, es posible que no se realice la acción de cambiar registros, y todos $ QL se registra en el registro actual hasta el final de la transacción. En general, se puede adoptar el valor predeterminado.
Entonces dudamos si hemos encontrado una transacción grande, por lo que necesitamos ver qué transacción causó el contenido en el binlog.
Ver registros binlog
Podemos usar mysqlbinlog
esta herramienta para ver el contenido en el binlog. Para un uso específico, consulte el sitio web oficial: https://dev.mysql.com/doc/refman/8.0/en/mysqlbinlog.html
.
- ver
binlog
registro
./mysqlbinlog --no-defaults --base64-output=decode-rows -vv /mysqldata/mysql/binlog/mysql-bin.004816|more
复制代码
binlog
Estadísticas del tamaño de byte ocupado por el archivo de registro en unidades de transacciones
./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
复制代码
Cierta transacción en producción en realidad ocupa 4 G.
- Pase
start-position
ystop-position
cuente el tamaño de bytes ocupado por cada SQL de esta transacción
./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
复制代码
Se descubrió que el SQL más grande ocupaba 32 millones de tamaño, entonces, ¿cuántos más de 10 millones hay?
- Por el número de más de 10M de tamaño
./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
复制代码
Los resultados estadísticos muestran que hay más de 200, estimaciones brutas, hay casi 4 G
- 根据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
还有statement
和mixed
两种模式。
- STATEMENT模式 ,基于SQL语句的复制
- 优点: 不需要记录每一行数据的变化,减少
binlog
日志量,节约IO,提高性能。 - 缺点: 由于只记录语句,所以,在
statement leve
l下 已经发现了有不少情况会造成MySQL的复制出现问题,主要是修改数据的时候使用了某些定的函数或者功能的时候会出现。
- ROW模式,基于行的复制
5.1.5版本的MySQL才开始支持,不记录每条sql语句的上下文信息,仅记录哪条数据被修改了,修改成什么样了。
- 优点:
binlog
中可以不记录执行的sql语句的上下文相关的信息,仅仅只需要记录那一条被修改。所以rowlevel
的日志内容会非常清楚的记录下每一行数据修改的细节。不会出现某些特定的情况下的存储过程或function
,以及trigger
的调用和触发无法被正确复制的问题 - 缺点: 所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,会产生大量的日志内容。
- MIXED模式
从5.1.8版本开始,MySQL提供了Mixed
格式,实际上就是Statement
与Row
的结合。
在Mixed
模式下,一般的语句修改使用statment
格式保存binlog
。如一些函数,statement
无法完成主从复制的操作,则采用row格式
保存binlog
。
总结
最终分析下来,我们定位到原来是由于大事务+blob字段大致binlog非常大,最终我们采用了修改业务代码,将blob字段单独拆到一张表中解决。所以,在设计开发过程中,要尽量避免大事务,同时在数据库建模的时候特别考虑将blob字段独立成表。
欢迎关注个人公众号【JAVA旭阳】交流学习