Elasticsearch Hot Shard Problém: Keď Jeden Node Robí Všetku Prácu
Jeden hot shard vie z kludneho clustera spravit permanentny poziar. “Máme 5 data nodov ale jeden je na 100% CPU zatiaľ čo ostatné sú nečinné.” Túto vetu som počul viackrát než dokážem spočítať, a príčina je takmer vždy rovnaká: hot shard. Elasticsearch sľúbil, že distribuuje vaše dáta naprieč clusterom, a urobil to—len nie rovnomerne. Jeden shard skončil s 50x viac dokumentmi než ostatné, a teraz je to úzke hrdlo ťahajúce nadol celý váš cluster.
Pamätám si prvýkrát, keď som narazil na tento problém. Mali sme krásny 10-nodový cluster, perfektne dimenzovaný podľa všetkých capacity planning guidelines. Napriek tomu boli search latencie astronomické a náš monitoring ukazoval jeden node konštantne na maxime. Trvalo nám trápne dlho uvedomiť si, že náš “distribuovaný” vyhľadávač sa v podstate stal single-node systémom pre naše najhorúcejšie queries.
Koreňová príčina bolo dizajnové rozhodnutie urobené mesiace predtým: routovali sme dokumenty podľa customer ID pre efektívnosť queries. Skvelý nápad v teórii—súvisiace dokumenty zostávajú spolu, čo robí filtrované queries rýchlejšie. Ale zabudli sme, že jeden z našich zákazníkov bol zodpovedný za 60% všetkých dokumentov. Ich shard bol enormný a každý query dotýkajúci sa ich dát šiel na rovnaký preťažený node.
Testované na: Elasticsearch 8.11, 5-nodový cluster, 100M dokumentov
Pochopenie Distribúcie Shardov
Aby ste mohli opraviť hot shardy, potrebujete pochopiť ako Elasticsearch rozhoduje kam dokumenty umiestniť.
Ako Routing Funguje
Default routing vzorec:
shard = hash(_routing) % number_of_primary_shards
_routing = document _id (defaultne)
= custom routing pole (ak špecifikované)
┌─────────────────────────────────────────────────────────────┐
│ Index: logs (5 primary shardov) │
├─────────────────────────────────────────────────────────────┤
│ Dokument s _id="abc123" │
│ → hash("abc123") % 5 = 2 │
│ → Ide do shard 2 │
│ │
│ Dokument s _id="def456" │
│ → hash("def456") % 5 = 4 │
│ → Ide do shard 4 │
│ │
│ Náhodné IDs = rovnomerná distribúcia (zvyčajne) │
└─────────────────────────────────────────────────────────────┘
Keď používate náhodné document IDs (ako UUIDs), hash funkcia distribuuje dokumenty pomerne rovnomerne naprieč shardmi. Ale keď používate custom routing alebo predvídateľné ID patterny, môžete skončiť s veľmi nerovnomernou distribúciou.
Kedy Hot Shardy Nastávajú
Existuje niekoľko bežných scenárov, ktoré vytvárajú hot shardy:
Scenár 1: Custom routing so skewed dátami
Index: orders (routing podľa customer_id)
Zákazník "amazon" = 50% všetkých objednávok
→ 50% dokumentov ide do JEDNÉHO shardu
→ Hot shard!
Scenár 2: Time-based indexy s nerovnomernými zápismi
Index: logs-2024.01.15 (5 shardov)
Burst logov o 14:00 všetky majú timestamp 14:xx:xx
→ Ak je timestamp v _id, podobné hashe
→ Hot shard počas burstu
Scenár 3: Sekvenčné IDs
Dokumenty s IDs: 1, 2, 3, 4, 5...
→ hash(1) % 5 = rovnaký shard pre patterny
→ Potenciálny hot shard
Najzákernejšie hot shardy pochádzajú z business distribúcie dát. E-commerce platformy majú “whale” zákazníkov, ktorí generujú neproporcionálny traffic. Multi-tenant SaaS produkty majú tenantov, ktorí tienia všetkých ostatných dohromady. Log agregačné systémy majú služby, ktoré generujú 100x viac logov než priemer. Kedykoľvek vaše dáta majú power-law distribúciu, routing podľa tej dimenzie vytvára hot shardy.
Dopad na Výkon
Hot shardy ubližujú výkonu viacerými spôsobmi:
Indexovanie: Hot node sa stáva úzkym hrdlom pre write throughput celého clustera. Keďže Elasticsearch čaká na potvrdenie primary shardu pred vrátením úspechu, pomalé indexovanie na jednom sharde spomaľuje všetky dokumenty idúce do toho shardu.
Vyhľadávanie: Queries, ktoré sa dotýkajú hot shardu, sú pomalé pretože ten node je preťažený. Elasticsearch používa scatter-gather model—query všetky shardy, zlúč výsledky—takže najpomalší shard určuje latenciu query.
Zdravie clustera: Hot node môže vyčerpať diskový priestor, pamäť alebo file descriptory pred ostatnými nodmi, spúšťajúc cluster-wide problémy ako realokácia shardov alebo split-brain scenáre.
Detekcia Hot Shardov
Predtým než môžete opraviť hot shardy, potrebujete ich nájsť. Tu je niekoľko metód detekcie.
Cat Shards API
Najjednoduchší prístup je cat shards API:
# Skontroluj veľkosti shardov a počty dokumentov
curl -s "localhost:9200/_cat/shards/myindex?v&h=index,shard,prirep,docs,store,node"
# Výstup:
index shard prirep docs store node
myindex 0 p 1000000 500mb node-1
myindex 1 p 1000000 500mb node-2
myindex 2 p 50000000 25gb node-3 ← HOT SHARD!
myindex 3 p 1000000 500mb node-4
myindex 4 p 1000000 500mb node-5
V tomto príklade má shard 2 50 miliónov dokumentov zatiaľ čo ostatné majú 1 milión každý. Ten 50x rozdiel je kričiaci hot shard. Store size (25gb vs 500mb) to robí ešte očividnejšie.
Node Stats API
Pre detailnejší pohľad použite node stats API:
# Skontroluj indexing rate per node
curl -s "localhost:9200/_nodes/stats/indices/indexing?pretty" | \
jq '.nodes | to_entries[] | {node: .value.name, indexing_total: .value.indices.indexing.index_total}'
# Skontroluj search rate per node
curl -s "localhost:9200/_nodes/stats/indices/search?pretty" | \
jq '.nodes | to_entries[] | {node: .value.name, query_total: .value.indices.search.query_total}'
Ak jeden node má významne vyššie indexing alebo search counts, spracováva viac trafficu než jeho peers—pravdepodobne kvôli hot shardu.
Thread Pool Stats
Skontrolujte či sú thread pooly nodu saturované:
curl -s "localhost:9200/_cat/thread_pool?v&h=node_name,name,active,queue,rejected"
# Hľadajte:
# - Vysoké 'active' counts na jednom node
# - Rastúca 'queue' na jednom node
# - Akékoľvek 'rejected' záznamy (indikuje preťaženie)
Rejected tasks sú jasný znak preťaženia. Ak jeden node rejectuje tasks zatiaľ čo ostatné sú idle, máte hot shard.
Prometheus Queries
Pre kontinuálny monitoring použite Prometheus metriky:
# Indexing rate podľa nodu (mali by byť podobné)
rate(elasticsearch_indices_indexing_index_total{node=~".*"}[5m])
# Nerovnováha veľkosti shardov
max(elasticsearch_indices_store_size_bytes) /
avg(elasticsearch_indices_store_size_bytes)
# Ak > 2, máte nerovnováhu
# CPU nerovnováha naprieč nodmi
max(elasticsearch_os_cpu_percent) / avg(elasticsearch_os_cpu_percent)
# Ak > 1.5, investigujte hot shardy
Nastavte alerty keď tieto pomery prekročia thresholdy, aby ste zachytili hot shardy predtým než spôsobia výpadky.
Riešenia
Keď ste identifikovali hot shard, tu sú stratégie na jeho opravu.
1. Routing Partition Size
Ak musíte používať custom routing (pre efektívnosť queries), použite routing partition size na rozloženie dokumentov cez viaceré shardy:
# Namiesto routingu do 1 shardu, routuj do viacerých
PUT /orders
{
"settings": {
"number_of_shards": 30,
"routing_partition_size": 6
},
"mappings": {
"_routing": {
"required": true
}
}
}
# Teraz: shard = (hash(_routing) + hash(_id) % partition_size) % shards
# Rovnaké customer_id ide do 6 rôznych shardov
# Rozkladá hot zákazníkov naprieč nodmi
S routing partition size sa jedna routing hodnota (ako customer ID) teraz mapuje na 6 rôznych shardov namiesto 1. Dokumenty vášho najväčšieho zákazníka sú rozložené cez 6 shardov, znižujúc horúcosť akéhokoľvek jednotlivého shardu.
Kompromis je efektívnosť queries: queries filtrované podľa customer ID teraz potrebujú prehľadať 6 shardov namiesto 1. Ale 6 shardov cez 10-nodový cluster je stále ďaleko lepšie než jeden preťažený shard.
2. Index Rollover so Shard Sizing
Použite ILM (Index Lifecycle Management) na vytváranie menších indexov častejšie:
# Použi ILM pre častejší rollover
PUT _ilm/policy/hot_shards_policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "10gb", # Menšie shardy
"max_docs": 10000000, # Alebo doc count
"max_age": "1h" # Alebo čas
}
}
}
}
}
}
# Viac indexov = viac shardov = lepšia distribúcia
Častejším rolloverom indexov vytvárate viac shardov distribuovaných naprieč clusterom. Aj keď každý index má hot shardy, sú rozložené cez rôzne nody v čase.
3. Shard Allocation Awareness
Použite allocation awareness na rozloženie shardov naprieč failure domainami:
# elasticsearch.yml - vynúť shardy cez zóny
cluster.routing.allocation.awareness.attributes: zone
node.attr.zone: zone1 # Nastav per node
# Zabezpečuje že repliky sú v rôznych zónach
# Rozkladá read load cez zóny
Aj keď toto neopravuje hot shardy priamo, zabezpečuje že aspoň repliky sú na rôznych nodoch. Read requesty môžu byť obslúžené replikami, distribuujúc read load aj keď jeden primary shard je hot.
4. Hot-Warm-Cold Architektúra
Pre time-series dáta implementujte hot-warm-cold tiering:
# Presuň hot shardy na dedikované hot nody
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.awareness.attributes": "data_tier"
}
}
# Hot tier: SSDs, vysoké CPU
# Warm tier: HDDs, nižšie CPU
# Routuj aktuálne indexy do hot tieru
Umiestnením vašich najhorúcejších (najnovších) dát na dedikované high-performance nody, obmedzíte hot shard problém na hardware navrhnutý na jeho zvládanie. Hot tier spracováva aktuálne zápisy a queries, zatiaľ čo staršie dáta sa presúvajú na lacnejší hardware.
5. Reindex s Lepším Routingom
Ak je vaša aktuálna routing stratégia fundamentálne zlomená, niekedy je jediné riešenie reindexovať s lepšou stratégiou:
# Reindex bez routingu (nechaj ES distribuovať podľa _id)
POST _reindex
{
"source": {
"index": "orders_old"
},
"dest": {
"index": "orders_new"
}
}
# Alebo reindex s kompozitným routingom
POST _reindex
{
"source": {
"index": "orders_old"
},
"dest": {
"index": "orders_new",
"routing": "customer_id_date" # Nové routing pole
},
"script": {
"source": "ctx._routing = ctx._source.customer_id + '_' + ctx._source.order_date.substring(0,10)"
}
}
Reindexovanie je drahé ale niekedy potrebné. Kompozitný routing kľúč (customer + date) distribuuje dokumenty jedného zákazníka cez veľa shardov v čase.
Prevenčné Stratégie
Najlepšie riešenie je predchádzať hot shardom v prvom rade.
Dobrý Dizajn Routing Kľúča
# Zle: Routuj podľa zákazníka (vytvára hot shardy pre veľkých zákazníkov)
doc = {
"_routing": customer_id, # "amazon" = 50% trafficu
"data": {...}
}
# Lepšie: Kompozitný routing kľúč
doc = {
"_routing": f"{customer_id}_{order_date}", # Distribuuje v čase
"data": {...}
}
# Najlepšie: Vyhni sa routingu pokiaľ nie je nutný
# Nechaj Elasticsearch použiť document _id pre routing
Spochybnite či vôbec potrebujete custom routing. Benefit výkonu queries z ko-lokovaných dokumentov je často menší než očakávané, najmä s moderným SSD storage a efektívnym cachingom.
Shard Sizing Guidelines
Dodržujte tieto pravidlá pre shard sizing:
- Cieľová veľkosť shardu: 10-50GB - Dostatočne malý na presun, dostatočne veľký na efektívnosť
- Shardy na node: 20-25 na GB heapu - Za týmto máte overhead
- Počet dokumentov: < 200M na shard - Pre rozumný query výkon
Ak by váš najväčší zákazník vytvoril 200GB shard, potrebujete viac shardov alebo inú routing stratégiu.
Monitoring Dashboard
Nastavte proaktívny monitoring:
# Alert na nerovnováhu shardov
- alert: ElasticsearchShardImbalance
expr: |
max(elasticsearch_indices_store_size_bytes) /
avg(elasticsearch_indices_store_size_bytes) > 3
for: 30m
annotations:
summary: "Nerovnováha veľkosti shardov > 3x priemer"
# Alert na CPU skew nodu
- alert: ElasticsearchHotNode
expr: |
max(elasticsearch_os_cpu_percent) /
avg(elasticsearch_os_cpu_percent) > 2
for: 15m
annotations:
summary: "Jeden node spracováva neproporcionálnu záťaž"
# Alert na rejected tasks
- alert: ElasticsearchRejectedTasks
expr: |
rate(elasticsearch_thread_pool_rejected_total[5m]) > 0
for: 5m
annotations:
summary: "Elasticsearch rejectuje tasks - investigujte hot shardy"
Checklist
## Hot Shard Prevencia
### Detekcia
- [ ] Monitoruj veľkosti shardov cez _cat/shards
- [ ] Alert na nerovnováhu > 3x
- [ ] Dashboard ukazujúci per-node CPU/indexing rate
- [ ] Monitoruj thread pool rejected counts
### Dizajn
- [ ] Vyhni sa routingu podľa high-cardinality skewed polí
- [ ] Použi routing_partition_size keď routing potrebný
- [ ] Zváž kompozitné routing kľúče
- [ ] Dimenzuj shardy na 10-50GB
### Operations
- [ ] Použi ILM pre automatický rollover
- [ ] Dimenzuj shardy primerane (10-50GB)
- [ ] Implementuj hot-warm-cold architektúru
- [ ] Maj pripravené reindex runbooky
Záver
Hot shardy sú jedným z najbežnejších Elasticsearch performance problémov, a sú úplne preventabilné so správnym dizajnom:
- Monitoruj veľkosti shardov pre skorú detekciu nerovnováhy pred výpadkami
- Vyhni sa custom routingu pokiaľ ho naozaj nepotrebujete pre query výkon
- Použi routing_partition_size keď je routing potrebný na rozloženie hot zákazníkov
- Rolluj indexy často na redistribúciu dát naprieč clusterom
- Dimenzuj shardy správne aby jednotlivé shardy zostali spravovateľné
Skontrolujte _cat/shards teraz na vašom produkčnom clusteri. Možno máte hot shard ukrytý na očiach, čakajúci na zničenie vášho SLO počas ďalšieho traffic spike.
Súvisiace články
- Prometheus Kardinalita Explózia - Monitoring v škále výzvy
- Redis Memory Fragmentácia - Data store optimalizácia
- ClickHouse ReplacingMergeTree Deduplikácia - Distribuovaná databáza quirks
Súvisiace články
Index Ktorý Zabil Write Performance: Strata PostgreSQL HOT Updates
Pridanie indexu pre výkon spôsobilo 10x pomalšie zápisy. Kontra-intuitívna príčina: nový index rozbil HOT updaty, meniaci lacné in-place updates na drahé full-row rewrites s masívnym bloatom.
UUIDv4 vs ULID vs TSID: Dopad na PostgreSQL B-Tree Indexy po 100M Záznamoch
Náhodné UUID ako Primary Key spôsobujú index bloat a random I/O. Benchmark s konkrétnymi číslami - veľkosť indexu, cache hit ratio a WAL volume po 100M insertoch.
eBPF Off-CPU Analýza: Nájdenie Latencie Ktorú Metriky Nevidia
CPU je na 20% ale latencia je 500ms. Štandardné profilery neukazujú nič. Appka čaká, nepočíta. Ukážem ako použiť eBPF na nájdenie na čo čaká.
Vyčerpanie Connection Poolu: Tichý Spúšťač Výpadkov
Aplikácia visí, ale databáza vyzerá zdravo. Najčastejšie je vyčerpaný connection pool. Ukážem detekciu, rozumné dimenzovanie a prevenciu únikov spojení.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.