【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- 可维护性

简介: 【6月更文挑战第4天】本文探讨了Twitter面临的一次发推文引发的巨大写入压力问题,指出用户粉丝数分布是决定系统扩展性的关键因素。为解决此问题,Twitter采用混合策略,大部分用户推文扇出至粉丝主页时间线,而少数名人推文则单独处理。性能指标包括吞吐量、响应时间和延迟,其中高百分位响应时间对用户体验至关重要。应对负载的方法分为纵向和横向扩展,以及自动和手动调整。文章强调了可维护性的重要性,包括可操作性、简单性和可演化性,以减轻维护负担和适应变化。此外,良好设计应减少复杂性,提供预测性行为,并支持未来改动。

后者的缺点是,发推现在需要大量的额外工作。平均来说,一条推文会发往约75个关注者,所以每秒4.6k的发推写入,变成了对主页时间线缓存每秒345K的写入。但是这个平均值隐藏了用户粉丝数差异巨大这一现实,一些用户有超过3000万的粉丝,这意味着一条推文就可能导致主页时间线缓存的3000万次写入。

在这个例子里,每个用户粉丝数的分布是探讨可扩展性的一个关键负载参数,因为它决定了扇出负载。

最后推特使用了两种方法的混合,大多数用户发的推文会被扇出写入其粉丝主页时间线缓存中,但是少数拥有海量粉丝的用户(名流)会被排除在外。当用户读取主页时间线时,分别获取该用户关注的每位名流的推文,再与用户的主页时间线缓存合并。

描述性能

系统负载是从用户的视角来审视系统,是一种客观指标;系统性能是描述系统的一种实际能力。比如:

  1. 吞吐量:每秒可以处理的单位数据量,通常记为QPS

  2. 响应时间:从用户侧观察到的发出请求到收到回复的时间

  3. 延迟:日常中,延迟经常和响应时间混用指代响应时间,但严格来说,延迟只是把请求过程中排队等休眠时间,虽然其在响应时间中一般占大头;但是只有我们把请求真正处理耗时认为是瞬时,延迟才能等同于响应时间。

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

响应时间的高百分位点(也称为 尾部延迟,即 tail latencies)非常重要,因为它们直接影响用户的服务体验。

应对负载的方法

在讨论了用于描述负载的参数和用于衡量性能的指标后,可以讨论可扩展性了:当负载参数增加时,如何保持良好的性能?

一般有下面两种方案:

  • 纵向扩展,也称为垂直扩展:转向更强大的机器

  • 横向扩展,也成为水平扩展:将负载分布到多台小机器

负载的两种扩展方式:

  • 自动:负载不好预测而且变化较多,使用该方式较好。缺点是不容易跟踪负载,容易抖动,造成资源浪费。

  • 手动:如果负载容易预测且不经常变化,最好手动。设计简单而且不容易出错。

针对不同应用场景来说的话:

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

  • 可以上云,利用云的可扩展性

  • 自行设计可扩展的分布式架构

两种服务类型:

  • 无状态服务:比较简单,多台机器,外层加一个gateway就行

  • 有状态服务:根据需求场景,如读写负载、存储量级、数据复杂度、响应时间、访问模式来进行取舍,设计合乎需求的架构

没有万金油架构!

可维护性

软件的大部分开销并不在最初的开发阶段,而是在持续的维护阶段,包括修复漏洞、保持系统正常运行、调查失效、适配新的平台、为新的场景进行修改、偿还技术债和添加新的功能。

但是我们可以,也应该以这样一种方式来设计软件:在设计之初就尽量考虑尽可能减少维护期间的痛苦,从而避免自己的软件系统变成遗留系统。为此,我们将特别关注软件系统的三个设计原则:

  • 可操作性:便于运维团队保持系统平稳运行

  • 简单性:从系统中消除尽可能多的复杂度,使新工程师也能轻松理解系统

  • 可演化性:工程师在未来能轻松地对系统进行更改,当需求变化时为新应用场景做适配

可操作性:人生苦短,关爱运维

一个优秀运维团队的典型职责如下:

  • 监控系统的运行状况,并在服务状态不佳时快速恢复服务。
  • 跟踪问题的原因,例如系统故障或性能下降。
  • 及时更新软件和平台,比如安全补丁。
  • 了解系统间的相互作用,以便在异常变更造成损失前进行规避。
  • 预测未来的问题,并在问题出现之前加以解决(例如,容量规划)。
  • 建立部署、配置、管理方面的良好实践,编写相应工具。
  • 执行复杂的维护任务,例如将应用程序从一个平台迁移到另一个平台。
  • 当配置变更时,维持系统的安全性。
  • 定义工作流程,使运维操作可预测,并保持生产环境稳定。
  • 铁打的营盘流水的兵,维持组织对系统的了解。

数据系统可以通过各种方式使日常任务更轻松:

  • 通过良好的监控,提供对系统内部状态和运行时行为的 可见性(visibility)
  • 为自动化提供良好支持,将系统与标准化工具相集成。
  • 避免依赖单台机器(在整个系统继续不间断运行的情况下允许机器停机维护)。
  • 提供良好的文档和易于理解的操作模型(“如果做 X,会发生 Y”)。
  • 提供良好的默认行为,但需要时也允许管理员自由覆盖默认值。
  • 有条件时进行自我修复,但需要时也允许管理员手动控制系统状态。
  • 行为可预测,最大限度减少意外。

简单性:管理复杂度

复杂度的表现:

  • 状态空间的膨胀

  • 组件间的强耦合

  • 纠结的依赖关系

  • 不一致的术语和命名

  • 解决性能问题的hack

  • 需要绕开的特例

过多地引入额外复杂度的原因一般是问题理解的不够本质,写出了流水账式的代码。如果你为一个问题找到了合适的抽象,那么问题就解决了一半,如:高级编程语言是一种抽象,隐藏了机器码、CPU 寄存器和系统调用。 SQL 也是一种抽象,隐藏了复杂的磁盘 / 内存数据结构、来自其他客户端的并发请求、崩溃后的不一致性。当然在用高级语言编程时,我们仍然用到了机器码;只不过没有 直接(directly) 使用罢了,正是因为编程语言的抽象,我们才不必去考虑这些实现细节。

如何找到合适的抽象?

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

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

可演化性:降低改变门槛

系统的需求永远不变,基本是不可能的。更可能的情况是,它们处于常态的变化中,例如:

  • 你了解了新的事实

  • 出现意想不到的应用场景

  • 业务优先级发生变化

  • 用户要求新功能

  • 新平台取代旧平台

  • 法律或监管要求发生变化

  • 系统增长迫使架构变化

如何应对?

  • 组织流程方面:敏捷开发

  • 系统设计:简单性与抽象性,合理抽象和封装,对修改关闭,对扩展开放

目录
相关文章
|
16天前
|
存储 关系型数据库 数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 多对一和多对多
【6月更文挑战第7天】该文探讨数据模型,比较了“多对一”和“多对多”关系。通过使用ID而不是纯文本(如region_id代替"Greater Seattle Area"),可以实现统一、避免歧义、简化修改、支持本地化及优化搜索。在数据库设计中,需权衡冗余和范式。文档型数据库适合一对多但处理多对多复杂,若无Join,需应用程序处理。关系型数据库则通过外键和JOIN处理这些关系。文章还提及文档模型与70年代层次模型的相似性,层次模型以树形结构限制了多对多关系处理。为克服层次模型局限,发展出了关系模型和网状模型。
23 6
|
18天前
|
XML NoSQL 数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 概念 + 数据模型
【6月更文挑战第5天】本文探讨了数据模型的分析,关注点包括数据元素、关系及不同类型的模型(关系、文档、图)与Schema模式。查询语言的考量涉及与数据模型的关联及声明式与命令式编程。数据模型从应用开发者到硬件工程师的各抽象层次中起着简化复杂性的关键作用,理想模型应具备简洁直观和可组合性。
15 2
|
15天前
|
SQL 人工智能 关系型数据库
【DDIA笔记】【ch2】 数据模型和查询语言 -- 文档模型中Schema的灵活性
【6月更文挑战第8天】网状模型是层次模型的扩展,允许节点有多重父节点,但导航复杂,需要预知数据库结构。关系模型将数据组织为元组和关系,强调声明式查询,解耦查询语句与执行路径,简化了访问并通过查询优化器提高效率。文档型数据库适合树形结构数据,提供弱模式灵活性,但在Join支持和访问局部性上不如关系型。关系型数据库通过外键和Join处理多对多关系,适合高度关联数据。文档型数据库的模式灵活性体现在schema-on-read,写入时不校验,读取时解析,牺牲性能换取灵活性。适用于不同类型或结构变化的数据场景。
17 0
|
17天前
|
SQL JSON NoSQL
【DDIA笔记】【ch2】 数据模型和查询语言 -- 关系模型与文档模型
【6月更文挑战第6天】关系模型是主流数据库模型,以二维表形式展示数据,支持关系算子。分为事务型、分析型和混合型。尽管有其他模型挑战,如网状和层次模型,但关系模型仍占主导。然而,随着大数据增长和NoSQL的出现(如MongoDB、Redis),强调伸缩性、专业化查询和表达力,关系模型的局限性显现。面向对象编程与SQL的不匹配导致“阻抗不匹配”问题,ORM框架缓解但未完全解决。文档模型(如JSON)提供更自然的嵌套结构,适合表示复杂关系,具备模式灵活性和更好的数据局部性。
20 0
|
20天前
|
缓存 关系型数据库 数据库
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- 可扩展性
【6月更文挑战第3天】可扩展性关乎系统应对负载增长的能力,但在产品初期过度设计可能导致失败。理解基本概念以应对可能的负载增长是必要的。衡量负载的关键指标包括日活、请求频率、数据库读写比例等。推特的扩展性挑战在于"扇出",即用户关注网络的广度。两种策略包括拉取(按需查询数据库)和推送(预计算feed流)。推送方法在推特案例中更为有效,因为它减少了高流量时的实时计算压力。
23 0
|
21天前
|
存储 消息中间件 缓存
【DDIA笔记】【ch1】 可靠性、可扩展性和可维护性 -- part1 可靠性
【6月更文挑战第2天】本书探讨现代数据系统,阐述其在信息社会中的关键作用,包括数据库、缓存、搜索引擎、流处理、批处理和消息队列等组成部分。随着技术发展,工具如Kafka、Spark和Redis等多功能组件使得系统设计更为复杂。面对可靠性、可扩展性和可维护性的挑战,书中强调了容错和韧性的重要性,区分了硬件故障、软件错误和人为错误,并提出了应对措施。可靠性关乎用户数据、企业声誉和生存,因此是系统设计的核心考量。
24 0
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件
有了原理图,可以设计硬件PCB,在设计PCB之间还有一个协同优先动作,就是映射封装,原理图库的元器件我们是自己设计的。为了更好的表述封装设计过程,本文描述了CH340G和MAX232芯片封装创建(SOP-16),并将原理图的元器件关联引脚封装。
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件

热门文章

最新文章