其他
选择数据库或设计分布式数据系统时,用 DDIA…
在选型、分片复制、设计事务/一致性、构建数据管道或排查复制滞后、写偏斜、热分区等分布式数据问题时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 48/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 56/100 ×0.15
适用场景
选择数据库或设计分布式数据系统时,用 D通用
解决思路
- 坚持核心原则:优先保证数据层的长期正确性、持久性和可演化性,因为数据比代码活得久;把应用当作数据密集型而非计算密集型,显式记录一致性、可用性、延迟的取舍。
- 按评分目标 10/10 操作:对 Quick Diagnostic 的七行逐项回答 yes/no;每行 yes 且有证据(经过刻意设计、有文档的取舍)约得 1.4 分,no 或未知得 0 分。
- 评分后报告当前分数、哪些诊断行失败、以及达到 10/10 所需改进。
- 数据模型:按实际访问模式选择关系、文档或图模型;关系模型用于多对多关系和即席查询,文档模型用于一对多关系和聚合局部性,图模型用于互连数据的递归遍历。
- 数据模型:决定 schema-on-write(关系,早发现错误)还是 schema-on-read(文档,灵活);必要时采用 polyglot persistence,为不同访问模式使用不同存储。
- 数据模型:评估对象-关系阻抗失配成本;对自包含聚合使用文档模型来降低该成本。
- 数据模型代码应用:用户资料含嵌套数据时,用文档模型把 profile、addresses、preferences 放在一个 MongoDB document 中。
- 数据模型代码应用:社交网络连接时,用图模型做关系遍历,例如 Neo4j Cypher:`MATCH (a)-[:FOLLOWS*2]->(b)` 查询朋友的朋友。
- 数据模型代码应用:财务账本需要 join 时,用关系模型保证引用完整性,例如 PostgreSQL 在 accounts、transactions、entries 之间使用 foreign keys。
- 存储引擎:按读写权衡选择引擎;日志结构 LSM tree 优化写入,页导向 B-tree 平衡读写。
- 存储引擎:写密集用 LSM tree:append-only 写、周期 compaction、优秀写吞吐,但读放大更高。
- 存储引擎:混合读写用 B-tree:原地更新、读延迟可预测,但页分裂带来写放大。
- 存储引擎:关注写放大,因为一次逻辑写可能造成多次物理写,影响有限写周期的 SSD。
- 存储引擎:分析查询用列存,通过压缩和向量化处理大幅提升扫描性能。
- 存储引擎:理解内存数据库快是因为避免编码开销,不是因为避免磁盘。
- 存储引擎代码应用:高写入吞吐用时序场景选 LSM-tree 引擎,例如 Cassandra 或 RocksDB 处理 100K+ writes/sec 的时序摄取。
- 存储引擎代码应用:混合读写 OLTP 用 B-tree 引擎,例如 PostgreSQL B-tree indexes 做事务性点查。
- 存储引擎代码应用:分析查询用列存,例如 ClickHouse 或 Parquet 扫描 billions of rows、few columns。
- 复制:为容错、扩展和降低延迟在多个机器保存副本;核心是一致地处理变更。
- 复制:单 leader 简单且可能强一致,但 leader 是瓶颈和单点故障。
- 复制:多 leader 改善跨数据中心写可用性,但冲突解决复杂。
- 复制:leaderless 通过 quorum 读写获得最高可用性,但需小心冲突处理。
- 复制:处理复制滞后导致的 read-your-writes、monotonic-read、causality 违反。
- 复制:同步复制保证持久性但增加延迟;异步复制在 failover 时可能丢数据。
- 复制:用 CRDT 或 last-writer-wins 解决冲突,并明确两者正确性保证不同。
- 复制代码应用:读多 web app 用单 leader + read replicas,例如 PostgreSQL primary + read replicas behind pgBouncer。
- 复制代码应用:多区域写用多 leader,例如 CockroachDB 或 Spanner with bounded staleness。
- 复制代码应用:购物车可用性用 leaderless with merge,例如 DynamoDB with last-writer-wins 或应用层 cart merge。
- 分区:通过分片把数据分布到节点,让每个节点处理子集,实现单机之外的横向扩展。
- 分区:key-range 分区支持高效范围扫描,但顺序键有热点风险。
- 分区:hash 分区均匀分布负载,但破坏排序顺序,使范围查询昂贵。
- 分区:local secondary indexes 需要 scatter-gather 查询;global secondary indexes 需要跨分区更新。
- 分区:即使使用 hash,单个键极热时仍会出现热点(celebrity problem)。
- 分区:rebalancing 策略可选固定分区数、动态拆分或按节点比例。
- 分区代码应用:时序数据按时间 + 来源做 key-range 分区,例如 partition by `(sensor_id, date)` 避免当天写热点。
- 分区代码应用:规模化用户数据按 user ID 做 hash 分区,例如 Cassandra consistent hashing on `user_id` 实现均匀分布。
- 分区代码应用:celebrity/hot-key 问题用随机后缀做 key splitting,在热键后加随机数字,把读分散到 10 个子分区。
- 事务与一致性:用事务提供 ACID 安全保证,简化应用代码,让你在事务范围内假装失败和并发不存在。
- 事务与一致性:理解隔离级别谱:read uncommitted、read committed、snapshot isolation、serializable。
- 事务与一致性:多数数据库默认 read committed 或 snapshot isolation,而不是 serializable;必须理解这允许哪些异常。
- 事务与一致性:防范 write skew:两个事务读同一数据、各自决策、写不同记录,没有行锁能阻止。
- 事务与一致性:serializable snapshot isolation(SSI)用乐观方式提供完整可串行化:不阻塞,但冲突时中止;two-phase locking 会阻塞并在争用下死锁。
- 事务与一致性:避免到处使用分布式事务;two-phase commit 昂贵脆弱;设计单分区操作替代。
- 事务与一致性代码应用:账户余额转账用 serializable transaction,例如 `BEGIN; UPDATE accounts ... -100 WHERE id=1; UPDATE accounts ... +100 WHERE id=2; COMMIT;`。
- 事务与一致性代码应用:库存预留用 SELECT FOR UPDATE 防 write skew,例如在 decrementing 前执行 `SELECT stock FROM items WHERE id = X FOR UPDATE`。
- 事务与一致性代码应用:跨服务操作用 Saga 代替分布式事务,例如 charge card、reserve inventory;失败时运行 compensating refund。
- 批处理和流处理:批处理转换有界数据集,流处理转换无界事件流;两者都计算派生数据。
- 批处理和流处理:分离 system of record 与派生数据(缓存、索引、物化视图),让各自可独立优化,并可在需求变化时从源重建。
- 批处理和流处理:MapReduce 概念简单但运维尴尬;用 dataflow engines(Spark、Flink)以任意 DAG 泛化。
- 批处理和流处理:用 change data capture(CDC)把数据库写入变成下游系统可消费的流。
- 批处理和流处理:利用 stream-table duality:流是表的 changelog;表是流的 materialized state。
- 批处理和流处理:exactly-once 语义需要幂等操作或事务性输出。
- 批处理和流处理:对无界流聚合使用时间窗口 tumbling、hopping、session。
- 批处理和流处理代码应用:每日分析管道用 Spark 批处理,从 S3 读当天 events,聚合,写入 warehouse。
- 批处理和流处理代码应用:实时欺诈检测用 Flink 流处理,消费 Kafka payment events,在 5-second tumbling windows 上跑规则。
- 批处理和流处理代码应用:同步搜索索引用 CDC,Debezium 捕获 PostgreSQL WAL,Kafka 喂 Elasticsearch。
- 批处理和流处理代码应用:审计轨迹/事件重放用 event sourcing,存 `OrderPlaced`、`OrderShipped` events,通过重放重建状态。
- 可靠性和容错:设计系统在组件故障时继续正确运行;应对故障而非对抗故障。
- 可靠性和容错:区分 fault 与 failure:fault 是一个组件偏离 spec,failure 是整个系统停止;容错防止前者变成后者。
- 可靠性和容错:硬件故障随机且独立;软件故障相关且系统化,更危险。
- 可靠性和容错:人为错误是停机主因;减少犯错机会,提高恢复能力。
- 可靠性和容错:把 timeouts 作为基本故障检测器,但调优困难:太短误报,太长延迟恢复。
- 可靠性和容错:safety 属性(不发生坏事)必须始终成立;liveness(好事最终发生)可暂时违反。
- 可靠性和容错:Byzantine fault tolerance 在区块链之外很少需要;假设 crash-stop 或 crash-recovery。
- 可靠性和容错代码应用:服务通信用 timeouts + retries with backoff,例如 `retry(max=3, backoff=exponential(base=1s, max=30s))` with jitter。
- 可靠性和容错代码应用:leader election 用 consensus algorithm(Raft/Paxos),例如 etcd 或 ZooKeeper 做 distributed locks 和 leader election。
- 可靠性和容错代码应用:优雅降级用 circuit breaker,例如 Resilience4j:open circuit after 50% failures in 10-second window。
- 避免按流行度选数据库;把 storage engine 匹配到实际读写模式。
- 避免忽略复制滞后;实现 read-your-writes 和 monotonic-read 保证。
- 避免到处使用分布式事务;设计单分区操作,跨服务用 sagas。
- 避免全部 hash 分区;时序用 key-range,复合键提升局部性。
- 避免假设 serializable 隔离;检查实际默认值,需要时显式加锁。
- 避免混淆批处理和流处理;按数据有界性和延迟需求匹配处理模型。
- 避免把所有故障当可恢复;分类故障,为每类设计恢复策略。
- 诊断:能解释为什么选这个数据库而不是替代品;否则按数据模型匹配、读写比、一致性需求、扩展路径评估。
- 诊断:知道数据库默认隔离级别;否则查文档,测试 write skew 和 phantom reads。
- 诊断:显式选择复制策略;否则记录 sync vs async、failover 行为、lag 容忍。
- 诊断:系统能处理热分区键;否则加 key-splitting 或 load shedding。
- 诊断:分离 system of record 与 derived data;否则引入 CDC 或 event sourcing 解耦。
- 诊断:超时和重试已调优而非默认;否则测量 p99;设置超时高于 p99、低于级联阈值。
- 诊断:已在生产条件测试 failover;否则跑 chaos experiments:kill leaders、partition networks、fill disks。
适用边界 · 注意事项
- 不适用于需要完整系统架构设计(服务边界、API、可扩展性等)时,应参见 system-design。
- 不适用于发布工程与弹性专项(发布流程、SLO、事故响应等)时,应参见 release-it。
- 不适用于需要 Byzantine 容错或区块链共识、而非崩溃-停止/崩溃-恢复假设的场景。