《数据密集型应用系统设计》笔记一——数据系统基础
2021/8/26大约 6 分钟
《数据密集型应用系统设计》笔记一——数据系统基础
第一章:可靠、可扩展与可维护的应用系统
认识数据系统
单一工具难以满足复杂应用系统的需求,因此整体工作被拆解为一系列能被单个工具高效完成的任务,并通过应用代码将它们缝合起来。

数据密集型:数据是其主要挑战(数据量、数据复杂度、数据变化速度)。与之相对的是计算密集型(处理器速度是瓶颈)。
软件系统三大核心问题:
- 可靠性(Reliability):系统面临各种错误仍可正常工作
- 可扩展性(Scalability):有合理的办法应对系统增长
- 可维护性(Maintainability):许多人在不同生命周期都能高效工作
可靠性
- 故障(fault):可能出错的事情;容错(fault tolerant)/ 弹性(resilient):系统可应对错误
- 故障 ≠ 失效(failure):故障是组件偏离正常规格,失效是系统整体停止服务
常见故障分类:
- 硬件故障:添加冗余硬件、软件容错(如负载均衡)
- 软件故障:全面测试、监控告警、系统/数据隔离、自动化部署回滚
- 人为失误:快速恢复机制、监控告警
可扩展性
描述负载
负载用负载参数描述(QPS、写入比例、日活用户量、缓存命中率等)。
推特发送推文的设计变迁:
- 方案一:推文放在全局集合,查询时做 join

- 方案二:推文插入每个关注者的时间线(「扇出」大,大 V 压力大)

- 最终方案:两者结合
描述性能
- 批处理系统关心吞吐量(throughput)
- 在线系统关心响应时间(response time)
- 响应时间度量:使用百分位数(P50/P95/P99/P999),而非平均值

- 测量应在客户端进行(而非服务端)
- 实践中的百分位点统计:滑动时间窗口 + 正向衰减 / t-digest 等近似算法

应对负载的方法
- 垂直扩展:升级硬件
- 水平扩展:将负载分布到多台小机器
- 弹性设计:自动检测负载并自动添加计算资源
- 无状态服务容易扩展;有状态服务从单点到分布式复杂性大,应尽量放在单节点
可维护性
三个设计原则:
- 可运维性:监控、链路追踪、CI/CD、规范流程
- 简单性:良好的抽象
- 可演化性:DDD、TDD、重构、敏捷
第二章:数据模型与查询语言
关系模型与文档模型
- 关系模型:数据组织成关系(表),每个关系是元组(行)的无序集合
- NoSql(Not Only SQL):需要更好的扩展性、更灵活的数据模型
当前关系型数据库和 NoSql 的混合持久化是常态。
数据模型选择依据:
- 文档模型:适合一对多关系(树结构)或记录间无关系的数据
- 关系模型:适合简单多对多关系
- 图模型:适合高度关联的数据
对象关系不匹配
使用面向对象语言需要转换层(阻抗失谐)。ORM 框架(如 Hibernate)减少样板代码,但不能完全隐藏差异。

JSON 表示自包含文档,有更好的局部性(一次查询出所有信息)。

多对一和多对多的关系
- 使用 ID 引用的好处:ID 无直接意义,即使信息变化也可保持不变
- 文档模型不适合多对一关系,对联结支持不足
- 数据库不支持联结时需多次查询模拟

文档数据库是否在重演历史?
- 层次模型:类似 JSON 的嵌套树结构,难支持多对多关系
- 关系模型:后来演变为 SQL,被广泛接受
- 网络模型:最初受关注,最终被淡忘

关系数据库与文档数据库现状
- 文档模型优势:模式灵活性、局部性性能好;劣势:不支持嵌套引用、联结弱
- 关系模型优势:联结操作强、多对多关系表达简洁
模式灵活性
- 读时模式(schema-on-read):文档数据库,类似动态类型
- 写时模式(schema-on-write):关系数据库,类似静态类型
数据局部性
- 文档通常存储为 JSON/XML/BSON 的连续字符串
- 读:频繁访问整个文档时局部性有优势;写:通常需重写整个文档
融合趋势
MySQL 等逐步支持 JSON/XML,融合关系模型与文档模型是未来方向。
数据查询语言
- 声明式查询语言(SQL):指定所需数据模式,不需指明如何实现
- 命令式语言:告诉计算机以特定顺序执行操作
MapReduce 查询
用于在许多机器上批量处理海量数据的编程模型。
图数据模型(略)
本章小结
- 文档数据库:数据来自自包含文档,文档间关联少
- 图数据库:所有数据都可能相互关联
- 文档数据库和图数据库通常不对存储数据强加模式
第三章:存储与检索
数据库核心:存储和检索。
数据库核心:数据结构
索引:高效查找特定键的值。适当的索引加速读取,但每个索引减慢写入。
索引类型:哈希索引、B+ 树、LSM 树等。
扩展阅读:检索技术核心 20 讲
事务处理与分析处理
列式存储
适合万亿行、PB 级别数据的存储方式。
第四章:数据编码与演化
数据编码格式
数据流模式
向前和向后兼容对可演化性非常重要。
基于数据库的数据流
- 数据库通常支持在不同时间写入不同的值
- 集群部署新版本时,旧版本可能丢失新版本写入的数据

基于服务的数据流:REST 和 RPC
- REST:基于 HTTP 的设计理念,简单通用,适合公共 API
- RPC:位置透明抽象,性能好但存在网络不可预测等问题
- 网络请求可能超时、重复、乱序
- 需要处理幂等(idempotence)
- 跨语言数据类型转换复杂
基于消息传递的数据流
- 消息代理:生产者向队列/主题发消息,消费者/订阅者接收
- 分布式 Actor 框架:集成消息代理和 Actor 编程模型(Akka、Orleans、Erlang OTP)
小结
数据编码格式对比:
- 语言特定编码:仅限单一语言,兼容性差
- 文本格式(JSON/XML/CSV):通用但兼容性取决于使用方式
- 二进制格式(Thrift/Protocol Buffers/Avro):紧凑高效,前后兼容性好,但需解码后才可读
数据流模式:数据库、RPC/REST API、异步消息传递。
参考资料
- 数据密集型应用系统设计 - 这可能是目前最好的分布式存储书籍,强力推荐【进阶】