505 lexime
505 lexime

Redukto kostot tuaja MongoDB me 79% me Shape-First Optimizations

nga Hayk Ghukasyan8m2025/04/18
Read on Terminal Reader

Shume gjate; Te lexosh

Duke profilizuar opsionet e ngadalta, duke rregulluar pyetjet N + 1 me $lookup, duke kapur / TTL'ing pyetjet e pakufizuara, refactoring dokumente jumbo, dhe ri-rregjistrimin e indekseve gjatë një sprint 48-orëshe, ata zvogëluar koston e tyre mujore nga $ 15,284 në $ 3,210 (-79%) dhe përmirësuar vonesën p95 nga 1.9 s në 140 msno sharding kërkuar.
featured image - Redukto kostot tuaja MongoDB me 79% me Shape-First Optimizations
Hayk Ghukasyan HackerNoon profile picture
0-item


Mbroni bazën tuaj të të dhënave nga zjarret e ardhshme për të shmangur humbje të mëdha kapitale në fazën tuaj të Serisë A

Mbroni bazën tuaj të të dhënave nga zjarret e ardhshme për të shmangur humbje të mëdha kapitale në fazën tuaj të Serisë A


Disclaimer: Më poshtë është një studim i rastit fiktiv i përdorur për të komunikuar praktikat më të mira për hartimin e skemës MongoDB, përshtatjen e performancës dhe optimizimin e kostos

Disclaimer: The following is a fictional case study used to communicate best practices for MongoDB schema design, performance tuning, and cost optimization


Dita kur ligji u bë bërthamor

Thirrja erdhi përmes2:17


Atlas shkaktoi një tjetër shkallëzim të klasterit të prodhimit të padëshiruar që rezultoi në njëM60makinë me një kosto mujore të$15kBordi donte të dinte pse djegia u rrit me 20% ndërsa M60 shërben si një shtrenjtë$15 k/monthsistemit të


I opened the profiler:

db.system.profile.aggregate([
  { $match: { millis: { $gt: 100 } } },
  { $group: {
      _id: { op: "$op", ns: "$ns", query: "$command.filter" },
      n: { $sum: 1 },
      avgMs: { $avg: "$millis" }
  }},
  { $sort: { n: -1 } }, { $limit: 10 }
]).pretty();


Çdo widget dashboard kërkoi që sulmuesi të tërheqë në një total të1.7 GBShuma e madhe e përdorimit të kujtesës krijoi majat e maleve në grafik që ngjanin me Everestin.


Serverat M30 tani punojnë me një nga këto klastra. Zgjidhja nuk çoi në një rritje të copave. Tre defekte të zakonshme të njohura siForma e krimitekzistonte në bazën e kodit para eliminimit.


Hetimi i skenës së krimit

2.1 N + 1 Çështja Tsunami

Kjo njihet si një anti-pattern – kur renditja e një grupi urdhëresh kërkon drejtimin e N pyetjeve të ndara për të gjetur linjat e urdhrave.

// Incorrect:  Orders   +   1 000 extra queries
const orders = await db.orders.find({ userId }).toArray();
for (const o of orders) {
  o.lines = await db.orderLines.find({ orderId: o._id }).toArray();
}


Hidden taxes

tëPërcaktoni pse rritet 1 000 kursorë = 1 000 ndërrime të kontekstit Storage I/O 1 000 shëtitje të indeksit + 1 000 deserializations të dokumenteve Rrjeti Çdo shëtitje e rrumbullakët konsumon ~1 ms RTT + TLS overhead
Metër Pse ajo spikestë1 000 kursorë = 1 000 ndërrime kontekstitëStorage I/O 1 000 index walks + 1 000 deserializationstëRrjeti Çdo udhëtim i rrumbullakët konsumon ~1 ms RTT + TLS overheadtëMetër Pse ajo spikestë

Metër

Metër

Pse është spiking

Pse është spiking

1 000 kursorë = 1 000 ndërrime kontekstillogaritës

Compute

1 000 kursorë = 1 000 ndërrime konteksti

1 000 kursorë = 1 000 ndërrime konteksti

Storage I/O 1 000 index walks + 1 000 deserializationstë

Fjalë kyçe I/O

Storage I/O

1 000 shëtitje index + 1 000 deserializations doc

1 000 shëtitje index + 1 000 deserializations doc

tëRrjetitëÇdo udhëtim i rrumbullakët konsumon ~1 ms RTT + TLS overheadtëRrjeti

Network

Çdo udhëtim i rrumbullakët konsumon ~1 ms RTT + TLS overhead

Çdo udhëtim i rrumbullakët konsumon ~1 ms RTT + TLS overhead


Refactor (4 lines):

// Success: Single round‑trip, 1 read unit per order
db.orders.aggregate([
  { $match: { userId } },
  { $lookup: {
      from: "orderLines",
      localField: "_id",
      foreignField: "orderId",
      as: "lines"
  }},
  { $project: { lines: 1, total: 1, ts: 1 } }
]);


Latency p95 u ul nga 2300 ms në 160 ms.

2300 milionë160 milionë

Përshkrimi i lexuesve:101 → 1.Kjo është 99% off – nuk ka nevojë për kodin e kuponit.


2.2 Unbounded Query Peshqirë zjarri

“Por ne duhet të tregojmë historinë e plotë të klikimeve!”

“Por ne duhet të tregojmë historinë e plotë të klikimeve!”


Sigurisht – vetëm jo në një kursor të vetëm.

// Failure: Streams 30 months of data through the API gateway
db.events.find({ userId }).toArray();


Fix: hard‑cap the batch and project only the fields you render.

db.events.find(
  { userId, ts: { $gte: ISODate(new Date() - 1000*60*60*24*30) } },
  { _id: 0, ts: 1, page: 1, ref: 1 }     // projection
).sort({ ts: -1 }).limit(1_000);


Pastaj le të Mongo pastruar prapa jush:

// 90‑day sliding window
db.events.createIndex({ ts: 1 }, { expireAfterSeconds: 60*60*24*90 });


Një klient fintech reduktoi faturën e tyre të ruajtjes me 72% gjatë natës thjesht duke shtuar TTL.

Një klient fintech reduktoi faturën e tyre të ruajtjes me 72% gjatë natës thjesht duke shtuar TTL.


2.3 Jumbo-Document Money Pit Pjesë

Mongo kap dokumentet në 16 MB, por çdo gjë mbi 256 KB është tashmë një flamur i kuq.

{
  "_id": "...",
  "type": "invoice",
  "customer": { /* 700 kB */ },
  "pdf": BinData(0,"..."),        // 4 MB binary
  "history": [ /* 1 200 delta rows */ ],
  "ts": ISODate()
}


Why it hurts

  1. Dokumenti i tërë është në faqe edhe nëse lexoni një fushë.
  2. WiredTiger nuk mund të ruajë sa shumë dokumente për faqe → më e ulët cache hit ratio.
  3. Të dhënat e indeksit janë të mëdha → bloom filter misses → more disk searches.

SolutionNë :schema‑by‑access‑patternNë :

graph TD
  Invoice[(invoices<br/>&lt;2 kB)] -->|ref| Hist[history<br/>&lt;1 kB * N]
  Invoice -->|ref| Bin[pdf‑store (S3/GridFS)]


Small invoice metas stay hot; BLOBS in S3 cost $0.023/GB‑month instead of NAND‑grade Atlas SSDs.

Metat e faturave të vogla mbeten të nxehta; BLOBS në S3 kushton $ 0,023 / GB-muaj në vend të NAND-grade Atlas SSDs.


Katër krime të tjera në formë që ndoshta jeni fajtorë

  1. Indeksi i ulët i kardinalitetit ({ tip: 1, ts: -1 }) – ri-rregulloni atë në { userId: 1, ts: -1 }.
  2. $regex fillon – me në fushën jo-indeksuar – skanimin e string nga ferri.
  3. findOneAndUpdate queue—document‐level locking bottleneck; përdorni Redis/Kafka.
  4. skip + paginimi i madh i kompensimit - Mongo duhet të numërojë çdo dokumente të kaluara; kaloni në kursorët e gamës (ts, _id).

Anatomia e kostos 101

“Por Atlas thotë se leximet janë të lira!”

“Por Atlas thotë se leximet janë të lira!”


Le të bëjmë matematikën.

tëKosto e Njësisë së Vlerës Metrike Kosto mujore Leads (3 k/s) 7.8 B $0.09 / M $702 Writes (150 / s) 380 M $0.225 / M $86 Transferimi i të dhënave 1.5 TB $0.25 / GB $375 Storage (2 TB) $0.24 / GB $480
Kosto Metrike e Vlerës Unitare Kosto mujoretëLeads (3 k/s) 7.8 B $0.09 / M $702tëShkrimet (150 /s) 380 M $0.225 / M $86Transferimi i të dhënave 1.5 TB $0.25 / GB $375tëRuajtja (2 TB) $0.24 / GB $480tëKosto Metrike e Vlerës Unitare Kosto mujoreMetrikë

Metrikë

Vlerë

Vlerë

Kostoja e njësisë

Kostoja e njësisë

Kosto mujore

Monthly cost

Leads (3 k/s) 7.8 B $0.09 / M $702Lexo më shumë (3 k/s)

Lexo më shumë (3 k/s)

8.3 B të

8.3 B të

0 0 0 0 0 0 0

0 0 0 0 0 0 0

702 dollarë

$702

Shkrimet (150 /s) 380 M $0.225 / M $86Fjalë kyçe (150 / s)

Fjalë kyçe (150 / s)

380 m

380 m

0.225 dollarë / m

0.225 dollarë / m

86 dollarë

$86

Transferimi i të dhënave 1.5 TB $0.25 / GB $375Transferimi i të dhënave

Data transfer

1.5 Mb

1.5 Mb

0.25 dollarë / GB

0.25 dollarë / GB

375 dollarë

$375

Ruajtja (2 TB) $0.24 / GB $480Hapësirë ruajtjeje (2 TB)

Hapësirë ruajtjeje (2 TB)


0.24 dollarë / GB

$0.24 / GB

480 dollarë

$480


Në total:$1,643.

Aplikoni këto fikse:

  • Leads rënë 70 % → $210
  • Transferimi bie 80 % → $ 75
  • Ruajtja bie 60 % → $192


Bileta e re: $ 564. Kjo është një inxhinier i nivelit të mesëm ose pistë deri në Q4 - ju zgjidhni.

Bileta e re: $ 564. Kjo është një inxhinier i nivelit të mesëm ose pistë deri në Q4 - ju zgjidhni.


48-Orë Shpëtim Sprint (Battle-tested Timeline)

tëHour Action Tool Wins 0‐2 Turn on profiler (slowms = 50). Mongo shell Surface top 10 slow ops. 2‐6 Rewrite N + 1 into $lookup. VS Code + Jest teston 90% më pak lexime. 6‐10 Add projections & limit to unbounded finds. API layer RAM steady; API 4× më i shpejtë. 10‐16 Break jumbo docs → metas + GridFS/S3. Scripted ETL Working set fits in RAM. 16‐22 Drop/replace low-cardinality indexes. Compass Disk shrinks; cache hits ↑. 22‐30 Create TTLs, month‐partition cold data, enable Online Archive. Atlas UI 60 % storage saved. 30‐36 Add Graph panels: hit cache %, scan: ratio, eviction rate
Hour Action Tool fitontë0‐2 Turn on profiler (slow = 50). Mongo shell Surface top 10 ops ngadalë.të2‐6 Rewrite N + 1 në $lookup. VS Code + Jest teston 90% më pak lexime.të6‐10 Shtoni projektime dhe kufizoni gjetjet e pakufizuara. shtresë API RAM qëndrueshme; API 4x më e shpejtë.të10‐16 Break jumbo docs → metas + GridFS/S3. Scripted ETL Working set përshtatet në RAM.të16‐22 Drop/replace low‐cardinality indexes. Compass Disk shrinks; cache hits ↑.të22‐30 Krijimi i TTL, të dhënat e ftohta të ndarjes së muajit, aktivizimi i Arkivimit Online. Atlas UI ruajti 60 % të ruajtjes.të30‐36 Shto panelet Grafana: hit cache %, scan:ix ratio, shkalla e shkarkimit.të36‐48 Test i ngarkesës me k6 k6 + metrics Atlas Konfirmoni p95 < 150 ms @ 2× ngarkesë.tëHour Action Tool fitontë

orë

orë

Veprimi

Action

mjetet

mjetet

fiton

fiton

0‐2 Turn on profiler (slow = 50). Mongo shell Surface top 10 ops ngadalë.të

0 – 2

0 – 2

Kthehu në profil (slowms = 50).

Përdorimi i profilit (slowms = 50) të

Shell Mongo

Shell Mongo

Surface Top 10 ops të ngadaltë

Surface Top 10 ops të ngadaltë

2‐6 Rewrite N + 1 në $lookup. VS Code + Jest teston 90% më pak lexime.

2 – 6

2 – 6

Rishkruani N + 1 në $lookup.

Rishkruani N + 1 në $lookup.

VS Kodi + Testet janë

VS Code + Jest tests

90 % më pak lexues

90 % më pak lexues

6 – 10tëShtoni parashikime dhe kufizoni gjetjet e pakufizuara.tëzjarrin e lëkurëstëRAM: API 4x më i shpejtëtë6 – 10

6‑10

Shtoni parashikime dhe kufizoni gjetjet e pakufizuara.

Përshkrimi i projekteve &limitGjenden dy të panjohura.

zjarrin e lëkurës

zjarrin e lëkurës

RAM: API 4x më i shpejtë

RAM: API 4x më i shpejtë

10‐16 Break jumbo docs → metas + GridFS/S3. Scripted ETL Working set përshtatet në RAM.

10‑16

10‑16

Shpërndaje dosjet jumbo → metas + GridFS / S3.

Shpërndaje dosjet jumbo → metas + GridFS / S3.

Skenarë ETL

Scripted ETL

Përgatitja e punimeve në RAM.

Working set fits in RAM.

të16 – 22tëZvogëloni / zëvendësoni indekset e ulët të kardinalitetit.tëKompasëDisk shrinks; cache hits ↑.të

16‑22

16 – 22

Drop/replace low‑cardinality indexes.

Drop/replace low‑cardinality indexes.

Compass

Kompasë

Disk shrinks; cache hits ↑.

Disk shrinks; cache hits ↑.

22 e 30

Create TTLs, month‑partition cold data, enable Online Archive.

Atlas UI

60 për qind e ruajtjes

22‑30

22 e 30

Krijo TTL, të dhënat e ftohta të ndarjes së muajit, aktivizoni Online Archive.

Krijo TTL, të dhënat e ftohta të ndarjes së muajit, aktivizoni Online Archive.

Atlas UI

Atlas për

60 për qind e ruajtjes

60 për qind e ruajtjes

të30 e 36tëtë

Add Grafana panels: cache hit %, scan:ix ratio, eviction rate.

Prometheus

tëParalajmërime të hershme.të30 e 36

30 e 36

Add Grafana panels: cache hit %, scan:ix ratio, eviction rate.

Add Grafana panels: cache hit %, scan:ix ratio, eviction rate.

Prometeu

Prometheus

Paralajmërime të hershme.

Paralajmërime të hershme.

36‑48

Test i ngarkesës me K6

k6 + Metrikë Atlastëtë

Confirm p95 < 150 ms @ 2× load.

36‑48

36‑48

Test i ngarkesës me K6

Test i ngarkesës me K6

k6 + Metrikë Atlas

k6 + Metrikë Atlas

Confirm p95 < 150 ms @ 2× load.

Konfirmoni p95 < 150 ms @ 2× ngarkesë.


Lista e kontrollit të vetë-auditimit - Pin It Above Your Desk

  • Largest doc ÷ median > 10? → Refactor.

  • Kursi kthen > 1000 dokumente? → Paginate.
  • TTL në çdo tavolinë ngjarje / dyqan? (Po / Jo)
  • Çdo indeks ku kardinaliteti < 10 %? → Drop/re‐order.
  • Profili ngadalëson > 1 % ops totale? → Optimizoni ose cache.

If primary cache hits remain under 90% it is wise to separate collections or add additional RAM memory post fixes.

Place the checklist on your laptop with adhesive glue after laminating it for printing.


Pse Shape Beats Indekset

MongoDB’s query planner does a cost‑based search across candidate plans. The cost vector includes:

workUnits = ixScans + fetches + sorts + #docs returned


Indekset e ulëtaixScansFormë e keqe inflatesfetchesdhesorts, which often dominate. Example:

db.logs.find(
  { ts: { $gte: start, $lt: end }, level: "error" }
).sort({ level: 1, ts: -1 });


Indeksi{ level: 1, ts: -1 }Planifikuesi nuk ndihmon në shmangien e marrjes së çdo dokumenti kur shton një predikat në një fushë të mos përmendur në array në parashikimet tuaja. Rezultati neto: 20 k merr për 200 goditje. Indeksi duhet të paraprijë operacionet e formës në operacionet e përditshme.


Metrat e gjalla që duhet të shikoni (Grafana PromQL)

# WiredTiger cache hit ratio
(rate(wiredtiger_blockmanager_blocks_read[1m]) /
 (rate(wiredtiger_blockmanager_blocks_read[1m]) +
  rate(wiredtiger_blockmanager_blocks_read_from_cache[1m]))
) < 0.10


Alert if > 10 % misses for 5 m.

# Docs scanned vs returned
rate(mongodb_ssm_metrics_documents[1m]{state="scanned"}) /
rate(mongodb_ssm_metrics_documents[1m]{state="returned"}) > 100


Nëse skanoni 100 herë më shumë dokumente se sa ktheheni, po djegni para.

If you scan 100× more docs than you return, you’re burning money.


Fjalë kyçe Thin-Slice Migration Script

Need to crack a 1‑TB events collection into clicks, views, loginspa vonesë? përdornidouble‑write / backfill pattern.

// 1. Add trigger
const changeStream = db.events.watch([], { fullDocument: 'updateLookup' });
changeStream.on('change', ev => {
  const dest = db[`${ev.fullDocument.type}s`];
  dest.insertOne({ ...ev.fullDocument });
});

// 2. Backfill historical in chunks
let lastId = ObjectId("000000...");
while (true) {
  const batch = db.events.find({_id: {$gt: lastId}}).sort({_id: 1}).limit(10_000);
  if (!batch.hasNext()) break;
  const docs = batch.toArray();
  docs.forEach(d => db[`${d.type}s`].insertOne(d));
  lastId = docs[docs.length - 1]._id;
}


Zero downtime, minimal extra storage (thanks to TTL), everyone sleeps.


When Sharding është the Answer

According to the rule of thumb you should shard only if you verify one of these conditions comes true after optimizing your database:

  1. Sistemi punon me një grup pune që përfaqëson më shumë se 80 për qind të RAM pavarësisht nga shkalla e performancës së cache.
  2. The system generates more than 15 thousand operations per second in its peak write performance when using one primary server.

  3. Your main priorities should be maintaining sub-70-millisecond multi-region latency because high AWS billing costs do not represent your critical concern.


The decision should be simple when the conditions do not match these rules.


Case Study Wrap‑Up

tëMetrika para pas ΔtëtëtëLeads/sec 6 700 900 −86 %tëtëp95 latenca 1.9 s 140 ms −92 %tëtëtë
Gjurmë Ram120 GB të

36 GB

70 % të
Shërbimi i ngrohjes (hot)2.1 Mb

600 GB

71 për qind

Çmimi Atlas / Mo.

15 284 dollarë3 210 dollarë79 për qind
Metrika para pas ΔtëGjurmë Ramtë120 GB tëtë

36 GB

70 % tëLeads/sec 6 700 900 −86 %Shërbimi i ngrohjes (hot)

2.1 TB

600 GB

të71 për qindtëp95 latenca 1.9 s 140 ms −92 %tëtë

Çmimi Atlas / Mo.

15 284 dollarë3 210 dollarëtë79 për qindtëMetrika para pas Δ

Metric

Metrikë

Before

Before

Pas

Pas

Δ

Δ

Gjurmë Ramtë120 GB tëtë

36 GB

të70 % tëtë

Gjurmë Ram

RAM footprint

120 GB të

120 GB të

36 GB

36 GB

70 % të

−70 %

Leads/sec 6 700 900 −86 %

Shkrimtarë / Sec

Shkrimtarë / Sec

6 700

6 700

900 të

900 të

−86 %

−86 %

Shërbimi i ngrohjes (hot)të2.1 Mb

600 GB

të71 për qindShërbimi i ngrohjes (hot)

Storage (hot)

2.1 TB

2.1 TB

600 GB

600 GB

71 për qind

71 për qind

p95 latenca 1.9 s 140 ms −92 %P95 Përmbajtja

P95 Përmbajtja

1.9 s

1.9 s

140 milionë

140 ms

92 për qind

92 për qind

tëtë

Çmimi Atlas / Mo.

15 284 dollarëtë3 210 dollarëtë79 për qindtëtë

Çmimi Atlas / Mo.

Çmimi Atlas / Mo.

15 284 dollarë

$15 284

3 210 dollarë

3 210 dollarë

79 për qind

−79 %


Asnjë copëza, asnjë ngrirje e madhe e kodit, vetëm kirurgji e formës së pamëshirshme.

No shards, no major code freeze, just ruthless shape surgery.


Takeaway: Debt vs. Death Spiral

Kërkesa për dorëzimin e shpejtë është e detyrueshme, por ruajtja e punës me cilësi të dobët i përket akumulimit vullnetar të borxheve. ofruesi i cloud-it ju ngarkon për interesin e përbërë që akumulohet me një normë vjetore prej 1000% mbi borxhin tuaj të papaguar. Ne kemi shqyrtuar kartat e kreditit me interes të lartë të MongoDB-së pasi ato përfaqësojnë pesë krimet e formës që kemi studiuar. Shkarkimi i këtyre borxheve brenda periudhës suaj aktuale të sprintit do të rezultojë në deklarata mirënjohëse teknike dhe financiare.


Ju duhet të hapni profilin për të punuar me$lookuppistons ndërsa shtoni pluhur TTL, dhe pastaj vendosni projektin tuaj në modalitetin e dobët. bordin tuaj dhe ekipin tuaj të zhvillimit dhe pager tuaj në 02:17 do të merrni pushim cilësor.


Vazhdoni me rifaktorizimin e kodit tuaj derisa të ndodh incidenti i ardhshëm i autoskalimit.

L O A D I N G
. . . comments & more!

About Author

Hayk Ghukasyan HackerNoon profile picture
Hayk Ghukasyan@hayk.ghukasyan
Senior Software Engineer and Backend Team Lead with 20+ years of experience. Passionate about system design, backend architecture, microservices, and helping others grow in tech.

VARUR TAGS

KY ARTIKU U PARAQIT NË...

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks