të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
të
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
të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:17të
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 overheadMetër
Metër
Pse është spikingPse është spiking
1 000 kursorë = 1 000 ndërrime kontekstillogaritësCompute
të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 doc1 000 shëtitje index + 1 000 deserializations doc
tëRrjetitëÇdo udhëtim i rrumbullakët konsumon ~1 ms RTT + TLS overheadtëRrjetiNetwork
Ç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!”
të“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.
të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
- të
- Dokumenti i tërë është në faqe edhe nëse lexoni një fushë. të
- WiredTiger nuk mund të ruajë sa shumë dokumente për faqe → më e ulët cache hit ratio. të
- Të dhënat e indeksit janë të mëdha → bloom filter misses → more disk searches. të
SolutionNë :schema‑by‑access‑patternNë :
graph TD
Invoice[(invoices<br/><2 kB)] -->|ref| Hist[history<br/><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.
të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ë
- të
- Indeksi i ulët i kardinalitetit ({ tip: 1, ts: -1 }) – ri-rregulloni atë në { userId: 1, ts: -1 }. të
- $regex fillon – me në fushën jo-indeksuar – skanimin e string nga ferri. të
- findOneAndUpdate queue—document‐level locking bottleneck; përdorni Redis/Kafka. të
- skip + paginimi i madh i kompensimit - Mongo duhet të numërojë çdo dokumente të kaluara; kaloni në kursorët e gamës (ts, _id). të
Anatomia e kostos 101
“Por Atlas thotë se leximet janë të lira!”
të“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 $480Metrikë
tëVlerë
Vlerë
tëKostoja e njësisë
Kostoja e njësisë
Kosto mujoreMonthly 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 00 0 0 0 0 0 0
të702 dollarë
$702
Shkrimet (150 /s) 380 M $0.225 / M $86Fjalë kyçe (150 / s)Fjalë kyçe (150 / s)
të380 m
380 m
0.225 dollarë / m0.225 dollarë / m
86 dollarë$86
Transferimi i të dhënave 1.5 TB $0.25 / GB $375Transferimi i të dhënaveData transfer
të1.5 Mb
1.5 Mb
0.25 dollarë / GB0.25 dollarë / GB
375 dollarë$375
Ruajtja (2 TB) $0.24 / GB $480Hapësirë ruajtjeje (2 TB)Hapësirë ruajtjeje (2 TB)
të
$0.24 / GB
të480 dollarë
$480
Në total:$1,643.
Aplikoni këto fikse:
- të
- Leads rënë 70 % → $210 të
- Transferimi bie 80 % → $ 75 të
- Ruajtja bie 60 % → $192 të
Bileta e re: $ 564. Kjo është një inxhinier i nivelit të mesëm ose pistë deri në Q4 - ju zgjidhni.
të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 rateorë
orë
tëVeprimi
Action
tëmjetet
mjetet
fitonfiton
0‐2 Turn on profiler (slow = 50). Mongo shell Surface top 10 ops ngadalë.të0 – 2
0 – 2
tëKthehu në profil (slowms = 50).
Përdorimi i profilit (slowms = 50
) të
Shell Mongo
Shell Mongo
të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.
tëVS Kodi + Testet janë
VS Code + Jest tests
90 % më pak lexues90 % 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 – 106‑10
Shtoni parashikime dhe kufizoni gjetjet e pakufizuara.Përshkrimi i projekteve &limit
Gjenden dy të panjohura.
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
tëShpërndaje dosjet jumbo → metas + GridFS / S3.
Shpërndaje dosjet jumbo → metas + GridFS / S3.
tëSkenarë ETL
Scripted ETL
të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 30Create TTLs, month‑partition cold data, enable Online Archive.
tëAtlas UI
60 për qind e ruajtjes
të22‑30
22 e 30
të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 3630 e 36
të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.
të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ë Atlask6 + Metrikë Atlas
të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.
të - Kursi kthen > 1000 dokumente? → Paginate. të
- TTL në çdo tavolinë ngjarje / dyqan? (Po / Jo)
- Çdo indeks ku kardinaliteti < 10 %? → Drop/re‐order. të
- Profili ngadalëson > 1 % ops totale? → Optimizoni ose cache. të
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ëtaixScans
Formë 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.
të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
, logins
pa 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:
- të
- 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.
-
The system generates more than 15 thousand operations per second in its peak write performance when using one primary server.
-
Your main priorities should be maintaining sub-70-millisecond multi-region latency because high AWS billing costs do not represent your critical concern.
të
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ë Ram | 120 GB të |
36 GB | 70 % të |
Shërbimi i ngrohjes (hot) | 2.1 Mb |
600 GB | 71 për qind |
të Çmimi Atlas / Mo. | 15 284 dollarë | 3 210 dollarë | 79 për qind |
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ë
tëBefore
Before
PasPas
Δ
Δ
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 7006 700
900 të
900 të
të−86 %
−86 %
Shërbimi i ngrohjes (hot)të2.1 Mb600 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 qind71 për qind
p95 latenca 1.9 s 140 ms −92 %P95 PërmbajtjaP95 Përmbajtja
1.9 s1.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$lookup
pistons 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.