數據庫共享和復制
數據庫共享和復制
1)為什麼需要它
當垂直的DB升級靠近CPU/IO/RAM極限或單個群集變成SPOF時,將進行復制(用於閱讀/NA)和緩存(用於記錄/數據分配)。目標是:- 吞吐量(水平寫入QPS增長)。
- 可用性(快速失敗,沒有單一故障點)。
- 數據本地化(多區域,低潛伏期)。
- 隔絕嘈雜的鄰居(熱門/熱鍵)。
2)基本術語和一致性模型
Primary/Leader ↔ Replica/Follower:在領導者上寫入,在副本上讀取。
同步復制:在N節點上寫入後確認交易(低RPO,高於潛伏期)。
異步:領導者捕獲commit並稍後發送日誌(RPO> 0,低潛伏期)。
法定人數(Raft/Paxos):記錄大多數節點;一個日誌,自動領導者。
讀後寫:保證讀取他們的記錄(參見第5節)。
銷售中的CAP是這樣的:對於網絡問題,您為關鍵操作選擇一致性(CP)或可用性(AP),通常在不同路徑上組合層。
3)復制: 選擇和做法
3.1物理和邏輯
物理(WAL/redo/binlog):更接近塊日誌,簡單而快速;僅限於同源拓撲/版本。
邏輯:行/表級別的DML/DDL流;允許部分復制副本、版本間遷移、用於DWH/流媒體的 CDC。
3.2設置和管理
控制lag (時間/字節/LSN)。
限制熱備用反饋和冗長的副本查詢(以免停止VACUUM/點擊)。
對於MySQL-GTID和Orchestrator;для PostgreSQL — Patroni/replication slots, synchronous_standby_names.
PostgreSQL(同步副本,片段):sql
-- на лидере
ALTER SYSTEM SET synchronous_commit = 'on';
ALTER SYSTEM SET synchronous_standby_names = 'FIRST 1 (standby_a, standby_b)';
SELECT pg_reload_conf();
MySQL GTID(事務標識符):
sql
SET GLOBAL enforce_gtid_consistency = ON;
SET GLOBAL gtid_mode = ON; -- перезапуск
CHANGE MASTER TO MASTER_AUTO_POSITION=1;
3.3個拓撲
1→N(→副本的領導者)+級聯(副本進一步泄漏)。
Multi-primary (active-active)-在OLTP中避免無嚴格沖突管理。
Quorum集群(Raft)-CockroachDB/Yugabyte/PG-Raft上層建築。
4)閱讀/寫入分頁和路由
始終寫入領導者;閱讀副本,但要考慮錯誤。
閱讀後寫作策略:1.Session stickiness:成功錄制後,客戶從領導者那裏讀取'Δ T'。
2.LSN/GTID門:客戶端報告「不想老化LSN=X」,路由器發送到LSN ≥ X的副本。
3.Stale-ok:部分查詢允許舊數據(目錄/磁帶)。
工具:PgBouncer/Pgpool-II(Postgres),ProxySQL/MaxScale(MySQL),Vitess(shard路由)。
LSN門示例(想法):將'pg_current_wal_lsn()'保存在HTTP-header/Cookie中,並要求路由器使用'pg_last_wal_replay_lsn()≥ LSN'提供復制副本。
5)Sharding策略
5.1鍵選擇
密鑰必須確保查詢的均勻性和局部性:- 「tenant_id」/「user_id」上的哈希-均勻但取消了範圍掃描。
- 時間範圍/ID-非常適合時間系列/存檔,但風險很高。
- 共謀搶購-簡化了加入/刪除縫線。
- Directory/lookup表是靈活的(任何算法),但另一表/緩存。
5.2種模式
共享無:每個共享都是單獨的DB/群集,應用程序知道路由。
Middleware sharding: Vitess (MySQL)、Citus (Postgres)、Proxy層隱藏拓撲。
聯合:按服務劃分數據域(目錄,payments, auth)。
5.3復合鑰匙
使用密鑰空間: {tenant} {entity} {id}並存儲在應用程序和緩存中。Для Postgres — hash partitioning + LIST/RANGE subpartition.
PostgreSQL partitioning(片段):sql
CREATE TABLE orders (
tenant_id int,
id bigint,
created_at timestamptz,
...,
PRIMARY KEY (tenant_id, id)
) PARTITION BY HASH (tenant_id);
CREATE TABLE orders_t0 PARTITION OF orders FOR VALUES WITH (MODULUS 16, REMAINDER 0);
--... t1..t15
6)ID生成
避免在sharding上「熱」單調汽車註入。
使用類似Snowflake的64位ID (time+region+shard+seq)或ULID/KSUID(單調性和分布性)。
Для Postgres — sequence per shard;對於MySQL-auto_increment_increment/offset(不同的offset on shards leaders)。
7)在線轉換和遷移
關鍵原理是:雙重寫入(雙寫入),相等性,時間雙重路由。
步驟(廣義上):1.添加新的shard/cluster。
2.啟用dual-read(一致性檢查)。
3.啟用dual-write(兩碼),捕捉差異。
4.執行背景歷史數據(batchi, 復制邏輯/CDC)。
5.將「真相之源」切換到新的陰影;離開「尾部」同步。
6.關閉舊的。
工具:Vitess Resharding、Citus move shards、pg_logical/pgoutput、Debezium (CDC)、gh-ost/pt-online-schema-change (DDL無鎖)。
8)多區域與地理分布
Leader-follower per region:本地閱讀,寫入-通過全局領導者(簡單模型,但跨區域RTT)。
Multi-Leader:記錄在兩個區域-需要沖突merging (時間表/版本/CRDT)。
True distributed SQL (Raft): CockroachDB/Yugabyte-數據「粘貼」到區域,查詢達到本地法定人數。
- 金錢/訂單為CP(法定人數/領導者),目錄/磁帶為AP(緩存,事件)。
- 在可能發生裂紋的情況下,始終計劃寫入(唯一鍵/轉換)。
9)在實踐中保持一致
閱讀您的寫作:「趕上」LSN/GTID的領導者或副本。
Monotonic reads:「不超過」最後閱讀的LSN。
Write-conflict control: `SELECT...FOR UPDATE',版本(「xmin」/「rowversion」),具有版本驗證的UPSERT。
等效性:支付/事件中的等效性鍵。
10)可觀察性,SLO和Alerta
Lag復制副本:時間(秒),LSN距離(字節),seconds_behind_master (MySQL)。
強制回滾/沖突、復制錯誤。
p95/p99 latency по route (read leader vs replica, write).
Throughput: TPS/locks/row-contended tables.
Bloat/VACUUM (PG), InnoDB buffer pool hit ratio (MySQL).
Dashbords:每包負載,「熱」shards,密鑰分配。
11) Bacaps、PITR和DR
PITR的完整備份+WAL/binlog(點對點恢復)。
存儲在不同的區域/雲中,定期進行恢復測試。
對於shards-一致的「切片」(時間協調/LSN)或恢復時的貼花冪等。
RPO/RTO在遊戲日進行拼寫和測試。
bash pg_basebackup -D /backups/base -X stream -C -S slot_replica_1 архивация WAL через archive_command или pgBackRest/Barman
12)安全和訪問
分割為VPC/ACL,mTLS為代理。
根據最低權利原則發揮作用/提供贈款;每個角色的單個用戶。
DDL/DCL審計,對復制副本上「重」請求的限制。
重新加密(KMS)和過境加密(TLS)。
「恐慌按鈕」:事件/調查期間的全球「只讀」。
13)工具和磚塊
PostgreSQL: Patroni (HA), PgBouncer (pooling/RO-routing), repmgr, pgBackRest/Barman (бэкап), Citus (шардинг), pglogical/Logical Replication, pgbadger/pg_stat_statements.
MySQL:Orchestrator(拓撲/自動失敗者),ProxySQL/MaxScale(路由),Percona XtraBackup(備份),Group Replication/InnoDB集群,Vitess(緩解/重整)。
分布式SQL:CockroachDB,YugabyteDB(法定人數,內置緩存/地理定位)。
CDC:用於事件/ETL的Debezium+Kafka/Pulsar。
14)反模式
單一初級,沒有自動失敗或沒有DR測試。
「神奇的」讀取分開,不包括lag →幻影錯誤/可疑錯誤。
Sharding 「sharding」:過早復雜化而不是垂直滑板/索引/緩存。
熱範圍(時間範圍)沒有時間桶/哈希鹽→一個碎片融化。
全球交易2PC在OLTP的數十個硬幣之上-p99的高尾巴和頻繁的鎖定。
遷移時缺少雙write/雙 read → 丟失/rasinchron。
DDL在銷售中沒有在線工具,也沒有兼容性快照標誌。
15)實施清單(0-60天)
0-15天
定義SLO DB, RPO/RTO。
啟用復制,lag監視,基本備份+PITR。
輸入路由器(PgBouncer/ProxySQL)和閱讀後寫入策略。
16-30天
選擇緩存策略,描述密鑰和電路。
準備轉換工具(Vitess/Citus/CDC)。
標記為「read-stale-ok」 vs 「strict」的服務/表目錄。
31-60天
運行pilot shard、dual-read和backfill。
遊戲日:領先者失敗,從PITR恢復,區域切換。
自動化熱硬鍵和不均勻報告。
16)成熟度量
Replica lag p95<目標(例如500 ms)用於批判性閱讀。
成功的DR測試≥ 1/季度(恢復≤ RTO,損失≤ RPO)。
負載分布:QPS/存儲不平衡 <20%。
具有嚴格一致性的查詢比例正確路由為100%。
在需要CP擔保(金錢/訂單)的事件中零數據丟失。
在線DDL/遷移無需停機,並帶有兼容性標誌。
17)食譜示例
用於計時範圍的Hash-salt(以免加熱):sql
-- вычисляйте bucket = hash(user_id) % 16, храните (bucket, created_at)
PARTITION BY LIST (bucket) SUBPARTITION BY RANGE (created_at)
讀取我的書寫middleware(偽代碼):
python lsn = db.leader_query("SELECT pg_current_wal_lsn()")
ctx.sticky_until = now()+5s ctx.min_lsn = lsn в роутере чтений: выбираем реплику с last_lsn >= ctx.min_lsn, иначе лидер
Vitess VSchema(片段):
json
{
"tables": {
"orders": { "column_vindexes": [{ "column": "tenant_id", "name": "hash" }] }
}
}
18)結論
Sharding和復制不僅是技術,而且是過程:一致性路由,遷移學科(雙寫入/讀入,背面),常規的DR測試和可觀察性lag/熱板。從簡單的leader→replica+讀後寫入開始,然後在負載配置文件真正需要的地方添加緩存。使用現成的平臺(Vitess/Citus/Distributed SQL),並將業務關鍵數據保持在CP模式-因此,基地將不再是瓶頸,並成為可預測的彈性平臺基礎。