DDIA读书笔记-第一章

第一章-数据系统及可靠、可扩展、可维护

概要

数据系统

常见的数据系统

数据库:用以存储数据,这样之后应用可以再次面问。

高速缓存 缓存那些复杂或操作代价昂贵的结果,以加快下一次访问。

索引 用户可以按关键字搜索数据井支持各种过掳

流式处理:持续发送消息至另 个进程,处理采用异步方式。

批处理 定期处理大量的累积数据。

越来越多 应用系统需求广泛,单个组件往往无能满足所有数 处理与

求。因而需要将任务 解,每个组件负责高效完成其中 部分,多个组件依靠应用层

代码驱动有机衔接起来。

有必要从根本上思考下如何评价一个好数据系统,如何构建一个好的数据系统,有哪些可以遵循的设计模式?有哪些通常需要考虑的方面?

书中用了三个词来回答:可靠性(Reliability)、可扩展性(Scalability)、可维护性(Maintainability

可靠性

出现意外情况如硬件、软件故障、人为失误等,系统应可以正常运转,虽然性能可能有所降低,但确保功能正确

如何衡量可靠性?

  • 用户期望的功能
  • 容忍用户不当使用方法
  • 性能可应对典型场景,合理的负载
  • 阻止未授权,恶意破坏

两个易混淆的概念:Fault(系统出现问题)Failure(系统不能提供服务)

不能进行 Fault-tolerance 的系统,积累的 fault 多了,就很容易 failure。

硬件故障

哪些故障?

  • 硬盘崩溃
  • 内存故障
  • 机房掉电
  • 网络不通
  • 机器过热导致cpu故障

硬盘的平均无故障时间( MTTF )约为 10 50 年,如果你有 1w+ 硬盘,则均匀期望下,每天都有坏盘出现。当然事实是硬盘会一波一波坏。

应对办法:冗余。

对磁盘配置RAID ,服务器配备双电源,甚至热插拔 CPU ,数据中心添加备用电源、发电机等

单机:RAID冗余

多机:多副本

软件错误

硬件故障属于随机性,而软件错误相关性高

  • 无法处理特定输入,导致崩溃
  • 错误进程耗尽共享资源,如cpu、内存、网络资源
  • 系统依赖的组件服务变慢甚至无响应
  • 级联故障

在设计软件时,我们通常有一些环境假设,和一些隐性约束。随着时间的推移、系统的持续运行,如果这些假设不能够继续被满足;如果这些约束被后面维护者增加功能时所破坏;都有可能让一开始正常运行的系统,突然崩溃。

应对

  • 检查依赖的假设条件与系统之间的交互
  • 全面测试
  • 进程隔离
  • 自动重启
  • 反复评估
  • 监控并分析
  • 异常告警
人为失误

软件是人设计和构建的,也是人来维护的。人为也是不可靠的

软件的不同阶段,可以有对应的应对措施

  • 设计编码
    1. 尽可能消除所有不必要的假设,提供合理的抽象,仔细设计 API
    2. 进程间进行隔离,对尤其容易出错的模块使用沙箱机制
    3. 对服务依赖进行熔断设计
  • 测试阶段
    1. 尽可能引入第三方成员测试,尽量将测试平台自动化
    2. 单元测试、集成测试、e2e 测试、混沌测试
  • 运行阶段
    1. 详细的仪表盘
    2. 持续自检
    3. 报警机制
    4. 问题预案
  • 针对组织
    1. 科学的培训和管理

可扩展性

随着规模 增长 ,例如数据 、流量或复杂性,系统应以合理的方式来匹配这种增长

描述应对负载增长能力的指标

描述负载

应对负载前,需要用合适的方式衡量负载,如负载参数

  • 应用日活月活
  • 每秒向 Web 服务器发出的请求
  • 数据库中的读写比率
  • 聊天室中同时活跃的用户数量

书中以 Twitter 2012 年 11 月披露的信息为例进行了说明:

  1. 识别主营业务:发布推文、首页 Feed 流。
  2. 确定其请求量级:发布推文(平均 4.6k 请求/秒,峰值超过 12k 请求/秒),查看其他人推文(300k 请求/秒)

单就这个数据量级来说,无论怎么设计都问题不大。但 Twitter 需要根据用户之间的关注与被关注关系来对数据进行多次处理。常见的有推拉两种方式:

  1. 。每个人查看其首页 Feed 流时,从数据库现拉取所有关注用户推文,合并后呈现。

  1. 。为每个用户保存一个 Feed 流视图,当用户发推文时,将其插入所有关注者 Feed 流视图中。

前者是 Lazy 的,用户只有查看时才会去拉取,不会有无效计算和请求,但每次需要现算,呈现速度较慢。而且流量一大也扛不住。

后者事先算出视图,而不管用户看不看,呈现速度较快,但会引入很多无效请求。

描述性能

如何描述系统性能

  1. 吞吐量(throughput):每秒可以处理的单位数据量,通常记为 QPS。
  2. 响应时间(response time):从用户侧观察到的发出请求到收到回复的时间。
  3. 延迟(latency):日常中,延迟经常和响应时间混用指代响应时间;但严格来说,延迟只是指请求过程中排队等休眠时间,虽然其在响应时间中一般占大头;但只有我们把请求真正处理耗时认为是瞬时,延迟才能等同于响应时间。

响应时间通常以百分位点来衡量,比如 p95,p99 和 p999,它们意味着 95%,99%或 99.9% 的请求都能在该阈值内完成。在实际中,通常使用滑动窗口滚动计算最近一段时间的响应时间分布,并通常以折线图或者柱状图进行呈现。

应对负载

有了描述负载和衡量性能的指标,可以讨论可扩展性了:应对负载增加,如何保持良好性能?

  • 垂直扩展

升级更好的机器

  • 水平扩展

用多个低廉机器分摊负载

负载扩展的两种方式:

  • 自动 如果负载不好预测且多变,则自动较好。坏处在于不易跟踪负载,容易抖动,造成资源浪费。
  • 手动 如果负载容易预测且不长变化,最好手动。设计简单,且不容易出错。

针对不同应用场景:

首先,如果规模很小,尽量还是用性能好一点的机器,可以省去很多麻烦。

其次,可以上云,利用云的可扩展性。甚至如 Snowflake 等基础服务提供商也是 All In 云原生。

最后,实在不行再考虑自行设计可扩展的分布式架构。

两种服务类型:

  • 无状态服务 比较简单,多台机器,外层罩一个 gateway 就行。
  • 有状态服务 根据需求场景,如读写负载、存储量级、数据复杂度、响应时间、访问模式,来进行取舍,设计合乎需求的架构。

可维护性

随着时间的推移,许多新的人员参与到系统开发和运维, 以维护现有功能或适配新场景等,系统都应高效运转。

软件的开发成本不在最初的开发阶段,在于后续的持续投入

  • 修复bug
  • 监控系统正常运行
  • 故障排除
  • 适配新平台
  • 搭配新场景
  • 完善技术缺陷
  • 增加新功能

但是人们只喜欢挖坑,不喜欢填坑。因此可以在设计时,把控好三个原则:

  • 可运维性(Operability) 便于运维团队无痛接手。
  • 简洁性(Simplicity) 便于新手开发平滑上手:这需要一个合理的抽象,并尽量消除各种复杂度。如,层次化抽象。
  • 可演化性(Evolvability) 便于后面需求快速适配:避免耦合过紧,将代码绑定到某种实现上。也称为可扩展性(extensibility)可修改性(modifiability)可塑性(plasticity)
可运维性-方便运维

方便运维团队来保持系统平稳运行。

有效的运维需要这些事情:

  1. 紧盯系统状态,出问题时快速恢复。
  2. 恢复后,复盘问题,定位原因。
  3. 定期对平台、库、组件进行更新升级。
  4. 了解组件间相互关系,避免级联故障。
  5. 建立自动化配置管理、服务管理、更新升级机制。
  6. 执行复杂维护任务,如将存储系统从一个数据中心搬到另外一个数据中心。
  7. 配置变更时,保证系统安全性。

系统具有良好的可维护性,意味着将可定义的维护过程编写文档和工具以自动化,从而解放出人力关注更高价值事情:

  1. 友好的文档和一致的运维规范。
  2. 细致的监控仪表盘、自检和报警。
  3. 通用的缺省配置。
  4. 出问题时的自愈机制,无法自愈时允许管理员手动介入。
  5. 将维护过程尽可能的自动化。
  6. 避免单点依赖,无论是机器还是人。
简洁性-降低复杂度

复杂度表现:

  1. 状态空间的膨胀。
  2. 组件间的强耦合。
  3. 不一致的术语和命名
  4. 为了提升性能的 hack。
  5. 随处可见的补丁(workaround)。

需求很简单,但不妨碍你实现的很复杂:过多的引入了额外复杂度——非问题本身决定的,而由实现所引入的复杂度。

好的解决方法是抽象

复杂度高通常是问题理解的不够本质,写出了“流水账”(没有任何抽象,abstraction)式的代码。

如果你为一个问题找到了合适的抽象,那么问题就解决了一半,如:

  1. 高级语言隐藏了机器码、CPU 和系统调用细节。
  2. SQL 隐藏了存储体系、索引结构、查询优化实现细节。

如何找到合适的抽象?

  1. 从计算机领域常见的抽象中找。
  2. 从日常生活中常接触的概念找。

总之,一个合适的抽象,要么是符合直觉的;要么是和你的读者共享上下文的。

可演化性-快速适配

系统不会一成不变,需求不断变化

  • 适配新的外部环境
  • 新的用例
  • 业务优先级变化
  • 用户所要的新功能
  • 新平台取代旧平台
  • 法律和监管要求的变化
  • 业务增长促使架构演变

应对:

  • 组织流程方面,敏捷开发
  • 设计方面,依赖前两点,合理封装和抽象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计数据密集型应用 (DDIA) 是一本由Martin Kleppmann撰写的专业著作,它深入探讨了如何构建高效可扩展的数据系统和应用程序。这本书通过详细解析不同领域的实际案例,帮助读者了解数据密集型应用的核心原则和最佳实践。 在DDIA中,作者首先介绍了数据系统的核心概念,例如数据模型、一致性、可靠性和可扩展性。然后,他详细阐述了各种数据存储和处理技术,包括关系型数据库、NoSQL数据库、消息队列、流处理等等。通过这些技术的比较和分析,读者可以了解它们的优缺点,并为自己的应用选择最合适的工具。 在第二部分,作者讨论了如何设计数据密集型应用的不同组件,包括数据复制和容错、数据分区和分片、数据一致性和并发控制。他提供了一些建议和模式,以帮助读者解决应用中的常见问题,例如数据冲突、性能瓶颈和容量规划。 最后,作者探讨了如何针对不同的应用场景选择合适的数据系统架构,包括关系型数据库、键值存储、文档数据库和图形数据库。他还介绍了流处理和批处理的概念,并介绍了一些实现这些架构的工具和技术。 通过阅读DDIA,读者可以获得设计和构建数据密集型应用所需的全面知识。这本书不仅适合软件工程师和系统架构师,还适用于对数据系统和应用感兴趣的任何技术人员。无论是构建社交网络、大规模数据分析系统还是电子商务网站,DDIA都是一本不可或缺的参考书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值