数据库共享和复制
数据库共享和复制
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模式-因此,基地将不再是瓶颈,并成为可预测的弹性平台基础。