MySQL:主从中的slave_max_allowed_packet和max_allowed_packet


简单记录 5.7.22,5.6.25也是如此


简单来说主从通过几个设置

  • DUMP线程读取event的时候,这个受到主库的max_allowed_packet的限制
  • IO线程读取DUMP线程发送的event的时候受到slave_max_allowed_packet的限制
  • SQL线程读取event的时候,受到slave_max_allowed_packet的限制

一、主从中slave_max_allowed_packet的说明

主要设置在函数set_slave_max_allowed_packet下面

  • 控制SQL线程能够读取的event的最大大小,并且默认为1G,不要进行调整这个参数。
函数重载 slave线程读取:
Log_event* Log_event::read_log_event(IO_CACHE* file,
                                     const Format_description_log_event
                                     *description_event,
                                     my_bool crc_check,
                                     read_log_event_filter_function f)
max_size来自如下:
uint log_max_allowed_packet= thd ? slave_max_allowed_packet : ~0U;

  if (data_len > max_size)
  {
    error = "Event too big";
    goto err;
  }
 sql_print_error("Error in Log_event::read_log_event(): "
                    "'%s', data_len: %lu, event_type: %d",
            error,data_len,head[EVENT_TYPE_OFFSET]);

主从报错会出现:

Last_SQL_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: 
the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the
 slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network 
problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or 
slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.

日志会出现:

2021-10-18T07:21:17.431850Z 24 [ERROR] Error in Log_event::read_log_event(): 'Event too big', data_len: 16034, event_type: 30
2021-10-18T07:21:17.431896Z 24 [ERROR] Error reading relay log event for channel '': slave SQL thread aborted because of I/O error
2021-10-18T07:21:17.431919Z 24 [ERROR] Slave SQL for channel '': Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave. Error_code: 1594
2021-10-18T07:21:17.431931Z 24 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'log_bin.000002' position 880125.
  • 控制IO线程能够读取的最大event的大小,因为主库发过来是event
 if (event_len == packet_error)
      {
        uint mysql_error_number= mysql_errno(mysql);
        switch (mysql_error_number) {
        case CR_NET_PACKET_TOO_LARGE:
          sql_print_error("\
Log entry on master is longer than slave_max_allowed_packet (%lu) on \
slave. If the entry is correct, restart the server with a higher value of \
slave_max_allowed_packet",
                         slave_max_allowed_packet);
          mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE,
                     "%s", "Got a packet bigger than 'slave_max_allowed_packet' bytes");
          goto err;

而这个err来自read_event函数的返回值。报错如下:

Log entry on master is longer than slave_max_allowed_packet (1024) on 
slave. If the entry is correct, restart the server with a higher value of 
slave_max_allowed_packet

二、主从中max_allowed_packet的说明

主要控制主库DUMP线程每次读取event的最大大小,但是DUMP线程做了修改每次会修改自身的max_allowed_packet为1G,不会依赖设置的参数max_allowed_packet

Binlog_sender::init
  /* Binary event can be vary large. So set it to max allowed packet. */
  thd->variables.max_allowed_packet= MAX_MAX_ALLOWED_PACKET;

其中MAX_MAX_ALLOWED_PACKET就是一个固定值为1024*1024*1024(1G),如果超过了1G的大小则会报错LOG_READ_TOO_LARGE。

函数重载,dump线程读取:
int Log_event::read_log_event(IO_CACHE* file, String* packet,
                              const Format_description_log_event *fdle,
                              mysql_mutex_t* log_lock,
                              enum_binlog_checksum_alg checksum_alg_arg,
                              const char *log_file_name_arg,
                              bool* is_binlog_active,
                              char *event_header)


 data_len= uint4korr(buf + EVENT_LEN_OFFSET);
  if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
      data_len > max(current_thd->variables.max_allowed_packet,//这个值固定为1G
                     opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
  {
    DBUG_PRINT("error",("data_len is out of bounds. data_len: %lu", data_len));
    result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
         LOG_READ_TOO_LARGE);
    goto end;
  }

报错的时候如下:

Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'log event entry 
exceeded max_allowed_packet; Increase max_allowed_packet on master; the first event '' at 4, the last
event read from '/opt/bin/log_bin.000002' at 1075335, the last byte read from '/opt/bin/log_bin.000002' at
1075354.'

显然event大于1G还是很难的,因为1个event默认是8K左右,如果超过了就会切换event。因此基本就是一行记录大于1G,才可能event的大小大于1G。这个时候可以检查下报错中的the last
event read from '/opt/bin/log_bin.000002' at 1075335的位置,event大小是否超过1G大小。
这个位置来自dump线程每次读取一个event后就会进行更新如下:

  if ((error= Log_event::read_log_event(log_cache, &m_packet, m_fdle.get(), NULL, checksum_alg,
                                        NULL, NULL, header)))
    goto read_error;

  set_last_pos(my_b_tell(log_cache)); //修改这个值

可以看到这是精确的dump线程读取event的位置。

三、关于错误的指定pos

如果错误指定了pos(change master 错误的指定了master_log_file/master_log_pos),则可能导致读取到的data_len过大,同样会导致问题。

Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'log event entry 
exceeded max_allowed_packet; Increase max_allowed_packet on master; the first event '' at 4, the last
event read from '/opt/bin/log_bin.000002' at 1075335, the last byte read from '/opt/bin/log_bin.000002' at
1075354.'

这是因为一旦指定错误pos,那么读取event header将会读错,那么根据偏移量读取的event的长度将会错误,这会导致获取根据偏移量EVENT_LEN_OFFSET获取data_len得到错误的数据。下面是读取event header的函数。

  inline static bool peek_event_header(char *header, IO_CACHE *log_cache)
  {
    DBUG_ENTER("Log_event::peek_event_header");
    if (my_b_read(log_cache, (uchar*) header, LOG_EVENT_MINIMAL_HEADER_LEN))
      DBUG_RETURN(true);
    DBUG_RETURN(false);
  }

四、metalink关于exceeded max_allowed_packet的说明

也就是这个错误:

Got fatal error 1236 from master when reading data from binary log: 'log event entry 
exceeded max_allowed_packet; Increase max_allowed_packet on master;
It is possible that the master simply recorded a statement that was larger than max_allowed_packet 
permitted it to read. However, this is only likely if the connection that created the entry deliberately set a 
larger value, and would be easily solved by simply setting the global max_allowed_packet variable larger
 on the master. On 5.5.26 and later, ensure that the slave_max_allowed_packet variable is large enough.

More likely, the slave has incorrectly received some part of the binary log, and has requested data from 
the incorrect position. If the position does not accurately match the start of a real event in the binary log, it
 will receive a value for the packet length that is essentially nonsense data.

If the following solution does not solve the problem, then the master's error log may be corrupt, 
particularly if it exceeds 4GB in size.

大概操作做如下:
1、改大max_allowed_packet(主库) /slave_max_allowed_packet(从库) 。
2、可能binlog损坏,也可能是指定pos错误了。
3、重做主从,一劳永逸。
4、确实一行数据超过了1G,这实际上不太可能。

如上分析,第一个操作实际上没啥用。因为dump线程的max_allowed_packet是固定1G的,而slave_max_allowed_packet过小,报错是不一样的。

五、mysql|mysqlbinlog

这种滚日志的操作会受到max_packet的影响,并且一个事务包含在一个packet中,日志如下:


image.png

1个事务的binlog超过1G便会报错,可以修改代码放大max packet,但是这可能导致主从问题。

而从io线程的网络包来看dump线程总是发送一个event大小给IO线程,io线程的收包如下:

主库操作:
mysql> insert into packtest values(1,repeat('a',16384));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(2,repeat('a',2000));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(3,repeat('a',2000));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(4,repeat('a',2000));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(5,repeat('a',2000));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(6,repeat('a',16384));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(7,repeat('a',2000));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(8,repeat('a',2000));
Query OK, 1 row affected (0.00 sec)
mysql> insert into packtest values(9,repeat('a',2000));
Query OK, 1 row affected (0.01 sec)
mysql> delete from packtest;
Query OK, 9 rows affected (0.01 sec)

从库IO线程收包情况:
2022-05-23T10:41:37.157736Z 24 [Note] net packet size 16427(第一行)
2022-05-23T10:41:37.159841Z 24 [Note] net packet size 8064(后面四行)
2022-05-23T10:41:37.163692Z 24 [Note] net packet size 16427(第六行)
2022-05-23T10:41:37.164061Z 24 [Note] net packet size 6057(后面三行)


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354