MySQL kļūda "Got a packet bigger than 'max_allowed_packet' bytes" nozīmē, ka viena savienojuma puse saņēma vienu ziņojumu, kas lielāks, nekā tai atļauts pieņemt. Šis ziņojums var būt viens SQL vaicājums, viena rezultāta rinda vai viens binārā žurnāla notikums ceļā uz repliku. MySQL to atsaka un aizver savienojumu. Risinājums gandrīz vienmēr ir palielināt max_allowed_packet, taču pareizajā pusē un nevis akli līdz maksimumam.
Klasisks gadījums ir atjaunošana:
ERROR 1153 (08S01) at line 4127: Got a packet bigger than 'max_allowed_packet' bytes
Kļūda 1153 (ER_NET_PACKET_TOO_LARGE, SQLSTATE 08S01) nāk no servera. Klienta bibliotēkai ir sava versija, kļūda 2020 "Got packet bigger than 'max_allowed_packet' bytes" (servera kļūdas, klienta kļūdas). Tā kā savienojums tiek aizvērts, daži klienti ziņo tikai "Lost connection to MySQL server during query" vai labi zināmo MySQL server has gone away, kas slēpj īsto cēloni.
Divi limiti, pa vienam katrā galā
Šī ir daļa, kas mulsina. Saskaņā ar MySQL rokasgrāmatu klientam un serverim katram ir savs max_allowed_packet, un, lai pārsūtītu lielas paketes, jāpalielina abi. Noklusējumi atšķiras:
- Serveris: pēc noklusējuma 64MB, maksimums 1GB, iestata ar 1024 baitu soli (sistēmas mainīgo apraksts).
- mysql komandrindas klients: pēc noklusējuma 16MB. mysqldump: 24MB.
- Pašas klienta bibliotēkas noklusējums ir 1GB, bet atsevišķas programmas un draiveri var iestatīt savu vērtību.
- Protokola limits ir 1GB. Neviens iestatījums to nepārsniedz.
Tātad virziens ir svarīgs. 40MB vaicājuma sūtīšana no mysql klienta uz serveri ar 64MB joprojām neizdodas, jo klientam ir 16MB. Lasīšana darbojas tāpat pretējā virzienā: serveris nesūta vairāk par savu globālo max_allowed_packet, lai ko atļautu klients.
1. solis: noskaidrojiet, kura puse atteica
-- servera puse: globālā vērtība (to saņem jauni savienojumi)
SELECT @@GLOBAL.max_allowed_packet / 1024 / 1024 AS server_mb;
-- jūsu pašreizējā sesija (tikai lasāma, fiksēta pieslēgšanās brīdī)
SELECT @@SESSION.max_allowed_packet / 1024 / 1024 AS session_mb;
-- cik liela ir lielākā vērtība, ko jūs patiešām glabājat?
SELECT MAX(LENGTH(payload)) / 1024 / 1024 AS biggest_mb FROM documents;
Salīdziniet šos skaitļus ar to, ko sūtāt. Ja kļūda ir 1153 no servera, servera limits ir par mazu. Ja tā ir 2020 vai parādās klienta rīkā, skatieties klienta opciju failu vai savienojuma virkni. Pārbaudiet arī, no kurienes nāk lielā pakete. Tipiski avoti no mūsu pieredzes:
- Dampu atjaunošana tabulām ar ļoti lielām rindām, parasti BLOB vai garām TEXT kolonnām.
- Lielas BLOB vai TEXT vērtības: faili, attēli, JSON dokumenti. Rokasgrāmata saka, ka limitam jābūt tik lielam kā lielākajam BLOB, ko vēlaties izmantot.
- Milzīgi ģenerēti vaicājumi: ORM, kas būvē
IN (...)sarakstu ar simtiem tūkstošu ID, vai masveida ievietošana bez partijas izmēra. - Funkcijas, kuru rezultāts pārsniegtu limitu. Tās parasti savienojumu nepārtrauc. Tā vietā saņemat brīdinājumu 1301, "Result of %s() was larger than max_allowed_packet".
2. solis: pareizi palieliniet servera limitu
max_allowed_packet ir dinamisks, bet ar vienu āķi: sesijas vērtība ir tikai lasāma un tiek iestatīta, kad klients pieslēdzas. Globālās vērtības maiņa palīdz tikai jauniem savienojumiem. Jūsu lietotnes pūls patur veco vērtību, līdz pieslēdzas no jauna.
-- MySQL 8.0+: mainiet tagad un saglabājiet pēc restarta
SET PERSIST max_allowed_packet = 268435456; -- 256MB
# vai my.cnf
[mysqld]
max_allowed_packet = 256M
Vai palielināt ir droši? Rokasgrāmata saka, ka jā: papildu atmiņa tiek piešķirta tikai tad, kad tā vajadzīga. Katra savienojuma buferis sākas ar net_buffer_length (pēc noklusējuma 16KB) un aug līdz max_allowed_packet tikai liela vaicājuma vai rindas dēļ. Mazais noklusējums ir piesardzība pret bojātām paketēm un pret nejaušu atmiņas izsīkšanu. Praksē mēs izvēlamies vērtību ar rezervi virs lielākās reālās vērtības, piemēram, 256MB, nevis 1GB visur. Tūkstotis savienojumu, kas vienlaikus sūta pa 1GB paketei, ir atmiņas problēma, no kuras neglābs neviens iestatījums.
Neaizmirstiet klientu. Pēc servera limita palielināšanas atjaunošana ar mysql klientu joprojām var neizdoties pie 16MB. Nododiet --max_allowed_packet arī klientam vai iestatiet to opciju faila sadaļā [mysql] vai [client].
Dampu atjaunošana
# dampa atjaunošana: mysql klienta noklusējums ir 16MB, palieliniet arī to
mysql --max_allowed_packet=256M appdb < dump.sql
Divas piezīmes no mysqldump dokumentācijas. Pirmkārt, tā opcija --network-timeout pēc noklusējuma ir ieslēgta un dampa laikā paceļ mysqldump paša pakešu limitu līdz maksimumam, tāpēc dampis parasti izdodas, un problēma parādās atjaunošanā. Otrkārt, klienta iestatījums nevar pārspēt serveri: viena pakete nekad nevar pārsniegt servera max_allowed_packet, lai kā būtu iestatīts mysqldump. Ar --extended-insert (daļa no noklusējuma --opt) mysqldump būvē vairāku rindu INSERT līdz --net-buffer-length baitiem (pēc noklusējuma 16KB). Tātad vaicājums dampā ir milzīgs tikai tad, ja milzīga ir viena rinda, un tad vienīgais risinājums ir palielināt limitus. Tieši šādu kļūmi regulārs atjaunošanas tests atklāj, pirms to izdara incidents.
Replikācija
Lieli rindu notikumi var salauzt arī replikāciju. Replikā attiecīgais iestatījums ir replica_max_allowed_packet, kura noklusējums ir 1GB un kas attiecas uz saņēmēja un piemērotāja pavedieniem (replikas opcijas). Rokasgrāmata norāda, ka avots var ierakstīt notikumus, kas pēc galvenes pievienošanas ir garāki par tā paša max_allowed_packet, tāpēc replikas vērtībai jābūt lielākai par avota vērtību. Ja avots atsakās sūtīt notikumu, replikas kļūdā ir teksts "log event entry exceeded max_allowed_packet; Increase max_allowed_packet on source" (rpl_binlog_sender.cc). Ja to atsaka replika, žurnālā rakstīts "Log entry on source is longer than replica_max_allowed_packet". CLONE spraudnim arī ir sava pārbaude, un tas pasaka, kāda minimālā vērtība tam vajadzīga.
Kad limita palielināšana ir nepareizs risinājums
Ja lielā pakete nāk no lietotnes koda, labāks risinājums bieži ir kodā. Sadaliet masveida ievietošanu partijās pa dažiem tūkstošiem rindu. Aizstājiet milzīgu IN sarakstu ar pagaidu tabulu un join. Apsveriet simtiem megabaitu lielu failu glabāšanu objektu krātuvē, MySQL paturot tikai atsauci. Limits, kas palielināts līdz 1GB tikai tāpēc, lai izietu viens slikts vaicājums, ielaidīs arī nākamo slikto vaicājumu.
Galvenās atziņas
- Kļūda 1153 nozīmē, ka viens vaicājums, rinda vai replikācijas notikums pārsniedza
max_allowed_packet, un savienojums tika aizvērts. - Klientam un serverim ir atsevišķi limiti: pēc noklusējuma serverim 64MB, mysql klientam 16MB, mysqldump 24MB, protokola maksimums 1GB.
- Sesijas vērtība ir tikai lasāma; globālās vērtības palielināšana palīdz tikai jauniem savienojumiem.
- Limita palielināšana ir droša, jo atmiņa tiek piešķirta pēc vajadzības, bet izmēriet to pēc savas reālās lielākās vērtības.
- Atjaunošanā palieliniet limitu gan serverī, gan mysql klientā.
- Replikācijai turiet
replica_max_allowed_packetvirs avotamax_allowed_packet.