395 lines
17 KiB
Markdown
395 lines
17 KiB
Markdown
# 🗄️ Databázová architektura
|
|
|
|
## Klasifikace databází
|
|
|
|
### Relační (SQL)
|
|
|
|
| DB | Licence | Use case |
|
|
|----|---------|----------|
|
|
| PostgreSQL | Open source | Univerzální, geospatial, analytika |
|
|
| MySQL | Open source | Web, LAMP stack |
|
|
| MariaDB | Open source | MySQL kompatibilní |
|
|
| Microsoft SQL Server | Proprietary | Enterprise .NET |
|
|
| Oracle DB | Proprietary | Enterprise |
|
|
| Amazon Aurora | Managed | MySQL/PostgreSQL kompatibilní |
|
|
|
|
### NoSQL
|
|
|
|
| Typ | DB | Use case |
|
|
|-----|----|----------|
|
|
| Document | MongoDB, Couchbase | JSON data, flexibilní schema |
|
|
| Key-Value | Redis, DynamoDB | Cache, session store, real-time |
|
|
| Wide-column | Cassandra, ScyllaDB | Time-series, IoT, velká data |
|
|
| Graph | Neo4j, Dgraph | Vztahy, doporučení, social grafy |
|
|
|
|
## Transaction isolation levels
|
|
|
|
| Úroveň | Dirty Read | Non-repeatable Read | Phantom Read | Serialization Anomaly |
|
|
|--------|-----------|---------------------|-------------|----------------------|
|
|
| **Read Uncommitted** | Ano (možné) | Ano | Ano | Ano |
|
|
| **Read Committed** | Ne (prevence) | Ano | Ano | Ano |
|
|
| **Repeatable Read** | Ne | Ne | Ano (PostgreSQL: Ne) | Ano |
|
|
| **Serializable** | Ne | Ne | Ne | Ne |
|
|
|
|
**Anomálie**:
|
|
- **Dirty Read** — čtení dat z necommitnuté transakce (data mohou být rollbacknuta)
|
|
- **Non-repeatable Read** — stejný dotaz vrátí jiná data (jiná transakce mezitím updatovala řádek)
|
|
- **Phantom Read** — stejný dotaz vrátí nové řádky (jiná transakce insertla data splňující podmínku)
|
|
- **Serialization Anomaly** — výsledek transakcí není ekvivalentní žádnému sériovému pořadí
|
|
|
|
### PostgreSQL specific
|
|
- **Read Uncommitted** se chová jako **Read Committed** (není implementováno)
|
|
- **Repeatable Read** v PG je **Snapshot Isolation** — zabraňuje i phantom reads
|
|
- **Serializable** v PG používá Serializable Snapshot Isolation (SSI) — detekce sériových konfliktů
|
|
|
|
## PostgreSQL detail
|
|
|
|
### MVCC (Multi-Version Concurrency Control)
|
|
|
|
- Každá transakce vidí snapshot dat (transaction snapshot) z okamžiku startu
|
|
- Staré verze řádků (tuple) zůstávají v tabulce, označené jako `xmax` / `xmin`
|
|
- INSERT vytvoří nový tuple s `xmin = current_xid`
|
|
- DELETE označí tuple `xmax = current_xid` (nezmizí hned)
|
|
- UPDATE = DELETE old + INSERT new
|
|
- VACUUM fyzicky maže tuple starší než nejstarší aktivní snapshot
|
|
|
|
### VACUUM a autovacuum
|
|
|
|
| Parametr | Popis | Výchozí |
|
|
|----------|-------|---------|
|
|
| `autovacuum_vacuum_threshold` | Min. mrtvých řádků pro spuštění | 50 |
|
|
| `autovacuum_vacuum_scale_factor` | % z tabulky jako threshold | 0.2 (20 %) |
|
|
| `autovacuum_analyze_threshold` | Min. změněných řádků pro ANALYZE | 50 |
|
|
| `autovacuum_vacuum_cost_limit` | Limituje I/O vacuum (prevence zátěže) | 200 |
|
|
| `autovacuum_naptime` | Interval mezi kontrolami | 1 min |
|
|
| `deadlock_timeout` | Detekce deadlocků | 1 s |
|
|
|
|
**Příznaky nedostatečného vacuum**:
|
|
- Růst tabulky (bloat) — staré tuple zabírají místo
|
|
- Zhoršení výkonu index scanů (VISIBLE MAP není aktuální)
|
|
- XID wraparound hazard — emergency vacuum (může zastavit DB)
|
|
|
|
### WAL archiving a PITR
|
|
|
|
```conf
|
|
# postgresql.conf
|
|
wal_level = replica # nebo logical
|
|
archive_mode = on
|
|
archive_command = 'aws s3 cp %p s3://backups/pg-wal/%f'
|
|
```
|
|
|
|
- **WAL** (Write-Ahead Log) — append-only log všech změn
|
|
- **WAL archiving** — kontinuální záloha WAL segmentů (16 MB)
|
|
- **PITR** (Point-In-Time Recovery) — obnova k libovolnému okamžiku
|
|
1. Restore base backup (pg_basebackup)
|
|
2. Replay WAL archivů až k cílovému času
|
|
3. `recovery_target_time = '2026-06-03 10:30:00 UTC'`
|
|
|
|
### Replication slots
|
|
|
|
- **Physical replication slot** — zaručuje, že WAL není smazán masterem, dokud ho replica nespotřebuje
|
|
- **Logical replication slot** — pro logickou replikaci (selectivní tabulky, transformace dat)
|
|
- **Riziko**: pokud replica spadne a slot není aktivní, WAL naroste na disku (disk full)
|
|
- Monitoring: `pg_replication_slots`, `pg_stat_replication`
|
|
|
|
## Replikace
|
|
|
|
| Typ | Popis | Latence |
|
|
|-----|-------|---------|
|
|
| Synchronní | Zápis potvrzen až po replikaci na všechny nod | Vysoká, ale konzistentní |
|
|
| Asynchronní | Zápis potvrzen ihned, replikace na pozadí | Nízká, možný data loss |
|
|
| Semi-synchronní | Potvrzení od majority nodů | Kompromis |
|
|
|
|
### Topologie
|
|
|
|
- **Leader-Follower** (Master-Slave) — čtení z replic
|
|
- **Leader-Leader** (Multi-master) — zápis na více nodů
|
|
- **Quorum-based** — R + W > N (Cassandra, DynamoDB)
|
|
|
|
## Index types
|
|
|
|
| Typ | Algoritmus | Use case | Operace | Poznámka |
|
|
|-----|-----------|----------|---------|----------|
|
|
| **B-tree** | Balanced tree | Většina dotazů — =, <, >, BETWEEN, IN, LIKE (prefix) | Rychlé vyhledávání, řazení | Výchozí v PostgreSQL, MySQL |
|
|
| **Hash** | Hash table | Pouze = (equality) | Rychlé lookup | Malá velikost, nelze range dotazy |
|
|
| **GiST** | Generalized Search Tree | Full-text, geometrie, intervaly, IP rozsahy | Rychlé: overlaps, contains, distance | GIST pro geometrii (PostGIS), full-text |
|
|
| **GIN** (Generalized Inverted Index) | Inverted index | Pole, JSONB, full-text search | contains (@>), overlaps (&&) | Pomalý build, rychlé čtení |
|
|
| **BRIN** (Block Range Index) | Min/Max per block range | Velké tabulky, data v pořadí (time-series) | Range dotazy na korelovaná data | Extrémně malý (tisíckrát menší než B-tree) |
|
|
| **SP-GiST** | Space-partitioned GiST | Quad-tree, KD-tree, radix tree | Partitioned search | Geografické clustery, síťová data |
|
|
|
|
## Index selection guide
|
|
|
|
| Query pattern | Doporučený index | Příklad |
|
|
|--------------|-----------------|---------|
|
|
| `WHERE user_id = 123` | B-tree na `user_id` | Uživatelský lookup |
|
|
| `WHERE status = 'active' AND created_at > '2026-01-01'` | Composite B-tree na `(status, created_at)` | Filtrace + range |
|
|
| `WHERE data @> '{"key": "value"}'` | GIN na JSONB sloupec | JSONB dotazy |
|
|
| `WHERE tags && ARRAY['urgent']` | GIN na pole | Tagy |
|
|
| `WHERE position <@> POINT(50, 14) < 1000` | GiST na geometry | Lokalitní dotazy |
|
|
| `WHERE event_time BETWEEN '2026-06-01' AND '2026-06-02'` | BRIN na `event_time` | Time-series, logy |
|
|
| `WHERE email = 'user@example.com'` | Hash na `email` | Equality only |
|
|
|
|
## Query execution
|
|
|
|
### Seq scan vs Index scan vs Bitmap scan
|
|
|
|
| Typ | Popis | Kdy se používá |
|
|
|-----|-------|---------------|
|
|
| **Seq Scan** | Prochází všechny řádky tabulky | Velká část tabulky (>10 %), malá tabulka, žádný vhodný index |
|
|
| **Index Scan** | Hledá v indexu, pak náhodný přístup k heap | Malá podmnožina dat (<5 %), selektivní dotazy |
|
|
| **Index Only Scan** | Načítá data pouze z indexu (ne z heap) | Všechny potřebné sloupce jsou v indexu (covering index) |
|
|
| **Bitmap Scan** | Kombinace více indexů → bitmapa → heap access | AND/OR podmínky na více indexovaných sloupcích |
|
|
| **Bitmap Heap Scan** | Načítá řádky z bitmapy (srovnané) | AND/OR kombinace, ~5-20 % tabulky |
|
|
|
|
### EXPLAIN ANALYZE
|
|
|
|
```sql
|
|
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
|
|
SELECT * FROM orders WHERE user_id = 456 AND created_at > '2026-01-01';
|
|
|
|
-- Výstup:
|
|
-- Index Scan using idx_orders_user_created on orders
|
|
-- Index Cond: ((user_id = 456) AND (created_at > '2026-01-01'::date))
|
|
-- Buffers: shared hit=3
|
|
-- Planning Time: 0.12 ms
|
|
-- Execution Time: 0.34 ms
|
|
```
|
|
|
|
Klíčové metriky: `Execution Time`, `Planning Time`, `Buffers` (hit/read/dirtied), `Rows Removed by Filter`, `Actual Time` (first...last)
|
|
|
|
## Sharding
|
|
|
|
Distribuce dat napříč uzly podle shard klíče.
|
|
|
|
```
|
|
┌─────────┐
|
|
│ Proxy │
|
|
│ Router │
|
|
└────┬────┘
|
|
┌──────────┼──────────┐
|
|
┌────▼───┐ ┌───▼────┐ ┌───▼────┐
|
|
│Shard A │ │Shard B │ │Shard C │
|
|
│ 0-100 │ │101-200 │ │201-300 │
|
|
└────────┘ └────────┘ └────────┘
|
|
```
|
|
|
|
### Hash-based sharding
|
|
|
|
```
|
|
shard_id = hash(shard_key) % number_of_shards
|
|
```
|
|
|
|
### Range-based sharding
|
|
|
|
- Data rozdělena podle rozsahu hodnot (např. uživatelé A-M, N-Z)
|
|
- Může vést k nerovnoměrnému rozdělení (hot spots)
|
|
|
|
### Consistent hashing
|
|
|
|
```
|
|
Hash ring:
|
|
0 ─── shard A ─── hash(key1)
|
|
│
|
|
90 ─── shard B ─── hash(key2)
|
|
│
|
|
180 ─── shard C ─── hash(key3)
|
|
│
|
|
270 ─── shard D ─── hash(key4)
|
|
```
|
|
|
|
- Minimalizuje přeuspořádání přidáním/odebráním nodu (pouze sousední shard)
|
|
- **Virtual nodes** (vnodes) — každý fyzický nod má více virtuálních bodů na ring (lepší distribuce)
|
|
- **Koordinační služba**: Cassandra (vnodes), Riak (vnodes), DynamoDB (Consistent Hashing)
|
|
|
|
### Rebalancing
|
|
|
|
- **Ruční** — zastavit zápisy, přerozdělit data, restartovat
|
|
- **Automatické** — incremental migration (Cassandra vnodes)
|
|
- **Proxy-based** — Vitess (shard splitting), Citus (shard rebalancing)
|
|
|
|
### Routing approaches
|
|
|
|
- **Proxy-based** — aplikace jde na proxy, ta routuje (Vitess, ProxySQL)
|
|
- **Client-side** — aplikace ví, na který shard jít
|
|
- **DNS-based** — každý shard má vlastní endpoint
|
|
|
|
## CAP teorém
|
|
|
|
V distribuovaném systému lze mít pouze 2 ze 3:
|
|
|
|
- **C**onsistency — všichni vidí stejná data
|
|
- **A**vailability — každý request dostane odpověď
|
|
- **P**artition tolerance — systém funguje i přes výpadek komunikace
|
|
|
|
V praxi: P je vždy vyžadováno, volíme mezi CP (konzistence) a AP (dostupnost).
|
|
|
|
### PACELC rozšíření
|
|
|
|
PACELC rozšiřuje CAP o chování za normálních podmínek (bez partition):
|
|
|
|
- **P**artition → **A**vailability vs **C**onsistency
|
|
- **E**lse (bez partition) → **L**atency vs **C**onsistency
|
|
|
|
| DB | Partition volba | Else volba |
|
|
|----|----------------|------------|
|
|
| Cassandra | AP (dostupnost) | LC (nízká latence, eventual consistency) |
|
|
| DynamoDB (default) | AP | LC |
|
|
| MongoDB | CP (primární) | LC |
|
|
| PostgreSQL (single) | CP | CC |
|
|
| CockroachDB | CP | CC |
|
|
|
|
### Quorum detail
|
|
|
|
- **R** (read quorum) + **W** (write quorum) > **N** (replication factor)
|
|
- Typické: N=3, R=2, W=2 (toleruje 1 node down)
|
|
- **Sloppy quorum** — při nedostupnosti nodu, data dočasně uložena na jiném nodu (nastolit konzistenci po obnově)
|
|
- **Hinted handoff** — dočasný zápis na jiný node s hintem, při obnově se data přenesou
|
|
|
|
## Caching
|
|
|
|
| Vrstva | Nástroj | Use case |
|
|
|--------|---------|----------|
|
|
| Application cache | Redis, Memcached | Session, API response cache |
|
|
| Database cache | Built-in | Query cache, buffer pool |
|
|
| CDN cache | CloudFront, Fastly | Static assets, API responses |
|
|
| HTTP cache | Varnish, nginx | Reverse proxy cache, ESI |
|
|
|
|
### Cache strategie
|
|
|
|
| Strategie | Popis | Use case |
|
|
|-----------|-------|----------|
|
|
| **Cache-aside** | Aplikace načte z cache, při miss jde do DB a naplní cache | Obecná |
|
|
| **Read-through** | Cache sama načte z DB při miss | Jednoduché lookupy |
|
|
| **Write-through** | Zápis jde do cache i DB zároveň | Konzistence |
|
|
| **Write-behind** | Zápis do cache okamžitě, do DB asynchronně | Propustnost |
|
|
| **Cache-aside (lazy loading)** | TTL + invalidace | Nejčastější |
|
|
|
|
### Redis detail
|
|
|
|
**Data structures**:
|
|
|
|
| Struktura | Popis | Use case |
|
|
|-----------|-------|----------|
|
|
| **String** | Binární string (max 512 MB) | Cache hodnoty, session tokeny, counters |
|
|
| **Hash** | Map field-value | Uživatelský profil, objekt v cache |
|
|
| **List** | Linked list (push/pop na oba konce) | Queue (RPUSH/LPOP), log stream |
|
|
| **Set** | Unikátní hodnoty (unordered) | Tags, deduplikace, memberships |
|
|
| **Sorted Set** | Unikátní + score (řazení) | Leaderboardy, rate limiting, timeouts |
|
|
| **Bitmap** | Bitové pole | Feature flagy, daily active users |
|
|
| **HyperLogLog** | Approximate cardinality (12 KB = 2^64) | Unikátní návštěvníci (error < 1%) |
|
|
| **Stream** | Append-only log (Kafka-like) | Event store, messaging |
|
|
|
|
**Eviction policies**:
|
|
|
|
| Policy | Popis | Use case |
|
|
|--------|-------|----------|
|
|
| **noeviction** | Chyba při zápisu když je plno | Transakční data, neztrácet |
|
|
| **allkeys-lru** | LRU na všechny klíče | Obecná cache, standard |
|
|
| **allkeys-lfu** | LFU na všechny klíče | Často přistupovaná data |
|
|
| **volatile-lru** | LRU na klíče s TTL | Cache s expirací |
|
|
| **volatile-ttl** | Nejblíž k expiraci | Krátkodobá data |
|
|
| **allkeys-random** | Náhodný | Testování |
|
|
|
|
**Redis Cluster vs Sentinel**:
|
|
|
|
| Vlastnost | Redis Sentinel | Redis Cluster |
|
|
|-----------|---------------|---------------|
|
|
| **Škálování** | Read replicas (master + replica) | Data sharding (16384 hash slotů) |
|
|
| **Auto-failover** | Ano (Sentinel) | Ano (gossip-based) |
|
|
| **Multi-key ops** | Ano (transactiony na masteru) | Omezené (stejný hash slot) |
|
|
| **Client komunikace** | Přes Sentinel (deprecated) | Cluster nodes redirect (MOVED/ASK) |
|
|
| **Minimální uzly** | Master + Replica + 3 Sentinel | 3 masters (každý s replikou) |
|
|
| **Use case** | Vysoká dostupnost, single shard | Multi-shard, horizontální škálování |
|
|
|
|
### Connection pooling
|
|
|
|
| Pooler | DB | Typ | Protokol |
|
|
|--------|-----|-----|----------|
|
|
| **PgBouncer** | PostgreSQL | Proxy (transaction/session) | PostgreSQL wire |
|
|
| **RDS Proxy** | PostgreSQL, MySQL | Managed proxy | AWS |
|
|
| **ProxySQL** | MySQL | Proxy (advanced routing) | MySQL wire |
|
|
| **Odyssey** | PostgreSQL | Proxy (multithreaded) | PostgreSQL wire |
|
|
| **pgpool-II** | PostgreSQL | Proxy (replication, load balancing) | PostgreSQL wire |
|
|
|
|
**PgBouncer režimy**:
|
|
- **Session pooling** — spojení drženo po celou dobu session (aplikace) → overhead
|
|
- **Transaction pooling** — spojení vráceno po dokončení transakce → efektivnější (vyžaduje bezstavovost)
|
|
|
|
## Migrace dat
|
|
|
|
### Schéma migrace (PostgreSQL / MySQL)
|
|
|
|
```
|
|
V1__initial_schema.sql
|
|
V2__add_users_table.sql
|
|
V3__add_email_index.sql
|
|
V4__add_orders_table.sql
|
|
```
|
|
|
|
### Zero-downtime migrace
|
|
|
|
1. **Expand** — přidání nového sloupce/tabulky (aplikace toleruje oba stavy)
|
|
2. **Migrate** — backfill dat, update aplikace na nové schema
|
|
3. **Contract** — odstranění starého sloupce/tabulky
|
|
|
|
### Nástroje detail
|
|
|
|
| Nástroj | Jazyk | Strategie | Zero-downtime | Rollback |
|
|
|---------|-------|-----------|--------------|----------|
|
|
| **Flyway** | Java (multi-lang CLI) | Versioned SQL | Omezeně (jen additive) | `undo` (limited, enterprise) |
|
|
| **Liquibase** | Java (multi-lang CLI) | Changesets (XML/YAML/JSON/SQL) | Ano (changeset design) | `rollback <count>` |
|
|
| **Alembic** | Python | Auto-generation, versioned | Ano (branching) | `downgrade` |
|
|
| **Prisma Migrate** | TypeScript | Declarative schema → diff | Ano (shadow DB) | `migrate diff` |
|
|
| **gh-ost** | Go | Triggerless online DDL (MySQL) | Ano (binlog stream) | Ne (progresivní) |
|
|
| **pgroll** | Go | Online schema migrace (PG) | Ano (views, multiple versions) | Ano (okamžitý) |
|
|
|
|
## Data consistency patterns
|
|
|
|
| Pattern | Popis | Příklad |
|
|
|---------|-------|---------|
|
|
| **Strong consistency** | Po zápisu každý read vidí nejnovější data | Single DB, Raft, Spanner |
|
|
| **Eventual consistency** | Po zápisu se data časem propagují | DNS, DynamoDB (default), Cassandra |
|
|
| **Read-after-write** | Autor svůj zápis vždy vidí (ostatní eventual) | Sociální sítě, komentáře |
|
|
| **Causal consistency** | Kauzálně závislé operace viděny ve správném pořadí | COPS, Orbe, MongoDB (causal clusters) |
|
|
| **Monotonic reads** | Nevidíte starší data po tom, co jste viděli novější | Cassandra (MONOTONIC_READ consistency) |
|
|
| **Monotonic writes** | Zápisy od jednoho clienta v pořadí | Queue-based, single leader |
|
|
|
|
## Storage engines — přehled
|
|
|
|
### B-Tree vs LSM-Tree
|
|
|
|
| Vlastnost | B-Tree | LSM-Tree |
|
|
|-----------|--------|----------|
|
|
| Zápis | In-place update (náhodný I/O) | Append-only (sekvenční I/O) |
|
|
| Čtení | Rychlé (přímo v page) | Pomalejší (merge z více SSTable) |
|
|
| Kompaktnost | Horší (page fragmentation) | Lepší (kompaktní SSTable) |
|
|
| Write amplification | Nižší | Vyšší (kompakce) |
|
|
| Read amplification | Nižší | Vyšší (bloom filtry pomáhají) |
|
|
| Typické DB | PostgreSQL, MySQL (InnoDB) | Cassandra, RocksDB, LevelDB |
|
|
|
|
### Write-Ahead Log (WAL)
|
|
|
|
- Append-only log pro crash recovery
|
|
- Každá změna se zapíše do WAL před aplikací na data page
|
|
- Checkpoint = bod, od kterého je WAL při recovery potřeba
|
|
|
|
### MVCC (Multi-Version Concurrency Control)
|
|
|
|
- Každá transakce vidí snapshot dat v okamžiku startu
|
|
- Staré verze řádků zůstávají v tabulce (vacuum/GC)
|
|
- Izolační úrovně: Read Committed, Repeatable Read, Serializable
|
|
|
|
## Best practices
|
|
|
|
- **Connection pooling** — PgBouncer, RDS Proxy, ProxySQL
|
|
- **Indexování podle query patternů** — nemít zbytečné indexy
|
|
- **Read replicas** pro reporting a analytiku
|
|
- **Backup & recovery** — point-in-time recovery (PITR), pravidelné testy
|
|
- **Query monitoring** — slow query log, pg_stat_statements, performance_schema
|
|
- **Encryption at rest & in transit**
|
|
- **Migrace v CI/CD** — součást pipeline, ne manuálně
|
|
|
|
## Zdroje
|
|
|
|
Odkazy, knihy a standardy: [sources/databases/sources.md](sources/databases/sources.md)
|