"MySQL server has gone away" ir klienta kļūda 2006. Tā nozīmē, ka klients mēģināja izmantot savienojumu, kas vairs nedarbojas. Kļūda neko nepasaka par to, kāpēc savienojuma vairs nav. MySQL dokumentācijā uzskaitīti vairāk nekā desmit iespējamie cēloņi, sākot ar dīkstāves taimautu un beidzot ar servera avāriju, un viena cēloņa labojums otram neder. Tāpēc pirmais uzdevums nav mainīt iestatījumu, bet noskaidrot, kas savienojumu aizvēra.
2006, 2013 un 4031: vienas problēmas trīs sejas
ERROR 2006 (HY000): MySQL server has gone away
ERROR 2013 (HY000): Lost connection to MySQL server during query
ERROR 4031 (HY000): The client was disconnected by the server because of inactivity.
See wait_timeout and interactive_timeout for configuring this behavior.
- 2006 (
CR_SERVER_GONE_ERROR): saskaņā ar dokumentāciju klients nevarēja nosūtīt serverim pieprasījumu. - 2013 (
CR_SERVER_LOST): klients, rakstot serverim, kļūdu nesaņēma, bet nesaņēma arī pilnu atbildi vai jebkādu atbildi. Dokumentācijā norādīts, ka tas, kuru no abām kļūdām saņemat servera puses taimauta gadījumā, ir atkarīgs no operētājsistēmas, tāpēc uztveriet tās kā vienu saimi. - 4031 (
ER_CLIENT_INTERACTION_TIMEOUT): pievienota MySQL 8.0.24. Kad serveris aizver savienojumu, jo tas bija dīkstāvē ilgāk parwait_timeout, tas tagad vispirms ieraksta savienojumā iemeslu, tāpēc klients redz skaidrāku ziņojumu. Laidiena piezīmēs piebilsts, ka vecā uzvedība joprojām attiecas uz vecākiem serveriem un vecākiem klientiem, tāpēc jauktās vidēs vienkāršs dīkstāves taimauts joprojām var parādīties kā 2006 vai 2013.
Ja redzat 4031, lielāko daļu šī raksta varat izlaist: savienojums bija pārāk ilgi dīkstāvē. Ja redzat 2006 vai 2013, lasiet tālāk.
1. solis: savāciet četrus faktus
Pirms kaut ko maināt, izpildiet serverī:
SHOW GLOBAL VARIABLES WHERE Variable_name IN
('wait_timeout', 'interactive_timeout', 'max_allowed_packet',
'net_read_timeout', 'net_write_timeout', 'connect_timeout');
SHOW GLOBAL STATUS WHERE Variable_name IN
('Uptime', 'Aborted_clients', 'Aborted_connects');
Pēc tam atbildiet uz četriem jautājumiem:
- Vai serveris restartējās? Salīdziniet
Uptimear kļūdu laiku. Dokumentācija iesaka tieši šo pārbaudi: ja savienojums pārtrūka, jo mysqld avarēja un restartējās, kļūda ir mazākā problēma, un jāizmeklē avārija. Pārbaudiet kļūdu žurnālu. - Cik ilgi savienojums bija dīkstāvē? Ja neveiksmīgais pieprasījums ir pirmais pēc klusa perioda (nakts darbi, process, kas pamostas reizi stundā, savienojumu pūls pēc nedēļas nogales) un pārtraukums ir garāks par sesijas
wait_timeout, cēlonis atrasts. - Cik liels bija pieprasījums? Milzīgs
INSERT, lielsBLOBvai garš ģenerēts vaicājums norāda uzmax_allowed_packet. - Vai kāds vai kas sesiju pārtrauca? DBA izpildīts
KILL, monitoringa skripts, kas pārtrauc ilgus vaicājumus, vai pārslēgšanās rīks no klienta puses izskatās vienādi.
Dokumentācija arī iesaka palaist mysqld ar log_error_verbosity vērtību 3, lai kļūdu žurnālā tiktu ierakstīti daži atvienošanās ziņojumi. Tas palīdz, ja klienta puse neko nepasaka.
1. cēlonis: savienojums bija dīkstāvē ilgāk par wait_timeout
Šo cēloni dokumentācija sauc par biežāko. Pēc noklusējuma serveris aizver savienojumu pēc astoņām stundām bez aktivitātes: wait_timeout un interactive_timeout noklusējuma vērtība abiem ir 28800 sekundes.
To mijiedarbībā ir slazds. Saskaņā ar servera mainīgo aprakstu, kad sesija sākas, tās wait_timeout tiek inicializēts no globālā wait_timeout vai no globālā interactive_timeout atkarībā no tā, vai klients pieslēdzās ar opciju CLIENT_INTERACTIVE. Tāpēc, mainot tikai vienu no abiem globālajiem mainīgajiem, jums svarīgie savienojumi var netikt ietekmēti. Pārbaudiet, ko sesija patiešām saņēma:
-- ko saņēma TIEŠI ŠĪ sesija (var atšķirties no globālās vērtības)
SELECT @@SESSION.wait_timeout, @@GLOBAL.wait_timeout, @@GLOBAL.interactive_timeout;
Komandas, kas samazināja wait_timeout, lai iztīrītu dīkstāves savienojumus (to apsvērt iesaka mūsu raksts par "Too many connections"), dažreiz aizmirst par lietotnes pusi. Ja savienojumu pūls tur savienojumus ilgāk nekā serveris, pūls agri vai vēlu izsniegs mirušu savienojumu.
Labojums pieder lietotnei, nevis lielākam taimautam:
- Iestatiet pūla maksimālo savienojuma mūžu vai dīkstāves laiku mazāku par servera
wait_timeout, lai pūls savienojumus izņemtu no aprites pirms servera. - Ieslēdziet pūla savienojumu validāciju (testa vaicājumu vai ping, pirms izsniegt savienojumu, kas bijis dīkstāvē), ja jūsu pūls to atbalsta.
- Ilgi strādājošos skriptos atveriet savienojumu tad, kad tas vajadzīgs, nevis palaišanas brīdī.
Neaizmirstiet, kas atrodas starp lietotni un MySQL. Slodzes balansētājiem, starpniekserveriem, NAT vārtejām un ugunsmūriem var būt savi dīkstāves taimauti, un tie var klusi pārtraukt TCP savienojumus, ko MySQL joprojām uzskata par atvērtiem. Ja wait_timeout ir astoņas stundas, bet savienojumi mirst pēc dažām klusuma minūtēm, skatieties tīkla ceļu.
2. cēlonis: pakete bija pārāk liela
No lapas "Packet Too Large": kad MySQL klients vai mysqld serveris saņem paketi, kas lielāka par max_allowed_packet baitiem, tas izdod kļūdu ER_NET_PACKET_TOO_LARGE (1153, "Got a packet bigger than 'max_allowed_packet' bytes") un aizver savienojumu. Daži klienti parāda tikai aizvērto savienojumu, tāpēc tas bieži izskatās kā 2006 vai 2013.
Galvenie skaitļi no dokumentācijas:
- Servera noklusējuma
max_allowed_packetir 64MB. mysqlklienta programmai ir savs noklusējums, 16MB.- Lielākā iespējamā pakete uz vai no MySQL 8.4 servera vai klienta ir 1GB.
Abām pusēm ir savs mainīgais, tāpēc lielam importam iestatījums var būt jāpalielina gan klientā, gan serverī:
[mysqld]
max_allowed_packet = 128M
# un klienta pusē, piemēram:
# mysql --max_allowed_packet=128M
Pirms palielināt, pārbaudiet, vai tas ir vajadzīgs. Dokumentācijā norādīts, ka INSERT vai REPLACE ar ļoti daudzām rindām tiek nosūtīts kā viens pieprasījums, un kļūdu bieži var novērst, sūtot mazāk rindu vienā vaicājumā. Mazākas partijas parasti ir vieglākas serverim, replikācijai un jūsu atkārtošanas loģikai nekā viens milzīgs vaicājums.
3. cēlonis: vaicājums vai rezultāts tīklā aizņēma pārāk ilgu laiku
Lapa par zaudētu savienojumu aplūko 2013 variantu. Ja ziņojumā ir "during query", dokumentācija saka, ka visticamākais cēlonis ir tīkla problēmas. Tajā aprakstīts arī gadījums, kad tiek sūtīti miljoniem rindu, un ieteikts palielināt net_read_timeout no noklusējuma 30 sekundēm līdz 60 sekundēm vai vairāk. Tā radniecīgais mainīgais net_write_timeout pēc noklusējuma ir 60 sekundes un nosaka, cik ilgi serveris gaida, rakstot klientam. Klients, kas lielu rezultātu kopu lasa lēni, piemēram, apstrādā katru rindu pirms nākamās ielādes, var tam uzdurties.
Svarīgi ir arī klienta puses taimauti. Dokumentācijā minētas C API lasīšanas un rakstīšanas taimauta opcijas; vairumam draiveru ir līdzvērtīgas. Ja draiveris padodas pēc 30 sekundēm vaicājumam, kas ilgst 40, rezultāts izskatās pēc zaudēta savienojuma, lai gan serveris ir kārtībā.
Kļūdām pieslēgšanās brīdī dokumentācija norāda uz connect_timeout (noklusējums 10 sekundes) un statusa skaitītāju Aborted_connects, kas palielinās par vienu katram sākotnējam pieslēgšanās mēģinājumam, ko serveris pārtrauc. "reading authorization packet" ziņojumā ir mājiens šajā virzienā.
4. cēlonis: sesija tika pārtraukta vai serveris nokrita
Dokumentācijā kā cēlonis minēts KILL vaicājums vai mysqladmin kill. Praksē tas ietver rīkus, kas automātiski pārtrauc ilgus vaicājumus; to ir vērts pārbaudīt, ja kļūdas koncentrējas ap smagām atskaitēm. Mūsu rakstā par lock wait timeout parādīts, kā atrast bloķējošās sesijas, kas ir biežs iemesls, kāpēc kāds vispār ķeras pie KILL.
Servera avārija, OOM pārtraukšana vai pārslēgšanās uz repliku arī izbeidz visus savienojumus. Ja Uptime ir īss, sāciet ar kļūdu žurnālu un sistēmas žurnālu, nevis ar klientu.
5. cēlonis: kļūdas lietotnes savienojumu apstrādē
Divi cēloņi no dokumentācijas nāk tieši no lietotnes koda:
- Savienojuma izmantošana pēc tā aizvēršanas. Dokumentācija to sauc par lietotnes loģikas kļūdu, kas jāizlabo.
- Atzaroti procesi, kas dala vienu savienojumu. Lietotnes, kas atzaro bērnprocesus, kuri visi izmanto vienu MySQL savienojumu, var saņemt šīs kļūdas. Labojums ir atsevišķs savienojums katram bērnprocesam. Uzmanieties no tā ar pre-fork tīmekļa serveriem un darbu izpildītājiem, kas atver savienojumu pirms atzarošanas.
GET_LOCK() slēdzenes atbrīvotas, pagaidu tabulas dzēstas, sesijas un lietotāja mainīgie zaudēti, un LAST_INSERT_ID() atiestatās uz 0. Kods, kas transakcijas vidū klusi pieslēdzas no jauna, var turpināt darbu tā, it kā puse tā darba nebūtu tikko izmesta. Pieslēdzieties no jauna un pēc tam sāciet visu darba vienību no sākuma.Izmantojiet Aborted_clients kā agru brīdinājumu
Lapā par komunikācijas kļūdām paskaidrots, ka, ja klients veiksmīgi pieslēdzas, bet vēlāk atvienojas nepareizi vai tiek pārtraukts, serveris palielina Aborted_clients un ieraksta žurnālā ziņojumu "Aborted connection". Cēloņi ir klients, kas beidz darbu, neaizverot savienojumu, klients, kas guļ ilgāk par wait_timeout vai interactive_timeout, klients, kas beidz darbu datu pārsūtīšanas vidū, pārāk mazs max_allowed_packet un bojāta tīkla aparatūra. Attēlojiet skaitītāju grafikā. Vienmērīga plūsma daudzām lietotnēm ir normāla; pēkšņs pieaugums pēc izlaidiena vai tīkla izmaiņām pasaka, kur meklēt, pirms lietotāji sāk ziņot par kļūdām.
Galvenās atziņas
- Kļūdas 2006 un 2013 pasaka tikai to, ka savienojuma vairs nav. Kopš 8.0.24 dīkstāves taimauts tiek paziņots kā skaidrākā kļūda 4031, ja to atbalsta gan klients, gan serveris.
- Pirms iestatījumu maiņas pārbaudiet
Uptime, dīkstāves laiku, pieprasījuma izmēru un nesenosKILL. - Dīkstāves taimautiem panāciet, lai pūls izņem savienojumus no aprites pirms servera
wait_timeout, un atcerieties, ka sesijas vērtība var nākt nointeractive_timeout. - Lieliem pieprasījumiem vispirms sadaliet partijas; ja palielināt
max_allowed_packet(servera noklusējums 64MB,mysqlklientam 16MB, maksimums 1GB), palieliniet to abās pusēs. - Auto-reconnect atiestata sesijas stāvokli un atritina atvērtās transakcijas, neko nepaziņojot lietotnei. Pēc atkārtotas pieslēgšanās sāciet visu darba vienību no sākuma.