Incidentu reaģēšana

Redis "ERR max number of clients reached": cēloņi un risinājumi

Redis darbojas, atmiņas pietiek, bet jauni savienojumi tiek noraidīti ar "max number of clients reached". Pats limits reti ir īstā problēma. Parasti kaut kas noplūdina savienojumus, vai OS startējot klusi samazināja maxclients. Paskaidrojam, kā to noteikt un novērst.

· 14 min lasīšanai · AG Data komanda

Redis kļūda "ERR max number of clients reached" nozīmē, ka serverim ir tik daudz atvērtu savienojumu, cik atļauj maxclients, tāpēc tas noraida jaunus. Komandas esošajos savienojumos turpina darboties, un atmiņa un CPU var izskatīties pilnīgi normāli. Tas ir jaudas limits, taču vairumā incidentu labot vajag nevis limitu. Kaut kas tur daudz vairāk savienojumu, nekā vajadzētu, vai operētājsistēma Redis ierobežoja zemāk, nekā domājat.

Kas tieši notiek pie limita

Pārbaude atrodas failā networking.c, un tā notiek, pieņemot savienojumu, pirms vēl tiek izveidots klienta objekts. Ja klientu skaits kopā ar klastera kopnes savienojumiem sasniedz vai pārsniedz maxclients, Redis uzraksta kļūdu, palielina skaitītāju un aizver soketu. Klients redz:

ERR max number of clients reached

Dažas šī koda detaļas praksē ir svarīgas:

Valkey ir tāda pati pārbaude un tāds pats ziņojums. Valkey 9.2, kas šī raksta tapšanas brīdī ir laidiena kandidāta stadijā, savā konfigurācijā pievieno maxclients-reserved un priority-subnets. Tie patur daļu limita savienojumiem no norādītajiem administrēšanas vai monitoringa tīkliem, lai operatori netiktu izslēgti. Pašā Redis līdzvērtīga iestatījuma nav.

Pirmā pārbaude: kāds ir reālais maxclients?

Noklusējums ir 10000. Redis klientu apstrādes dokumentācija paskaidro āķi: Redis vajag maxclients plus 32 failu deskriptorus (32 tiek rezervēti iekšējai lietošanai). Startējot tas pārbauda savu atvērto failu limitu un, ja tas ir par zemu, mēģina to paaugstināt pats. Kods failā server.c samazina vērtību soli pa solim, līdz OS to pieņem. Ja pietiekami daudz iegūt neizdodas, Redis samazina maxclients, lai tas ietilptu. Tas neatsakās startēt. Tas ieraksta brīdinājumu žurnālā un turpina ar mazāko limitu.

Tātad, ja procesa cietais (hard) limits ir 1024 atvērti faili, 10000 klusi kļūst par 992, lai gan konfigurāciju neviens nav mainījis. Pārbaudiet, kas ir darbojošamies procesam:

# darbojošā procesa reālais limits
grep 'open files' /proc/$(pidof redis-server)/limits

# ko Redis izlēma startējot
grep -i 'maxclients\|open files' /var/log/redis/redis-server.log

Meklējamie brīdinājumi ir "maxclients has been reduced to N to compensate for low ulimit" vai "Unable to obtain the current NOFILE limit", ja Redis limitu nevarēja nolasīt un pieņēma 1024. Ja Redis darbojas zem systemd, ulimit jūsu čaulā uz servisu neattiecas. Limits nāk no vienības iestatījuma LimitNOFILE=.

maxclients var mainīt darbības laikā ar CONFIG SET. Konfigurācijas kods vispirms vēlreiz pielāgo failu limitu, un, ja OS jauno vērtību nevar atbalstīt, komanda beidzas ar kļūdu "The operating system is not able to handle the specified number of clients, try with N". Tātad CONFIG SET klusi nepārsniegs OS limitu.

Otrā pārbaude: kas tur savienojumus

Sāciet ar skaitļiem. Ja nevarat pieslēgties, jo visas vietas ir aizņemtas, palaidiet šīs komandas no hosta, kura savienojums jau ir atvērts, izmantojiet monitoringa aģenta sesiju vai vispirms atbrīvojiet dažas vietas (skatīt tālāk).

redis-cli INFO clients
# connected_clients:9968
# cluster_connections:0
# maxclients:10000
# blocked_clients:12

redis-cli INFO stats | grep -E 'rejected_connections|total_connections_received'

Skaitītājs rejected_connections, kas turpina augt, apstiprina, ka limits tiek sasniegts tieši tagad. Tad sagrupējiet savienojumus. CLIENT LIST izdrukā vienu rindu katram savienojumam ar tādiem laukiem kā addr, name, age, idle, flags, cmd un, sākot ar Redis 7.2, lib-name un lib-ver:

# savienojumi pa klientu IP adresēm
redis-cli CLIENT LIST | grep -o 'addr=[^:]*' | sort | uniq -c | sort -rn | head

# savienojumi pa klienta nosaukumiem / bibliotēkām (ja klienti tos iestata)
redis-cli CLIENT LIST | grep -o 'name=[^ ]*' | sort | uniq -c | sort -rn | head
redis-cli CLIENT LIST | grep -o 'lib-name=[^ ]*' | sort | uniq -c | sort -rn | head

Modeļi, ko parasti atrodam:

  1. Viens hosts vai serviss ar tūkstošiem savienojumu. Savienojumu noplūde: klients, kas tiek izveidots katram pieprasījumam un nekad netiek aizvērts, pūls bez augšējās robežas vai ietvars, kas katrā darba procesā atver jaunu pūlu.
  2. Milzīgas idle vērtības daudziem savienojumiem. Savienojumi, ko pameta klienti, kas avarēja vai tika nogalināti, tos neaizverot. Paša Redis timeout noklusējums ir 0, tāpēc šādi savienojumi paliek atvērti, līdz TCP keepalive pamana, ka otras puses vairs nav. Keepalive pēc noklusējuma ir ieslēgts ar 300 sekundēm, un konfigurācijas komentārs saka, ka Linux sistēmā miruša savienojuma aizvēršanai vajag apmēram divreiz vairāk laika.
  3. Viss mērogojās vienlaikus. Automātiskā mērogošana dubultoja podu skaitu, un katrs pods atver fiksēta izmēra pūlu. Pūla izmērs × instanču skaits ir tas skaitlis, kas jāsalīdzina ar maxclients.
  4. Daudz blpop/xread vai abonentu. Bloķējošās komandas un Pub/Sub aizņem savienojumu visu gaidīšanas laiku. Katram šādam patērētājam vajag savu savienojumu, tāpēc tie ātri sakrājas.

Risinājumi, no tūlītējiem līdz pastāvīgiem

# atbrīvot vietas tagad: aizvērt konkrēta hosta savienojumu
redis-cli CLIENT KILL ADDR 10.20.0.15:53122
redis-cli CLIENT KILL TYPE normal MAXAGE 86400   # Redis 7.4+, pēc savienojuma vecuma

# automātiski aizvērt dīkstāvē esošus savienojumus (sekundes, 0 = nekad)
redis-cli CONFIG SET timeout 300

# paaugstināt griestus, ja OS limits to atļauj
redis-cli CONFIG SET maxclients 20000

Atbrīvojiet vietas tagad. CLIENT KILL var aizvērt savienojumus pēc ID, ADDR, LADDR, USER vai TYPE, un kopš Redis 7.4 arī pēc MAXAGE. Ņemiet vērā, ka MAXAGE aizver klientus, kas vecāki par norādīto sekunžu skaitu: tas ir savienojuma vecums, nevis dīkstāves laiks. Dīkstāves filtra nav, tāpēc, lai aizvērtu tikai dīkstāvē esošus savienojumus, paņemiet ID no CLIENT LIST un aizveriet tos. Noplūdinošā servisa restarts bieži atbrīvo vairāk vietu un ātrāk nekā jebkas, ko darāt serverī.

Iestatiet dīkstāves taimautu. timeout aizver parastus savienojumus, kas dīkstāvē ilgāk par norādīto sekunžu skaitu. Saskaņā ar timeout.c tas neattiecas uz replikām, saiti ar master, bloķētiem klientiem un Pub/Sub abonentiem, tāpēc to ieslēgt ir samērā droši. Dokumentācija brīdina, ka pārbaude notiek pakāpeniski, tāpēc savienojumi tiek aizvērti nedaudz vēlāk par precīzo vērtību. Iestatiet to garāku par jūsu pūlu pašu dīkstāves taimautu, lai savienojumu vispirms aizvērtu pūls un tas neuzdurtos mirušam soketam.

Paaugstiniet limitu, ja slodze ir reāla. Ja savienojumu skaits ir pamatots, vispirms paaugstiniet OS failu limitu (LimitNOFILE= vai ulimit -n), tad maxclients konfigurācijas failā un ar CONFIG SET. Katrs savienojums izmanto arī atmiņu saviem buferiem. Pirms klientu skaita reizināšanas pārbaudiet tot-mem komandā CLIENT LIST un ieskatieties mūsu Redis OOM un maxmemory ceļvedī.

Nelabojiet noplūdi, paaugstinot maxclients. Ja viens serviss bez ierobežojuma palielina savienojumu skaitu, augstāks maxclients tikai nopērk laiku, un nākamais incidents nāk ar lielāku atmiņas patēriņu un vairāk atvērtu failu deskriptoru. Labojiet klientu: viens kopīgs pūls katram procesam, stingra pūla izmēra augšējā robeža un savienojumu atgriešana pēc lietošanas.

Novērsiet nākamo reizi

Galvenās atziņas

Redis Valkey Savienojumi Problēmu novēršana
Sadarbība ar mums

Redis noraida savienojumus?

Savienojumu izsīkums parasti ir klienta problēma, kas parādās serverī. Mēs atrodam servisu, kas noplūdina savienojumus, pareizi iestatām limitus un brīdinājumus, lai tas neatkārtotos.

Sazināties Vairāk no emuāra