Nova historia

Reduce os teus custos de MongoDB nun 79% con optimizacións de forma inicial

por Hayk Ghukasyan8m2025/04/18
Read on Terminal Reader

Demasiado longo; Ler

A factura de MongoDB dunha startup ficticia subiu un 20% cando Atlas auto-escalou a un M60. Ao perfilar operacións lentas, corrixir consultas N + 1 con $lookup, capping /TTL'ing consultas ilimitadas, refactoring documentos jumbo, e reordenar índices durante un sprint de 48 horas, eles reduciron o seu custo mensual de $ 15,284 a $ 3,210 (-79%) e melloraron a latencia p95 de 1,9 s a 140 msno-sharding necesario.
featured image - Reduce os teus custos de MongoDB nun 79% con optimizacións de forma inicial
Hayk Ghukasyan HackerNoon profile picture
0-item


que

Protexe a súa base de datos de incendios futuros para evitar perdas de capital a gran escala na súa etapa Serie A

que

Protexe a súa base de datos de incendios futuros para evitar perdas de capital a gran escala na súa etapa Serie A


que

Disclaimer: O seguinte é un estudo de caso ficticio usado para comunicar as mellores prácticas para o deseño de esquemas de MongoDB, axuste de rendemento e optimización de custos

que

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


O día en que se converteu en nuclear

A chamada chegou a través do2:17.


Atlas causou outra escalada de clúster de produción non solicitada que resultou nunhaM60máquina a un custo mensual de$15kO panel quería saber por que a queima aumentou en 20% mentres que o M60 serve como un caro$15 k/monthO sistema.


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();


Cada widget de dashboard requiriu que o delincuente puxese un total de1.7 GBA enorme cantidade de memoria usada creou picos de montaña no gráfico que se parecían ao Everest.


Os servidores M30 agora operan cun destes clusters. A solución non provocou un aumento de fragmentos.shape crimesexistía na base de código antes da eliminación.


Investigación da escena do crime

2.1 N + 1 Tsunami de Query

Isto é recoñecido como un anti-patrón - cando ordenar un conxunto de ordes require executar N consultas separadas para recuperar liñas de orde.

// 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

queCompute 1 000 cursores = 1 000 interruptores de contexto Almacenamento I/O 1 000 pasos de índice + 1 000 deserializacións de doc Rede Cada volta-trip consume ~1 ms RTT + TLS
Métro por que se espíaqueCalcula 1 000 cursores = 1 000 interruptores de contextoqueI/O de almacenamento 1 000 pasos de índice + 1 000 deserializacións docqueRede Cada ronda-viaxe consume ~1 ms RTT + TLS manexo sobre cabezaqueMétro por que se espíaque

Metros

Metros

Por que se espía

Por que se espía

Calcula 1 000 cursores = 1 000 interruptores de contextoComputacións

Compute

1 000 cursores = 1 000 interruptores de contexto

1 000 cursores = 1 000 interruptores de contexto

I/O de almacenamento 1 000 pasos de índice + 1 000 deserializacións docque

Servizos de almacenamento I/O

Storage I/O

1 000 paseos de índice + 1 000 deserializacións doc

1 000 paseos de índice + 1 000 deserializacións doc

Rede Cada ronda-viaxe consume ~1 ms RTT + TLS manexo sobre cabezaRede

Network

Cada ronda-viaxe come ~1 ms RTT + TLS manexo sobre a cabeza

Cada ronda-viaxe come ~1 ms RTT + TLS manexo sobre a cabeza


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 } }
]);


A latencia p95 caeu de 2.300 ms a 160 ms.

2 300 ms160 millóns

Páxinas que ligan con read-ops:101 → 1.Isto é 99% de desconto - non é necesario ningún código de cupón.


2.2 Unbounded Query Firehose

que

"Pero temos que amosar a historia completa do clic!"

que

“But we have to show the full click history!”


Claro - só non nun único cursor.

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


Fix: hard-cap o lote e proxectar só os campos que renderiza.

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);


Entón deixe Mongo limpar detrás de ti:

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


Un cliente de fintech reduciu a súa factura de almacenamento nun 72% ao longo da noite simplemente engadindo TTLs.

Un cliente de fintech reduciu a súa factura de almacenamento nun 72% ao longo da noite simplemente engadindo TTLs.


2.3 Jumbo-Document Money Pit Páxina

Mongo capas documentos en 16 MB, pero calquera cousa máis de 256 KB xa é unha bandeira vermella.

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


Why it hurts

  1. Todo o documento está pagado, aínda que lea un campo.
  2. que
  3. WiredTiger non pode almacenar tantos documentos por páxina → menor ratio de hit de caché.
  4. que
  5. As entradas de índice son enormes → o filtro de bloom perde → máis discos buscan.
  6. que

Solution: schema‑by‑access‑pattern: de

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


que

Os metas de pequenas facturas permanecen quentes; BLOBS en S3 custa $ 0,023 / GB-mes en vez de NAND-grade Atlas SSDs.

que

Os metas de pequenas facturas permanecen quentes; BLOBS en S3 custa $ 0,023 / GB-mes en vez de NAND-grade Atlas SSDs.


Four More Shape Crimes You’re Probably Guilty Of

    que
  1. Baixo índice de cardinalidade ({ tipo: 1, ts: -1 })—re-ordeo a { userId: 1, ts: -1 }.
  2. que
  3. $regex comeza no campo non indexado - escaneo de cadeas desde o inferno.
  4. que
  5. findOneAndUpdate queue—document‐level locking bottleneck; use Redis/Kafka.
  6. que
  7. Mongo debe contar cada documento salto; cambie para os cursores de rango (ts, _id).
  8. que

Anatomía de custos 101

que

“Pero Atlas di que as lecturas son baratas!”

“Pero Atlas di que as lecturas son baratas!”


Let’s do the math.

queValor métrico custo mensualquequequequequequequequeque

Ler máis (3 k/s)

que

7.8 B ao

$0.09 / M

702 millóns

Escrito (150 / s)

380 m

$ 0.225 / M

que

86 millóns

Data transfer

que

5 TB

0,25 € / GB

$375

que

Storage (2 TB)

que


0,24 € / GBque

$480

Valor métrico custo mensualqueLer máis (3 k/s)que7.8 B aoque$0.09 / M702 millónsquequeEscribe (150 /s) 380 M $0.225 / M $86queTransferencia de datos 1.5 TB $0.25 / GB $375quequeEspazo de almacenamento (2 TB)quequeque0,24 € / GBqueque

480 millóns

quequeValor métrico custo mensualque

Metroloxía

Metroloxía

valor

valor

Custo da unidade

Custo da unidade

Custo mensual

Custo mensual

Ler máis (3 k/s)que7.8 B aoque$0.09 / M702 millónsqueque

Ler máis (3 k/s)

Ler máis (3 k/s)

que

7.8 B ao

7.8 B ao

$0.09 / M

$0.09 / M

702 millóns

$702

Escrito (150 / s)que380 m$ 0.225 / Mque86 millónsqueEscrito (150 / s)

Escrito (150 / s)

380 m

380 m

que

$ 0.225 / M

$ 0.225 / M

que

86 millóns

$86

Transferencia de datos 1.5 TB $0.25 / GB $375Transferencia de datos

Transferencia de datos

que

5 TB

5 TB

0,25 € / GB

0,25 € / GB

375 millóns

$375

queEspazo de almacenamento (2 TB)quequeque0,24 € / GBqueque

480 millóns

queque

Storage (2 TB)

Espazo de almacenamento (2 TB)

que



0,24 € / GB

0,24 € / GB

que

480 millóns

$480


En total:$1,643.

Aplique os fixos:

    que
  • As lecturas caen un 70% → $210
  • que
  • Transferencia cae 80% → $75
  • que
  • O almacén cae 60% → $192
  • que


que

Nova factura: $ 564. que é un enxeñeiro de nivel medio ou pista ata o cuarto cuarto - escolle.

que

New bill: $564.É un enxeñeiro de nivel medio.orPunto de saída para o Q4 - escolle.


48-Hour Rescue Sprint (Tempo de batalla probado)

queHour 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 testa un 90% menos de lecturas. 6‐10 Engade proxeccións e límites a achados ilimitados. API layer RAM steady; API 4× máis rápido. 10‐16 Break jumbo docs → metas + GridFS/S3. Scripted ETL Working set fits in RAM. 16‐22 Drop/replace indexes de baixa cardinality. Compass Disk shrinks; cache hits ↑. 22‐30 Crea TTLs, datos fríos de partición mensual, habilita o Arquivo en liña. Atlas UI 60 % de almacenamento gardado. 30‐36 Engade paneis de gráficos: hit cache
Horas de acción ferramenta gañaque0‐2 Turn on profiler (slow = 50). Mongo shell Surface top 10 slow ops.que2‐6 Reescribe N + 1 en $lookup. VS Código + Jest proba un 90% menos de lecturas.que6‐10 Engadir proxeccións e limitar os achados ilimitados. API capa RAM constante; API 4x máis rápido.que10‐16 Break jumbo docs → metas + GridFS/S3. Scripted ETL Working set encaixa en RAM.quequeque

16 ao 22

queBaixar / substituír índices de baixa cardinalidade.queCompás

Disc shrinks; cache hits ↑.

queque22‐30 Crear TTLs, datos fríos de particións mensuais, habilitar o Arquivo en liña.que30‐36 Engadir paneis de Grafana: Hit de caché %, scan:ix ratio, taxa de expulsión.que36‐48 queLoad‐test con k6 k6 + métricas Atlas Confirm p95 < 150 ms @ 2× carga.queHoras de acción ferramenta gañaque

Hora

Hora

que

Accións

Accións

que

Tool

Tool

que

Gañou

Gañou

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

0‐2

Xire o perfil (lentos = 50).

Turn on profiler (slowms = 50).

Shell de Mongo

Mongo shell

Descrición do xogo Surface Top 10 Slow Ops.

Descrición do xogo Surface Top 10 Slow Ops.

2‐6 Reescribe N + 1 en $lookup. VS Código + Jest proba un 90% menos de lecturas.que

2‐6

2‐6

que

Escribe N + 1 en $lookup.

Escribe N + 1 en$lookup. .

que

VS Código + Jest Probas

VS Código + Jest Probas

Un 90% menos de lectores.

Un 90% menos de lectores.

queque

6 ó 10

que

Add projections & limit to unbounded finds.

queque

API layer

queRAM estable; API 4x máis rápido.que

6 ó 10

6 ó 10

Engadir proxeccións e limitar os achados ilimitados.

Add projections & limitdos descubrimentos ilimitados.

que

API layer

Liña de lume

RAM steady; API 4× faster.

RAM steady; API 4× faster.

10‐16 Break jumbo docs → metas + GridFS/S3. Scripted ETL Working set encaixa en RAM.que

10 ó 16

10 ó 16

que

Combina os documentos jumbo → metas + GridFS/S3.

Break jumbo docs → metas + GridFS/S3.

que

Proxecto ETL

Proxecto ETL

que

Funcionan en conxunto con RAM.

Funcionan en conxunto con RAM.

que

16 ao 22

queBaixar / substituír índices de baixa cardinalidade.queCompás

Disc shrinks; cache hits ↑.

queque

16 ao 22

16 ao 22

que

Drop/replace low‑cardinality indexes.

Drop/replace low‑cardinality indexes.

que

Compass

Compás

Disc shrinks; cache hits ↑.

Disk shrinks; cache hits ↑.

queque

22‑30

Crear TTLs, particións de datos fríos de mes, habilitar Arquivo en liña.

Atlas de UIque

60 % storage saved.

queque

22‑30

22‑30

que

Crear TTLs, particións de datos fríos de mes, habilitar Arquivo en liña.

Crear TTLs, particións de datos fríos de mes, habilitar Arquivo en liña.

Atlas de UI

Atlas de UI

que

60 % storage saved.

60 % storage saved.

30 ó 36

Engadir os paneis de Grafana: cache hit %, scan:ix ratio, taxa de exclusión.

PrometeoqueAlerta visual precoz.que

30 ó 36

30 ó 36

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

Engadir os paneis de Grafana: cache hit %, scan:ix ratio, taxa de exclusión.

Prometeo

Prometeo

Alerta visual precoz.

Alerta visual precoz.

que

36 ó 48

que

Load‑test with k6

queque

k6 + Atlas métricas

Confirmar p95 < 150 ms @ 2× carga.que

36 ó 48

36 ó 48

que

Load‑test with k6

Proba de carga con K6

que

k6 + Atlas métricas

k6 + Atlas metrics

que

Confirmar p95 < 150 ms @ 2× carga.

Confirmar p95 < 150 ms @ 2× carga.


Self‑Audit Checklist—Pin It Above Your Desk

  • Largest doc ÷ median > 10? → Refactor.

  • Cursor returns > 1 000 docs? → Paginate.

  • que
  • TTL on every event/store table? (Yes/No)

  • que
  • Any index where cardinality < 10 %? → Drop/re‑order.

  • Profiler slowops > 1 % total ops? → Optimize or 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.


Why Shape Beats Indexes

O planificador de consultas de MongoDB realiza unha busca baseada en custos entre os plans de candidatos.

workUnits = ixScans + fetches + sorts + #docs returned


Indexes only reduce ixScans. Bad shape inflates fetches and sorts, que moitas veces dominan. Exemplo:

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


Índice{ level: 1, ts: -1 } does not help planner avoid fetching every document when it adds a predicate to an unmentioned array field in your projections. Net result: 20 k fetches for 200 hits. Index should precede shape operations in daily operations.


Live Metrics You Should Be Watching (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


Alerta se > 10 % perde por 5 m.

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


que

Se escaneas 100 veces máis documentos do que volves, estás queimando diñeiro.

que

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


Hands‑On: Thin‑Slice Migration Script

Necesidade de crack unha 1‐TBevents collection into clicks,views,loginssen tempo de inactividade? usardouble‑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.


Cando o ShardingIs the Answer

Segundo a regra do polgar só debes esmagar se verificasone of these conditions comes true after optimizing your database:

  1. O sistema funciona cun conxunto de traballo que representa máis do 80% da RAM independentemente da taxa de rendemento da caché.
  2. The system generates more than 15 thousand operations per second in its peak write performance when using one primary server.

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


  5. que

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


Estudo de caso Wrap-Up

Metric Before After Δ pegada RAM 120 GB 36 GB −70 % Ler/seg 6 700 900 −86 % Almacenamento (quente) 2.1 TB 600 GB −71 % latencia p95 1.9 s 140 ms −92 % Atlas custo / mes $15 284 $3 210 −79 %
Metric Before After Δ pegada RAM 120 GB 36 GB −70 % Ler/seg 6 700 900 −86 % Almacenamento (quente) 2.1 TB 600 GB −71 % latencia p95 1.9 s 140 ms −92 % Atlas custo / mes $15 284 $3 210 −79 %que

Metroloxía

queAntesDespoisqueΔqueque

Metroloxía

Metroloxía

Antes

Antes

que

After

Despois

Δ

Δ

Pegadas de RAM120 GB máis

36 GB máis

que-70 por centoqueque

Pegadas de RAM

Pegadas de RAM

que

120 GB máis

120 GB máis

36 GB máis

36 GB máis

que

-70 por cento

−70 %

Lecturas / Secque6 700 persoas900 millónsqueO 86%que

Lecturas / Sec

Lecturas / Sec

6 700 persoas

6 700 persoas

que

900

900

O 86%

O 86%

queAlmacenaxe (quente)que2 TBque600 GB máisque- O 71%queAlmacenaxe (quente)

Almacenaxe (quente)

2 TB

2.1 TB

600 GB máis

600 GB máis

- O 71%

- O 71%

P95 Latitude1.9 Sque140 millónsque-92 por centoqueque

P95 Latitude

P95 Latitude

1.9 S

1.9 S

140 millóns

140 millóns

-92 por cento

-92 por cento

queAtlas de custos / mo.que15 284 millóns3 210 millónsque

−79 %

Atlas de custos / mo.

Atlas cost / mo.

15 284 millóns

15 284 millóns

$3 210

$3 210

que

- O 79 %

−79 %


que

Non hai fragmentos, non hai conxelación de código importante, só cirurxía de forma implacable.

que

Non hai fragmentos, non hai conxelación de código importante, só cirurxía de forma implacable.


Título orixinal: Debt vs. Death Spiral

O requisito de entregar rapidamente é obrigatorio, pero manter o traballo de baixa calidade pertence á acumulación voluntaria de débedas. O provedor de nube cobra intereses compostos que se acumulan cunha taxa anual de 1000% sobre a súa débeda non pagada. Examinamos as tarxetas de crédito de alto interese de MongoDB xa que representan os cinco crimes de forma que estudamos.


You need to open the profiler to work with the $lookupPistóns mentres engade po TTL, e despois implementa o teu proxecto en modo lixeiro. O teu panel e o teu equipo de desenvolvemento e o teu pager ás 02:17 obterán descanso de calidade.


Proceed with the refactoring of your code until the next autoscaling incident happens.

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks