Incidentu reaģēšana

ClickHouse "Memory limit exceeded" (Code 241): kas sasniedza limitu un kā to novērst

Code 241 var nozīmēt vienu smagu vaicājumu, vienu alkatīgu lietotāju vai serveri, kuram kopumā beigusies atmiņa, un katram gadījumam risinājums ir citāds. Lūk, kā tos atšķirt pēc kļūdas teksta un sistēmas tabulām un kas patiešām palīdz.

· 14 min lasīšanai · AG Data komanda

ClickHouse "Memory limit exceeded" ir kļūdas kods 241, MEMORY_LIMIT_EXCEEDED. Tā izskatās pēc vienas kļūdas, taču rodas no vairākiem dažādiem limitiem: viena vaicājuma, viena lietotāja vai visa servera. Smags GROUP BY, kam jāmaina iestatījums, un serveris, kuram patiešām beigusies atmiņa, rada gandrīz vienādu ziņojumu, un, jaucot vienu ar otru, tiek iztērētas stundas. Šis ceļvedis parāda, kā izlasīt kļūdu, atrast, kas patērē atmiņu, un labot pareizo lietu. Tālāk minētie noklusējumi pārbaudīti pret ClickHouse 26.8 LTS pirmkodu un aktuālo dokumentāciju; pārbaudiet system.settings savā versijā, jo vairāki no tiem pēdējās versijās mainījušies.

Izlasiet kļūdas pirmos vārdus

Teksts nāk no ClickHouse atmiņas uzskaitītāja (memory tracker), un tā pirmie vārdi nosauc sasniegto limitu:

Vērtība maximum pasaka, uz kuru skaitli skatīties. Ja tā sakrīt ar vaicājumiem iestatītu vērtību, tas ir vaicājuma limits; ja tā ir tuvu lielākajai daļai servera RAM, tas ir visa servera limits.

Limiti un to noklusējumi

Tātad pašu uzturētā serverī ar noklusējuma iestatījumiem vienam vaicājumam parasti nav sava limita, un tas darbojas, līdz to aptur visa servera limits. Tāpēc (total) variants ir tik izplatīts serveros, kurus neviens nav noregulējis.

Atrodiet, kas izmantoja atmiņu

Sāciet ar neizdevušamies vaicājumiem. system.query_log pieraksta izņēmumus ar to kodu un atmiņu, ko vaicājums bija izmantojis:

SELECT event_time, user,
       formatReadableSize(memory_usage) AS mem,
       left(exception, 120)             AS error,
       left(query, 100)                 AS q
FROM system.query_log
WHERE event_date >= today() - 1
  AND type = 'ExceptionWhileProcessing'
  AND exception_code = 241
ORDER BY event_time DESC
LIMIT 20;

(total) gadījumā neizdevies vaicājums ir tikai daļa no ainas. Skatieties, kas darbojās vienlaikus ar to un kuru formu vaicājumi, veiksmīgi izpildoties, izmanto visvairāk atmiņas. normalized_query_hash sagrupē vaicājumus, kas atšķiras tikai ar literāļu vērtībām:

SELECT normalized_query_hash,
       count()                               AS runs,
       formatReadableSize(max(memory_usage)) AS peak_mem,
       any(left(query, 100))                 AS sample
FROM system.query_log
WHERE event_date >= today() - 1
  AND type = 'QueryFinish'
GROUP BY normalized_query_hash
ORDER BY max(memory_usage) DESC
LIMIT 10;

Ja problēma notiek tieši tagad, system.processes rāda pašreizējo un maksimālo atmiņu katram strādājošam vaicājumam:

SELECT query_id, user, elapsed,
       formatReadableSize(memory_usage)      AS mem,
       formatReadableSize(peak_memory_usage) AS peak,
       left(query, 80)                       AS q
FROM system.processes
ORDER BY memory_usage DESC;

Dokumentācijā norādīts, ka memory_usage tur var neietvert dažus speciālas atmiņas veidus, tāpēc uztveriet to kā apakšējo robežu. Ja viens vaicājums acīmredzami dominē un nav būtisks, KILL QUERY WHERE query_id = '...' atbrīvo serveri visiem pārējiem. Jaunākie ieraksti system.query_log nonāk pēc izrakstīšanas intervāla; izpildiet SYSTEM FLUSH LOGS, ja tie vajadzīgi nekavējoties.

Biežākie cēloņi

  1. Augstas kardinalitātes GROUP BY. Grupēšana pēc lietotāja ID, sesijas ID vai URL vairāku mēnešu datos veido hash tabulu ar ierakstu katrai atšķirīgai atslēgai. Tas ir klasisks veids, kā ClickHouse pietrūkst atmiņas.
  2. Join ar lielu labās puses tabulu. Uz hash balstītie join algoritmi labo pusi veido atmiņā. Ar lielo tabulu JOIN labajā pusē pietiek, lai izsmeltu RAM.
  3. Lielas kārtošanas ar ORDER BY lieliem rezultātiem bez LIMIT.
  4. Vienlaicīgums. Desmit vaicājumi, kuriem katram vajag 10% atmiņas, atsevišķi ir kārtībā, bet kopā – liktenīgi. No šejienes rodas (total) kļūda, lai gan neviens atsevišķs vaicājums neizskatās ekstrēms.
  5. Fona darbs. Sapludināšana un mutācijas konkurē par to pašu atmiņu. Daļu uzkrājums, kā aprakstīts mūsu "Too many parts" ceļvedī, rada serverim papildu slodzi.

Vispirms labojiet vaicājumu

Iestatījumi maina, kur nonāk atmiņa; vaicājuma izmaiņas samazina, cik tās vajag. Pirms palielināt kādu limitu, pārbaudiet, vai vaicājums var darīt mazāk darba:

Ļaujiet smagām operācijām izmantot disku

ClickHouse var daļu agregācijas, kārtošanas vai join pārvietot uz disku, nevis beigties ar kļūdu. Saskaņā ar iestatījumu izmaiņu vēsturi izlikšana uz disku GROUP BY un ORDER BY pēc noklusējuma ieslēgta kopš 25.1: max_bytes_ratio_before_external_group_by un max_bytes_ratio_before_external_sort ir 0.5, tātad operācija sāk izmantot disku, kad sasniegusi pusi pieejamās atmiņas. Versija 26.5 pievienoja tādu pašu attiecību hash join – max_bytes_ratio_before_external_join, arī 0.5. Absolūtie sliekšņi max_bytes_before_external_group_by un max_bytes_before_external_sort pēc noklusējuma ir 0.

Ja iestatāt absolūto slieksni, GROUP BY dokumentācija iesaka max_memory_usage iestatīt aptuveni divreiz lielāku, jo agregācija notiek divos posmos un uz disku var izlikt tikai pirmajā. Tās piemērs: max_bytes_before_external_group_by 10000000000 ar max_memory_usage 20000000000. Izkliedētiem vaicājumiem tā iesaka distributed_aggregation_memory_efficient = 1, lai serverī, kas apvieno rezultātus, atmiņas patēriņš paliktu zems. Un tā godīgi norāda cenu: kad dati nonāk uz diska, vaicājums ilgst vairākas reizes ilgāk, aptuveni trīs reizes.

Join gadījumā algoritms grace_hash sadala labo tabulu daļās (buckets), vienu patur atmiņā un pārējās ieraksta diskā, pievienojot daļas, ja hash tabula pārsniedz limitu. To var izvēlēties konkrētam vaicājumam ar SETTINGS join_algorithm = 'grace_hash'.

Iestatiet limitus, kas aizsargā serveri

Neierobežota atmiņa vaicājumam nozīmē, ka viens slikts vaicājums var nogāzt visu serveri. Iestatījumu profils ad-hoc un atskaišu lietotājiem notur to vaicājumus budžeta robežās:

CREATE SETTINGS PROFILE reports_limits
SETTINGS max_memory_usage = 20000000000,
         max_bytes_before_external_group_by = 10000000000,
         max_bytes_before_external_sort = 10000000000
TO report_user;

Ar vaicājuma limitu nekontrolēts vaicājums beidzas ar kļūdas Query variantu, nevis iegrūž serveri (total) limitā, paņemot līdzi citus vaicājumus.

ClickHouse ir arī atmiņas overcommit, ko dokumentācija apraksta kā eksperimentālu funkciju. Kad sasniegts visa servera limits, vaicājums īsu brīdi gaida, kamēr atmiņa tiks atbrīvota (memory_usage_overcommit_max_wait_microseconds, pēc noklusējuma 5 sekundes), un, ja nekas netiek atbrīvots, uzskaitītājs aptur vaicājumu ar lielāko piešķirtās atmiņas attiecību pret memory_overcommit_ratio_denominator (noklusējums 1 GiB). Praksē tas nozīmē, ka lielākais patērētājs tiek apturēts ar lielāku varbūtību nekā vaicājums, kas nejauši pēdējais pieprasīja atmiņu.

Nepalieliniet vienkārši limitu. Ja kļūdā redzams (total), max_server_memory_usage_to_ram_ratio palielināšana virs noklusējuma aizstāj tīru vaicājuma kļūdu ar risku, ka operētājsistēma nogalinās visu ClickHouse procesu. Vispirms samaziniet vai ierobežojiet slodzi; atmiņu pievienojiet tikai tad, ja darba datu apjomam tās patiešām vajag.

Ko uzraudzīt

Galvenās atziņas

ClickHouse Atmiņa Veiktspēja Incidentu reaģēšana
Sadarbība ar mums

ClickHouse vaicājumi beidzas ar Code 241?

Mēs atrodam vaicājumus un iestatījumus, kas izraisa atmiņas kļūdas, noregulējam limitus un izlikšanu uz disku un uzturam analītiku darbā, neatņemot resursus pārējam serverim.

Sazināties Vairāk no emuāra