MySQL "Too many connections" ir viena no tām kļūdām, kas izskatās vienkārša, bet parasti tāda nav. Lietotnes žurnāli pildās ar ERROR 1040 (HY000): Too many connections, vietne sāk rādīt kļūdas, un, kad mēģināt pieslēgties, lai saprastu, kas notiek, MySQL atraida arī jūs. Ātrais risinājums, pēc kura visi sniedzas, ir lielāks max_connections. Dažreiz tas ir pareizi. Biežāk limits ir tikai vieta, kur kļūst redzama īstā problēma: kaut kas augšpus datubāzes tur savienojumus daudz ilgāk, nekā vajadzētu.
Ko šī kļūda patiesībā nozīmē
MySQL ir fiksēts vienlaicīgu klientu savienojumu griesti, ko nosaka max_connections. Kad visas vietas ir aizņemtas, jauni savienojumi tiek noraidīti, un serveris palielina statusa skaitītāju Connection_errors_max_connections. Noklusējuma vērtība MySQL 8.4 ir 151, diapazons no 1 līdz 100 000. Faktisko vērtību ierobežo arī operētājsistēma: tā ir mazākā no jūsu iestatītās un open_files_limit mīnus 810. Tātad, ja palielināt max_connections, bet failu deskriptoru limits paliek zems, MySQL var klusi izmantot mazāku skaitli nekā konfigurācijā.
Pārvaldītajos servisos noklusējums ir cits. Amazon RDS for MySQL to aprēķina no instances atmiņas, aptuveni viens savienojums uz 12 MB. Pēc AWS datiem tas ir ap 60 uz db.t3.micro un ap 630 uz 8 GiB klases.
1. solis: iegūstiet sev sesiju
Nevar salabot datubāzi, kurai nevar piekļūt. MySQL to paredz, ja vien tas ir pareizi iestatīts:
- Rezervētā vieta. mysqld patiesībā atļauj max_connections + 1 savienojumu. Papildu vieta ir paredzēta kontiem ar privilēģiju
CONNECTION_ADMIN(vai novecojušoSUPER). Tas darbojas tikai tad, ja jūsu lietotnes lietotājam šīs privilēģijas nav. Ja lietotne pieslēdzas ar administratora līmeņa kontu, tā aizņems arī rezerves vietu, un jūs paliksiet ārpusē kopā ar visiem pārējiem. - Administratīvā saskarne. Kopš MySQL 8.0.14 var iestatīt
admin_addressunadmin_port(noklusējuma ports 33062). Saskarne pastāv tikai tad, jaadmin_addressir iestatīts startēšanas brīdī, tāpēc incidenta vidū to ieslēgt nevar. Kad tā ir ieslēgta, tai nav savienojumu limita, un tā pieņem tikai lietotājus arSERVICE_CONNECTION_ADMIN. Ja uzturat MySQL paši, konfigurējiet to tagad, kamēr viss ir mierīgi.
Ja nav pieejams ne viens, ne otrs, iespējas kļūst rupjākas: apturēt lietotnes slāni, kas pārpludina serveri, vai pārstartēt MySQL. Pārstartēšana izmet visu procesā esošo darbu un pierādījumus par to, kas notika, tāpēc tā ir pēdējais līdzeklis, nevis pirmais solis.
2. solis: paskatieties, pirms pārtraucat
Kad esat iekšā, nesāciet pārtraukt pavedienus pa vienam no SHOW PROCESSLIST. Vispirms tos sagrupējiet, lai aina būtu redzama dažās rindās:
SELECT user, SUBSTRING_INDEX(host, ':', 1) AS client,
command, state, COUNT(*) AS conns, MAX(time) AS max_sec
FROM information_schema.processlist
GROUP BY user, client, command, state
ORDER BY conns DESC;
Rezultāts parasti norāda uz kādu no dažiem scenārijiem:
- Simtiem
Sleepsavienojumu ar lielumax_sec. Lietotne atver savienojumus un neatdod tos atpakaļ. Tā ir savienojumu noplūde vai pārāk lieli savienojumu pūli. Noklusējumawait_timeoutir 28 800 sekundes, tātad MySQL neaktīvu savienojumu tur atvērtu 8 stundas, pirms pats to aizver. - Daudz sesiju stāvoklī
Waiting for table metadata lock. Viena sesija tur bloķējumu (biežiALTER TABLE, kas gaida aiz garas transakcijas, vai atvērta transakcija, ko kāds aizmirsa apstiprināt), un viss pārējais stāv rindā aiz tās. Rinda aizpilda savienojumu limitu. Skatssys.schema_table_lock_waitsparāda, kurš bloķē kuru. - Daudz sesiju aktīvi izpilda vienu un to pašu vaicājumu. Lēns vaicājums pēc izlaišanas, trūkstošs indekss vai tikko beidzies kešs. Katrs pieprasījums ilgst ilgāk, tāpēc vienlaikus to ir vairāk, un vietas beidzas. Salabojiet vaicājumu, un savienojumu skaits kritīsies pats.
- Vienam klienta hostam pieder lielākā daļa savienojumu. Pakešuzdevums, nevaldāms darbinieka process vai atkārtošanas cilpa. Apturiet to avotā.
3. solis: atbrīvojiet vietas, nepasliktinot situāciju
Pārtrauciet selektīvi, sākot ar neaktīvajām sesijām, kas pieder lietotnei. Ja vispirms ģenerējat komandas, sarakstu var pārbaudīt pirms izpildes:
SELECT CONCAT('KILL ', id, ';')
FROM information_schema.processlist
WHERE user = 'app_user'
AND command = 'Sleep'
AND time > 300;
Ja sesijas gaida bloķējumu, pārtrauciet bloķētāju, nevis rindu. Simts gaidošu sesiju pārtraukšana tikai atbrīvo vietu simts jaunām, kas gaidīs tieši tāpat. Esiet uzmanīgi ar sesijām, kas veic garus ierakstus: to pārtraukšana atritina transakciju, un liela atritināšana var ilgt tikpat ilgi kā darbs, ko tā atceļ.
Pēc tam tieciet galā ar avotu. Ja lietotne atkārto pieprasījumus uzreiz un paralēli, tā dažās sekundēs atkal aizpildīs katru atbrīvoto vietu. Lietotnes samazināšana vai trokšņaina darbinieka izslēgšana uz dažām minūtēm bieži ir ātrākais risinājums.
max_connections palielināšana ar SET GLOBAL darbojas bez pārstartēšanas un ir pieņemams ārkārtas pasākums. Taču katrs savienojums patērē atmiņu, un serveris, kuram beidzas RAM, ir daudz smagāks incidents nekā serveris, kas atraida savienojumus. Ja cēlonis ir bloķējumu sastrēgums vai lēns vaicājums, vairāk vietu nozīmē tikai vairāk sesiju, kas iestrēgst aiz tā. Ja produkcija nedarbojas un neesat pārliecināti, kurā situācijā atrodaties, tieši tad ir laiks izsaukt ārkārtas DBA, pirms veicat izmaiņas, kuras nevar atsaukt.
Cik lielam jābūt max_connections?
Maģiska skaitļa nav. MySQL rokasgrāmata norāda, ka praktiskais maksimums ir atkarīgs no pavedienu bibliotēkas, pieejamās RAM, atmiņas uz vienu savienojumu, slodzes un vēlamā atbildes laika. Tajā minēts, ka Linux parasti bez problēmām apkalpo 500 līdz 1000 vienlaicīgu savienojumu, bet ar daudziem gigabaitiem RAM un vieglu slodzi uz savienojumu līdz pat 10 000.
Noderīgāk ir rēķināt no lietotnes puses. Saskaitiet katru procesu, kam ir savienojumu pūls: lietotnes serverus, podus, darbiniekus, cron uzdevumus, administrēšanas rīkus. Reiziniet katru ar tā pūla izmēru, pieskaitiet rezervi izlaišanām, kad vecās un jaunās instances darbojas vienlaikus, un salīdziniet ar limitu. Kubernetes komandas te bieži tiek pārsteigtas: 40 podi ar pūlu 20 ir 800 iespējamu savienojumu, un automātiskā mērogošana to var divkāršot dažās minūtēs.
Ja godīgā summa ir krietni virs tā, ko serveris spēj apkalpot, atbilde ir mazāk savienojumu, nevis lielāks limits: mazāki pūli vai starpniekserveris, kas daudzus klientu savienojumus apvieno mazākā skaitā servera savienojumu (ProxySQL pašu uzturētam MySQL, RDS Proxy AWS vidē). Tā ir tā pati ideja, ko PostgreSQL gadījumā aprakstām mūsu ceļvedī par savienojumu pūliem.
Iestatījumi, ko vērts pārbaudīt pēc tam
wait_timeout: 8 stundas neaktīvam savienojumam ir ilgs laiks. Samazinot to, paliek mazāk noplūdušu sesiju, taču iestatiet to lielāku par pūla paša neaktivitātes taimautu, citādi lietotne saskarsies ar savienojumiem, ko serveris jau aizvēris.max_user_connectionsvai konta limits arALTER USER ... WITH MAX_USER_CONNECTIONS n: neļauj vienam servisam aizņemt visas vietas un atstāt pārējos bez tām. Globālais noklusējums ir 0, kas nozīmē bez limita.open_files_limitun systemdLimitNOFILE: pārliecinieties, ka operētājsistēma atļauj jūsu konfigurēto skaitu.thread_cache_size: pēc noklusējuma automātiski 8 +max_connections/100, ne vairāk par 100. JaThreads_createdaug strauji salīdzinājumā arConnections, daudzi savienojumi saņem jaunus pavedienus, nevis atkārtoti izmantotus.- Privilēģijas: noņemiet
CONNECTION_ADMINunSUPERlietotņu kontiem, lai rezervētā vieta paliktu rezervēta.
Sekojiet tam, pirms tas salūzt
"Too many connections" gandrīz nekad nerodas no zila gaisa. Visi rādītāji, kam sekot, ir vienuviet:
SHOW GLOBAL STATUS WHERE Variable_name IN
('Threads_connected', 'Max_used_connections',
'Connection_errors_max_connections', 'Threads_created', 'Connections');
- Brīdiniet par
Threads_connectedprocentos nomax_connections, piemēram, pie 80%, lai būtu laiks rīkoties. - Sekojiet
Max_used_connections. Ja tas ir tuvu limitam, jūs jau esat bijuši tuvu dīkstāvei. - Brīdiniet par jebkuru
Connection_errors_max_connectionspieaugumu. Katrs pieaugums ir atraidīts klients. - Kopā ar savienojumu skaitu sekojiet vaicājumu latentumam un bloķējumu gaidīšanai. Augošs latentums parasti ir tas, kas dzen savienojumu skaitu uz augšu.
Galvenās atziņas
- ERROR 1040 nozīmē, ka visas
max_connectionsvietas ir aizņemtas. Limits parasti ir simptoms; cēlonis ir noplūdes, pārāk lieli pūli, bloķējumu sastrēgumi vai lēni vaicājumi. - Nedodiet
CONNECTION_ADMINlietotņu lietotājiem, lai papildu administratora vieta darbotos. Pašu uzturētam MySQL iestatietadmin_address, pirms tas vajadzīgs. - Pirms kaut ko pārtraucat, sagrupējiet procesu sarakstu. Pārtrauciet neaktīvās lietotnes sesijas un bloķētājus, nevis rindu.
max_connectionspalielināšana ir derīgs īstermiņa risinājums tikai tad, ja serverim ir brīva atmiņa un cēlonis nav bloķējums vai slikts vaicājums.- Nosakiet limitu no kopējā pūlu izmēra, izmantojiet starpniekserveri, ja šī summa ir par lielu, un brīdiniet krietni pirms 100% sasniegšanas.