本书分为三个部分
第一部分是数据系统的基础,介绍了一些基本思想,稍微提了一些 building blocks
第二部分是分布式数据系统,讨论了单机扩展到多台机器时的典型问题和解决方案
第三部分是派生数据,讨论了多数据整合,包括批处理和流处理。
•大多数应用 (application) 是 data-intensive 数据密集型的,而不是 compute-intensive 计算密集型的。真正的问题通常来自于数据的数量、数据的复杂性以及数据的快速多变。
•DDIA 介绍了数据系统的原理和实用性,以及如何使用它们来构建数据密集型的应用程序。探索现有数据系统的共同点 & 差异,以及它们如何实现预设目标
•第 1 章是关于数据系统的三个主要点:可靠性、可扩展性和可维护性
•越来越多的应用系统 (application) 需求广泛,以至于单个组件无法满足所有的数据处理和存储需求。
•应用系统代码可以衔接多个组件,将它们拼接在一起,并提供某些保证。
•例如下图:一个新的复合系统可以保证缓存在写入时正确更新或者作废,从而向外部客户提供一致的结果。
对外隐藏了细节,但是内部引入了问题:当系统出问题时,如何确保数据的正确性和完整性?当部分系统降级(degrade)时,如何为客户提供始终如一的良好性能?当负载增加时,如何扩容应对?什么样的 API 才是友好的 API?
•database 存储数据,以便自己或其他应用程序之后能再次找到
•caches 记住开销昂贵操作的结果,加快读取速度
•indexes 允许用户按关键字搜索数据,或以各种方式对数据进行过滤
•stream processing 向其他进程发送消息,进行异步处理
•batch processing 定期处理累积的大批量数据
•RMDB / NoSQL / NewSQL
•replication
•Vertical scaling (scaling up) vs horizontal scaling (sharding)
•load balancer / proxy / API Gateway
•Message queue
•Consistent hashing
•Rate limiter
•CDN
可靠性简单理解为 “即使发生某些错误,系统也能继续正常工作”
•单个硬件迟早会有故障,需要增加冗余度
•随着数据量和计算需求的增加,越来越多的应用系统需要使用大量机器,需要进一步引入软件容错机制
•云平台优先考虑灵活性(flexibility)和弹性(elasticity),而不是单机可靠性。
•难以察觉,往往导致多个层级系统故障
•可能平常处于休眠状态,直到偶然触发
•没有快速的解决方案 -- 只能仔细考虑细节:规划、测试、进程隔离、允许崩溃和自动重启、监控并分析系统行为
人是不可靠的,需要结合几种策略:
•最小出错设计:尽量减少人为错误的机会
•分离最容易出错的地方 vs 容易故障的环境:提供沙盒进行测试,不要在生产环境直接修改
•提供快速恢复的机制:回滚 / 切换 master 节点
•提供监测系统
•对人员需要管理 + 培训
•系统今天能可靠运行,并不意味用户 x10 之后也能可靠运行
•可扩展性(Scalability) 是用来描述系统应对负载增长能力的术语
•load parameters 负载参数,e.g. QPS, Read/ Write Ratio, simultaneous users, cache hit rate…
•2012/11,twitter post tweet averages 4.6k requests/sec, peak of 12k requests/sec
•实际上,到 2020 年这个数字也没怎么增长, ~ 6k requests/sec
•批处理系统关注吞吐量 throughput
•在线系统关注响应时间 response time
•响应时间不是一个固定数字,而是一种数值分布
•最好使用百分位数 (percentiles), e.g. median (p50), 95th, 99th•百分位数用于描述和定义 service level objectives (SLOs) & service level agreements (SLAs)
•scaling up 垂直扩展 (vertical scaling),升级到更强大的机器 -- 简单,但昂贵
•scaling out 水平扩展 (horizontal scaling),将负载分布到多台更小的机器上
•无状态服务分布到多台机器比较简单;有状态服务分布到多机会增加复杂性
良好的可操作性包括:
•通过监控,提供对系统内部状态和运行时行为的 可见性(visibility)-- Grafana & Prometheus
•支持自动化,将系统与标准化工具相集成 -- Jenkins integration with Git / AWS / Maven / Ansible
•避免依赖/绑定单台机器 -- 允许系统停机维护
•提供良好的文档和易于理解的操作模型(“如果执行 X,会导致 Y”)-- SRE playbook
•提供良好的默认行为,且允许管理员覆盖默认值 -- borgspec / ConfigMap
•尝试自我修复,需要时允许管理员手动控制系统状态 -- restart / rollback
•行为可预测,减少意外
简化系统并不意味着减少功能;主要意味着消除意外方面(accidental) 的复杂性
•意外复杂性:由实现本身衍生出来的,而非系统本身固有的复杂度
•消除意外复杂性最好的方法是抽象:好的抽象可以隐藏大量实现细节,对外提供干净、易懂的接口
•敏捷开发模式提供了一个适应变化的框架
•在更大的数据系统层面提高敏捷就需要实现可演化性
•简单性和良好的抽象可以在很大程度上实现可进化性