add brain

This commit is contained in:
2026-03-12 15:17:52 +07:00
parent fd9f558fa1
commit e7821a7a9d
355 changed files with 93784 additions and 24 deletions

View File

@@ -0,0 +1,70 @@
---
title: Connection Pooling and Limits
description: Connection management best practices
tags: mysql, connections, pooling, max-connections, performance
---
# Connection Management
Every MySQL connection costs memory (~110 MB depending on buffers). Unbounded connections cause OOM or `Too many connections` errors.
## Sizing `max_connections`
Default is 151. Don't blindly raise it — more connections = more memory + more contention.
```sql
SHOW VARIABLES LIKE 'max_connections'; -- current limit
SHOW STATUS LIKE 'Max_used_connections'; -- high-water mark
SHOW STATUS LIKE 'Threads_connected'; -- current count
```
## Pool Sizing Formula
A good starting point for OLTP: **pool size = (CPU cores * N)** where N is typically 2-10. This is a baseline — tune based on:
- Query characteristics (I/O-bound queries may benefit from more connections)
- Actual connection usage patterns (monitor `Threads_connected` vs `Max_used_connections`)
- Application concurrency requirements
More connections beyond CPU-bound optimal add context-switch overhead without improving throughput.
## Timeout Tuning
### Idle Connection Timeouts
```sql
-- Kill idle connections after 5 minutes (default is 28800 seconds / 8 hours — way too long)
SET GLOBAL wait_timeout = 300; -- Non-interactive connections (apps)
SET GLOBAL interactive_timeout = 300; -- Interactive connections (CLI)
```
**Note**: These are server-side timeouts. The server closes idle connections after this period. Client-side connection timeouts (e.g., `connectTimeout` in JDBC) are separate and control connection establishment.
### Active Query Timeouts
```sql
-- Increase for bulk operations or large result sets (default: 30 seconds)
SET GLOBAL net_read_timeout = 60; -- Time server waits for data from client
SET GLOBAL net_write_timeout = 60; -- Time server waits to send data to client
```
These apply to active data transmission, not idle connections. Increase if you see errors like `Lost connection to MySQL server during query` during bulk inserts or large SELECTs.
## Thread Handling
MySQL uses a **one-thread-per-connection** model by default: each connection gets its own OS thread. This means `max_connections` directly impacts thread count and memory usage.
MySQL also caches threads for reuse. If connections fluctuate frequently, increase `thread_cache_size` to reduce thread creation overhead.
## Common Pitfalls
- **ORM default pools too large**: Rails default is 5 per process — 20 Puma workers = 100 connections from one app server. Multiply by app server count.
- **No pool at all**: PHP/CGI models open a new connection per request. Use persistent connections or ProxySQL.
- **Connection storms on deploy**: All app servers reconnect simultaneously when restarted, potentially exhausting `max_connections`. Mitigations: stagger deployments, use connection pool warm-up (gradually open connections), or use a proxy layer.
- **Idle transactions**: Connections with open transactions (`BEGIN` without `COMMIT`/`ROLLBACK`) are **not** closed by `wait_timeout` and hold locks. This causes deadlocks and connection leaks. Always commit or rollback promptly, and use application-level transaction timeouts.
## Prepared Statements
Use prepared statements with connection pooling for performance and safety:
- **Performance**: reduces repeated parsing for parameterized queries
- **Security**: helps prevent SQL injection
Note: prepared statements are typically connection-scoped; some pools/drivers provide statement caching.
## When to Use a Proxy
Use **ProxySQL** or **PlanetScale connection pooling** when: multiple app services share a DB, you need query routing (read/write split), or total connection demand exceeds safe `max_connections`.
## Vitess / PlanetScale Note
If running on **PlanetScale** (or Vitess), connection pooling is handled at the Vitess `vtgate` layer. This means your app can open many connections to vtgate without each one mapping 1:1 to a MySQL backend connection. Backend connection issues are minimized under this architecture.