Späť na blog

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:

  1. Monitoruj veľkosti shardov pre skorú detekciu nerovnováhy pred výpadkami
  2. Vyhni sa custom routingu pokiaľ ho naozaj nepotrebujete pre query výkon
  3. Použi routing_partition_size keď je routing potrebný na rozloženie hot zákazníkov
  4. Rolluj indexy často na redistribúciu dát naprieč clusterom
  5. 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

Súvisiace články

Citujte tento článok

Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.

Michal Drozd. "Elasticsearch Hot Shard Problém: Keď Jeden Node Robí Všetku Prácu". https://www.michal-drozd.com/sk/blog/elasticsearch-hot-shard-problem/ (Publikované 16. októbra 2025).