yaUlinzi wa database yako dhidi ya moto ujao ili kuepuka kupoteza fedha kubwa katika hatua yako ya Serie A
Ulinzi wa database yako dhidi ya moto ujao ili kuepuka kupoteza fedha kubwa katika hatua yako ya Serie A
Disclaimer: The following is a fictional case study used to communicate best practices for MongoDB schema design, performance tuning, and cost optimization
Disclaimer: The following is a fictional case study used to communicate best practices for MongoDB schema design, performance tuning, and cost optimization
Siku ambayo Sheria ilibadilika kwa nyuklia
Wito huo ulifanyika kwa kupitia2:17ya
Atlas ilisababisha upanuzi mwingine usiohitajika wa uzalishaji wa cluster ambayo ilisababishaM60mashine kwa gharama ya kila mwezi ya$15k. The board wanted to know why burn increased by 20% while M60 serves as an expensive $15 k/monthMfumo wa.
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();
Kila widget ya dashboard ilihitaji mwakilishi kuvutia kwa jumla ya1.7 GBKila dakika kabla ya rendering. kiasi kikubwa cha matumizi ya kumbukumbu iliundwa juu ya mlima katika chati ambayo ilionekana kama Everest.
Msajili wa M30 sasa hufanya kazi na mojawapo ya makundi haya. ufumbuzi haukuwa na ongezeko la shards.Jinsi ya kufanya uhalifuilikuwepo kwenye msingi wa codebase kabla ya kuondolewa.
Uchunguzi wa eneo la uhalifu
2.1 N + 1 ya Tsunami ya Query
Hii inatambuliwa kama anti-mfano - wakati utaratibu wa seti moja ya amri inahitaji kuendesha N maswali tofauti ili kupata mstari wa amri.
// 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
Mita ya | yaKwa nini inachukuliwa |
---|---|
Maelezo ya | ya1 000 cursors = 1 000 mabadiliko ya mazingira |
Mita ya
Kwa nini inachukuliwa
Compute
1 000 cursors = 1 000 mabadiliko ya mazingira
Storage I/O
1 000 index walezi + 1 000 doc deserializations
Network
Kila safari ya mzunguko inachukua ~1 ms RTT + TLS handshake juu ya kichwa
Kila safari ya mzunguko inachukua ~1 ms RTT + TLS handshake juu ya kichwa
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 kupungua kutoka 2 300 ms kwa 160 ms.
2 300 kwa ajili yaUrefu wa ms 160Atlas read‑ops: 101 → 1.Hiyo ni 99% chini—hakuna msimbo wa kuponi unahitajika.
2.2 Unbounded Query ya Firehose
“Lakini tunahitaji kuonyesha historia kamili ya click!”
ya“Lakini tunahitaji kuonyesha historia kamili ya click!”
Bila shaka - tu si katika cursor moja.
// Failure: Streams 30 months of data through the API gateway
db.events.find({ userId }).toArray();
Fix: hard-cap mfululizo na mradi tu masharti unayotengeneza.
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);
Then let Mongo clean up behind you:
// 90‑day sliding window
db.events.createIndex({ ts: 1 }, { expireAfterSeconds: 60*60*24*90 });
Mteja mmoja wa fintech aliipunguza akaunti yao ya kuhifadhi kwa 72% kwa usiku tu kwa kuongeza TTLs.
yaMteja mmoja wa fintech aliipunguza akaunti yao ya kuhifadhi kwa 72% kwa usiku tu kwa kuongeza TTLs.
2.3 Jumbo‑Document Money Pit
Mongo hufungua nyaraka kwenye 16 MB, lakini chochote zaidi ya 256 KB tayari ni bendera nyekundu.
{
"_id": "...",
"type": "invoice",
"customer": { /* 700 kB */ },
"pdf": BinData(0,"..."), // 4 MB binary
"history": [ /* 1 200 delta rows */ ],
"ts": ISODate()
}
Why it hurts
- ya
- Daktari wote ni ukurasa katika hata kama wewe kusoma shamba moja. ya
- WiredTiger haiwezi kuhifadhi docs nyingi kwa ukurasa → kiwango cha chini cha hit ya cache.
- Ununuzi wa index ni kubwa → filters ya bloom hupoteza → utafutaji zaidi wa diski. ya
Solution: schema‑by‑access‑pattern:
graph TD
Invoice[(invoices<br/><2 kB)] -->|ref| Hist[history<br/><1 kB * N]
Invoice -->|ref| Bin[pdf‑store (S3/GridFS)]
Meta za akaunti ndogo zinaendelea kuwa na joto; BLOBS katika S3 gharama $ 0,023 / GB mwezi badala ya NAND-grade Atlas SSDs.
yaMeta za akaunti ndogo zinaendelea kuwa na joto; BLOBS katika S3 gharama $ 0,023 / GB mwezi badala ya NAND-grade Atlas SSDs.
Vifaa 4 vya uhalifu ambavyo unaweza kuwa na hatia
- ya
- Kuanzisha mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi juu ya mlinzi.
- $regex huanza-na kwenye uwanja usio na indexed-kutafuta mstari kutoka jahanamu.
- findOneAndUpdate queue—document‑level locking bottleneck; use Redis/Kafka. ya
- skip + kubwa offset pagination—Mongo lazima kuhesabu kila doc skipped; kubadilisha kwa kiwango (ts, _id) cursors. ya
Mchakato wa Anatomy 101
“Lakini Atlas anasema kusoma ni ya bei nafuu!”
ya“Lakini Atlas anasema kusoma ni ya bei nafuu!”
Hebu tufanye kazi ya Math.
Mifumo ya Metric | yathamani ya | yaya Gharama ya unit | yaya Gharama ya kila mwezi |
---|---|---|---|
Maoni yako (3 k/s) | ya
7.8 ya B | 0 0 0 0 0 0 0 0 | yaya 702 |
Maelezo ya picha (150 / s) | ya 380 M | ya$ 0.225 / M kwa ajili ya | 86 kwa ajili ya |
Uhifadhi wa bure (2 TB) |
| ya
$0.24 / GB | ya $480 |
Mifumo ya Metric
thamani ya
Gharama ya unit
Gharama ya unit
Gharama ya kila mwezi
Gharama ya kila mwezi
Maoni yako (3 k/s)
7.8 ya B
0 0 0 0 0 0 0 0
ya 702
$702
Maelezo ya picha (150 / s)
Mita ya 380
380 M
$ 0.225 / M kwa ajili ya
$86
Uhamisho wa data
Uhamisho wa data
1.5 TB
Dola ya 0.25 / GB
$375
Uhifadhi wa bure (2 TB)
Dola ya 0.24 / GB
Dola ya 0.24 / GB
$480
Total: $1,643.
Fikiria juu ya fikra:
- Idadi ya wasomaji imepungua kwa asilimia 70 → $ 210
- Usafiri wa chini ya 80% → $ 75 ya
- Uhifadhi hupungua kwa 60% → $ 192
Akaunti mpya: $ 564. Hiyo ni mhandisi wa kati au runway hadi Q4 - unachagua.
yaNew bill: $564. That’s one mid‑level engineer auKuanzisha mlinzi juu ya msalaba wa Q4 - Chagua.
48-Hour Msaidizi Sprint (Battle-kujaribu Timeline)
Asilimia 90 ya wasomaji wanasoma kidogo.
Siku ya
Siku ya
Hatua ya
Zana ya
ya kushinda
ya kushinda
0 ya 2
Weka juu ya profile (slowms = 50).
Weka juu ya profile (slowms = 50).
Shell ya Mongo
Shell ya Mongo
Kuanzisha mlinzi juu ya 10 Slow Ops.
Kuanzisha mlinzi juu ya 10 Slow Ops.
90 % fewer reads.
2 ya 6
Kuandika tena N + 1 katika $lookup.
VS Code + Jest tests
90 % fewer reads.
Asilimia 90 ya wasomaji wanasoma kidogo.
6‑10
6 ya 10
Kuongeza makadirio & kupunguza kwa utafiti usio na kikomo.
Add projections & limit
Kuanzisha mlinzi juu ya msalaba wa mwisho.
API layer
RAM imara; API ya 4x ya haraka.
10‑16
Kuondoa jumbo docs → metas + GridFS / S3.
Maoni ya ETL
Mchakato wa kufanya kazi katika ram.
Working set fits in RAM.
16 ya 22
Drop/replace low‑cardinality indexes.
Kompyuta ya
Kompyuta ya
Disk shrinks; cache hits ↑.
Disk shrinks; cache hits ↑.
Tengeneza TTLs, data ya baridi ya kila mwezi, uwezesha Online Archive.
22 ya 30
22‑30
Tengeneza TTLs, data ya baridi ya kila mwezi, uwezesha Online Archive.
Tengeneza TTLs, data ya baridi ya kila mwezi, uwezesha Online Archive.
Atlas UI
Atlas ya
Asilimia 60 ya uhifadhi imehifadhiwa.
30 ya 36
Add Grafana panels: cache hit %, scan:ix ratio, eviction rate.
30 ya 36
30 ya 36
Kuongeza paneli za Grafana: Cache hit %, scan:ix ratio, kiwango cha kuondolewa.
Add Grafana panels: cache hit %, scan:ix ratio, eviction rate.
ya Prometheus
Visual early warnings.
Load‑test with k6
K6 + Mifumo ya Atlas
36‑48
Utafutaji wa K6
Load‑test with k6
K6 + Mifumo ya Atlas
k6 + Atlas metrics
Uhakikishe p95 < 150 ms @ 2× mzigo.
Confirm p95 < 150 ms @ 2× load.
Orodha ya kuangalia mwenyewe—Pin it juu ya meza yako
-
Largest doc ÷ median > 10? → Refactor.
ya - Kurejesha kurudi > 1000 docs? → Pageinate.
- TTL kwenye kila meza ya tukio / duka? (Yes/No)
- Kiashiria chochote ambapo kardinali < 10 %? → Drop/re‐order.
-
Profiler slowops > 1 % total ops? → Optimize or cache.
ya
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.
Kwa nini Shape Beats Indices
MongoDB’s query planner hufanya utafutaji wa gharama kwa mipango ya wagombea. Vector ya gharama inajumuisha:
workUnits = ixScans + fetches + sorts + #docs returned
Indexes only reduce ixScans
. Bad shape inflates fetches and sortsMara nyingi kuna hali ambapo ni muhimu kwenda kwa haraka kufanya kazi au biashara.Mafunzo:
db.logs.find(
{ ts: { $gte: start, $lt: end }, level: "error" }
).sort({ level: 1, ts: -1 });
Index { level: 1, ts: -1 }
husaidia Planner kuepuka kukusanya kila hati wakati anaongeza predicate kwa uwanja usiotajwa wa mfululizo katika makadirio yako. Matokeo ya net: 20k kukusanya kwa 200 hits. Index inapaswa kuja kabla ya shughuli za fomu katika shughuli za kila siku.
Mifano ya kuishi unapaswa kuangalia (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
Kumbuka ikiwa > 10 % hupoteza kwa mita 5.
# Docs scanned vs returned
rate(mongodb_ssm_metrics_documents[1m]{state="scanned"}) /
rate(mongodb_ssm_metrics_documents[1m]{state="returned"}) > 100
Ikiwa unatafuta docs 100x zaidi kuliko unavyowasilisha, unachoma pesa.
yaIkiwa unatafuta docs 100x zaidi kuliko unavyowasilisha, unachoma pesa.
Hands‑On: Thin‑Slice Migration Script
Unahitaji kuondoa 1 TBevents
Mkusanyiko waclicks
yaviews
yalogins
without downtime? Use the double‑write / backfillMfano wa.
// 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.
Wakati wa ShardingIs the Answer
Kwa mujibu wa kanuni ya thumb, unapaswa kuharibu tu ikiwa unathibitishaone of these conditions comes true after optimizing your database:
- ya
- Mfumo unafanya kazi na seti ya kazi ambayo inawakilisha zaidi ya asilimia 80 ya RAM bila kujali kiwango cha utendaji wa cache. ya
-
The system generates more than 15 thousand operations per second in its peak write performance when using one primary server.
- Priorities yako kuu inapaswa kuwa kudumisha chini ya millisecond 70 multi-region latency kwa sababu gharama kubwa ya malipo ya AWS sio wasiwasi wako muhimu. ya
The decision should be simple when the conditions do not match these rules.
Utafiti wa kesi Wrap-Up
ya Mifumo ya Metric | kabla ya |
Baada ya | yaya Δ |
---|---|---|---|
Picha ya ram | Kiwango cha GB 120 | ya
ya GB 36 | yaya −70 % | ya
Maoni ya Sekta / Sec | ya6 700 ya | ya
900 | ya
−86 % |
ya Uhifadhi wa hewa (Hot) | Mchakato wa 2.1 TB | ya Kiwango cha GB 600 | yaya 71% ya | ya
ya p95 latency | ya 1.9 s | yaUrefu wa 140 ms | yaya kwa asilimia 92 |
ya Gharama ya Atlas / mo. | yaMshahara wa 15 284 | Mshahara wa 3 210 | ya
kwa asilimia 79 | ya
kwa asilimia 70
Gharama ya Atlas / mo.
Mifumo ya Metric
Mifumo ya Metric
kabla ya
kabla ya
After
ya Δ
−70 %
RAM footprint
Kiwango cha GB 120
ya GB 36
−70 %
kwa asilimia 70
Reads/sec
6 700 ya
900
−86 %
kwa asilimia 86
Uhifadhi wa hewa (Hot)
Uhifadhi wa hewa (Hot)
Mchakato wa 2.1 TB
Kiwango cha GB 600
600 GB
71% ya
71% ya
p95 latency
1.9 s
Urefu wa 140 ms
140 ms
kwa asilimia 92
kwa asilimia 92
Gharama ya Atlas / mo.
Gharama ya Atlas / mo.
Gharama ya Atlas / mo.
Mshahara wa 15 284
Mshahara wa 3 210
kwa asilimia 79
Hakuna vichaka, hakuna baridi kubwa ya msimbo, tu upasuaji usio na huruma.
yaHakuna vichaka, hakuna baridi kubwa ya msimbo, tu upasuaji usio na huruma.
Maelezo ya mchezo Debt vs. Death Spiral
Mahitaji ya utoaji haraka ni lazima, lakini kudumisha kazi ya ubora mbaya ni sehemu ya kukusanya mapato ya kujitolea. Mtoa huduma wa wingu hutumia riba ya mchanganyiko ambayo inakuja kwa kiwango cha kila mwaka cha asilimia 1000 juu ya mapato yako yasiyo ya kulipwa. Tumechunguza kadi za mkopo za kiwango cha juu za MongoDB kama zinawakilisha uhalifu wa aina tano tuliyojadili. Kuondoa mapato haya ndani ya kipindi chako cha sprint sasa utafanya ripoti za kiufundi na kifedha za shukrani.
Unahitaji kufungua profile ili kufanya kazi na$lookup
Pistons wakati kuongeza mvuke wa TTL, na kisha kupitisha mradi wako katika hali ya lean. bodi yako na timu yako ya maendeleo na pager yako saa 02:17 itapata mapumziko ya ubora.
Endelea na refactoring ya msimbo wako mpaka tukio la baadaye la autoscaling linatokea.