元数据

SRE:Google运维解密

  •  SRE:Google运维解密|200
  • 书名: SRE:Google运维解密
  • 作者: 贝特西·拜尔等
  • 简介: 在本书中,不仅展示了 Google 是如何运用各种计算机工具软件、硬件以持续部署和监控一些世界上最大的软件系统的。还展示了在运维过程中,Google 工程师团队是如何学习、成长、反复修改,最后定义出一套完整的工具和科技体系的过程。本书适合各种水平的运维工程师参考使用。
  • 出版时间 2016-10-01 00:00:00
  • ISBN: 9787121297267
  • 分类: 计算机-计算机综合
  • 出版社: 电子工业出版社

高亮划线

时间序列数据的存储

  • 📌 ime-series的名字称为标签集合(labelset),因为它的实现方式就是一个标签(key=value)的集合。 ^26271721-81-2253-2340
    • ⏱ 2022-01-02 18:00:28

负载均衡:虚拟IP

  • 📌 虚拟IP地址(VIP)不是绑定在某一个特定的网络接口上的,它是由很多设备共享的。 ^26271721-139-465-505

    • ⏱ 2021-12-30 12:30:32
  • 📌 一致性哈希(consistent hashing)算法。 ^26271721-139-1696-1731

    • ⏱ 2021-12-30 12:37:18
  • 📌 直接服务器响应(DSR ^26271721-139-2179-2197

    • ⏱ 2021-12-30 12:38:34
  • 📌 但是使用2层信息进行内部负载均衡会导致在大规模部署下出现问题:所有的机器(也就是所有的负载均衡器和所有的后端服务器)必须可以在数据链路层相通。如果服务器数量不多,网络能够支撑这样的连接那就不是问题,但是所有的机器都需要在同一个广播域中。正如你想的那样,Google 在一段时间后,由于规模原因,已经放弃了这种方案。 ^26271721-139-2281-2438

    • ⏱ 2021-12-30 12:40:19
  • 📌 包封装(encapsulation)模式。网络服务在均衡器将待转发的网络包采用通用路由封装协议(GRE,参见文献[Han94])封装到另外一个IP包中,使用后端服务器的地址作为目标地址。后端服务器接收到网络包,将IP和GRE层拆除,直接处理内部的IP包,就像直接从网络接口接收到的那样。网络负载均衡器和后端不再需要共存在同一个广播域中,只要中间有路由连接即可 ^26271721-139-2501-2680

    • ⏱ 2021-12-30 12:44:16

识别异常任务:流速控制和跛脚鸭任务

  • 📌 在Google的RPC框架实现中,不活跃的客户端(没有建立TCP连接的客户端)也会定期发送UDP健康检查包。 ^26271721-142-1645-1699

    • ⏱ 2021-12-30 12:53:59
  • 📌 跛脚鸭状态后端任务正在监听端口,并且可以服务请求,但是已经明确要求客户端停止发送请求。 ^26271721-142-1493-1565

    • ⏱ 2021-12-30 12:56:17

利用划分子集限制连接池大小

  • 📌 子集划分:限制某个客户端任务需要连接的后端任务数量。 ^26271721-143-514-547

    • ⏱ 2021-12-30 12:58:00
  • 📌 我们将客户端任务划分在多“轮”中 ^26271721-143-3729-3745

    • ⏱ 2021-12-30 13:20:30
  • 📌 子集选择算法二:确定性算法 ^26271721-143-3423-3436

    • ⏱ 2021-12-30 13:24:20
  • 📌 这里要注意的关键点是,每一轮计算仅仅将整个列表中的每一个后端分配给唯一一个客户端 ^26271721-143-4252-4292

    • ⏱ 2021-12-30 13:25:26
  • 📌 这个列表应该被随机重排 ^26271721-143-4373-4384

    • ⏱ 2021-12-30 13:27:14
  • 📌 在每轮计算中使用不同的重排列表 ^26271721-143-4666-4681

    • ⏱ 2021-12-30 13:27:26

负载均衡策略

  • 📌 需要我们的任务编排系统跟踪某个任务平均机器性能的取样数据,同时在具体调度资源的时候将其考虑在内。 ^26271721-144-2640-2688

    • ⏱ 2021-12-30 13:45:15
  • 📌 我们创造了一个虚拟CPU单位(Google计算单元GCU)。我们用GCU来给CPU性能建模,同时维护一个GCU与不同CPU类型的性能映射表。 ^26271721-144-2782-2852

    • ⏱ 2021-12-30 13:45:30
  • 📌 如果一个任务目前不健康,它可能会开始返回100%的错误。取决于错误的类型,错误回复可能延迟非常低;一般来说返回一个“我不健康”的错误比实际处理请求要快得多。于是,客户端任务错误地认为该任务可用,从而给该异常任务分配了大量的请求。我们在这里将这种问题称之为地漏效应(sinkhole effect)。幸运的是,这个问题有一个相对简单的解决办法—将最近收到的错误信息计算为活跃请求。这样,如果某个后端进入异常状态,负载均衡策略可以开始将负载迁走,正如迁走过载项目的负载那样。 ^26271721-144-4925-5188

    • ⏱ 2021-12-30 13:52:54
  • 📌 在实际中,我们发现使用最闲轮询策略的大型服务会造成最忙任务比最闲服务使用两倍的CPU。该策略与简单轮询策略一样,效果都很差。 ^26271721-144-5676-5738

    • ⏱ 2021-12-30 13:55:35
  • 📌 但是我们发现轮询策略可能会导致最高负载任务比最低负载任务使用2倍的CPU资源。这样的负载均衡结果是非常浪费的 ^26271721-144-1021-1075

    • ⏱ 2021-12-30 13:57:15
  • 📌 每个客户端的活跃请求不包括其他客户端发往同一个后端的请求 ^26271721-144-5553-5581

    • ⏱ 2021-12-30 13:58:02
  • 📌 在实践中,加权轮询策略效果非常好,极大降低了最高和最低负载任务的差距。 ^26271721-144-6140-6175

    • ⏱ 2021-12-30 13:59:39

第21章 应对过载

  • 📌 应对过载的一个选项是服务降级:返回一个精确度降低的回复,或者省略回复中一些需要大量计算的数据。 ^26271721-145-683-730
    • ⏱ 2021-12-30 14:02:17

QPS陷阱

  • 📌 Google在多年的经验积累中得出:按照QPS来规划服务容量,或者是按照某种静态属性(认为其能指代处理所消耗的资源:例如某个请求所需要读取的键值数量)一般是错误的选择。就算这个指标在某一个时间段内看起来工作还算良好,早晚也会发生变化。 ^26271721-146-591-708

    • ⏱ 2021-12-30 17:42:26
  • 📌 更好的解决方案是直接以可用资源来衡量可用容量。例如,某服务可能在某个数据中心内预留了500 CPU 内核和1TB内存用以提供服务。用这些数字来建模该数据中心的服务容量是非常合理的。我们经常将某个请求的“成本”定义为该请求在正常情况下所消耗的CPU时间(这里要考虑到不同CPU类型的性能差异问题)。 ^26271721-146-822-970

    • ⏱ 2021-12-30 17:44:20
  • 📌 在绝大部分情况下(当然总会有例外情况),我们发现简单地使用CPU数量作为资源配给的主要信号就可以工作得很好 ^26271721-146-999-1052

    • ⏱ 2021-12-30 17:48:39

给每个用户设置限制

  • 📌 当全局过载情况真的发生时,使服务只针对某些“异常”客户返回错误是非常关键的,这样其他用户则不会受影响。为了达到这个目的,该服务的运维团队和客户团队协商一个合理的使用约定,同时使用这个约定来配置用户配额,并且配置相应的资源。 ^26271721-147-693-804
    • ⏱ 2021-12-30 17:49:58

客户端侧的节流机制

  • 📌 当某个客户端检测到最近的请求错误中的一大部分都是由于“配额不足”错误导致时,该客户端开始自行限制请求速度,限制它自己生成请求的数量。超过这个请求数量限制的请求直接在本地回复失败,而不会真正发到网络层。 ^26271721-148-859-959

    • ⏱ 2021-12-30 17:56:45
  • 📌 自适应节流 ^26271721-148-1017-1029

    • ⏱ 2021-12-30 18:00:48
  • 📌 客户端请求拒绝概率 ^26271721-148-1465-1474

    • ⏱ 2021-12-30 18:00:55

处理过载错误

  • 📌 每个客户端都跟踪重试与请求的比例。一个请求在这个比例低于10%的时候才会重试。 ^26271721-151-1775-1814

    • ⏱ 2021-12-30 22:50:43
  • 📌 请求只应该在被拒绝的层面上面的那一层进行重试。当我们决定某个请求无法被处理,同时不应该被重试时,返回一个“过载;无须重试”错误 ^26271721-151-2835-2898

    • ⏱ 2021-12-30 23:02:57
  • 📌 每次请求重试次数限制,限制重试3次。 ^26271721-151-1589-1614

    • ⏱ 2021-12-30 23:34:32

连接造成的负载

  • 📌 批处理代理任务实际充当了保险丝的角色。 ^26271721-152-1219-1238

    • ⏱ 2021-12-30 23:26:50
  • 📌 强制要求批处理任务使用某些特定的批处理代理后端任务,这些代理仅仅转发请求,同时将回复转发给客户端。于是,请求路线从“批处理客户端→后端”变为“批处理客户端→批处理代理→后端”。 ^26271721-152-1063-1151

    • ⏱ 2021-12-30 23:27:54
  • 📌 我们观察到,超大规模的批处理任务会在短时间内建立大量的客户端。协商和维护这些超大数量的连接可以造成整个后端的过载。 ^26271721-152-853-910

    • ⏱ 2021-12-30 23:28:29

第22章 处理连锁故障

  • 📌 连锁故障是由于正反馈循环(positive feedback)导致的不断扩大规模的故障。 ^26271721-154-718-834
    • ⏱ 2021-12-30 23:39:09

防止软件服务器过载

  • 📌 使用负载压力测试得出服务器的极限,同时测试过载情况下的失败模式 ^26271721-156-518-549

    • ⏱ 2021-12-31 01:53:56
  • 📌 提供降级结果 ^26271721-156-681-687

    • ⏱ 2021-12-31 01:54:23
  • 📌 在过载情况下主动拒绝请求 ^26271721-156-803-815

    • ⏱ 2021-12-31 01:54:48
  • 📌 大部分“每个请求一个线程”模型的软件服务器使用一个队列和一个线程池来处理请求。接收到的请求将会进入队列,线程池中的某线程会将请求从队列中取出,进行实际处理。通常情况下,当队列排满时,服务器会拒绝新的请求。 ^26271721-156-1936-2038

    • ⏱ 2021-12-31 02:23:35
  • 📌 对一个流量基本稳定的服务来说,队列长度比线程池大小更小会更好(如 50% 或更小)。当服务处理速度无法跟上请求到达速率时,尽早拒绝请求会更好。 ^26271721-156-2334-2405

    • ⏱ 2021-12-31 02:26:35
  • 📌 流量抛弃(load shedding)是指在软件服务器临近过载时,主动抛弃一定量的负载。 ^26271721-156-2629-2680

    • ⏱ 2021-12-31 02:28:20
  • 📌 可以通过降低回复的质量来大幅减少所需的计算量 ^26271721-156-3493-3515

    • ⏱ 2021-12-31 02:31:52
  • 📌 一定要使用随机化的、指数型递增的重试周期。 ^26271721-156-6506-6528

    • ⏱ 2021-12-31 02:48:51
  • 📌 考虑使用一个全局重试预算。例如,每个进程每分钟只允许重试60次,如果重试预算耗尽,那么直接将这个请求标记为失败,而不真正发送它。这个策略可以在全局范围内限制住重试造成的影响 ^26271721-156-6794-6881

    • ⏱ 2021-12-31 02:51:01
  • 📌 RPC截止时间(deadline)定义了前端会等待多长时间,这限制了后端可以消耗的前端资源。 ^26271721-156-7656-7702

    • ⏱ 2021-12-31 12:44:14
  • 📌 可使用截止时间传递机制 ^26271721-156-8582-8593

    • ⏱ 2021-12-31 13:24:53

慢启动和冷缓存

  • 📌 当使用延迟类缓存时,服务器可以在空缓存的情况下仍然处理预期的请求负载,但是使用容量类缓存时,该服务将不能够在空缓存下处理请求负载。 ^26271721-157-1616-1681

    • ⏱ 2021-12-31 14:36:47
  • 📌 在用户的请求路径中最好能够避免使用同层通信—也就是避免通信路径中出现环。应该由客户端来进行这种通信。例如,如果一个前端需要和后端通信,但是猜错了后端任务,后端不会代理请求给正确的后端,而是通过返回错误使得前端在正确的后端任务上重试它的请求。 ^26271721-157-2817-2937

    • ⏱ 2021-12-31 14:51:42

解决连锁故障的立即步骤

  • 📌 进程任务的健康检查(“这个进程是否响应请求”)和服务级别的健康检查(“该进程是否能够回复这种类型的请求”)是两种概念不同的操作。进程任务的健康检查对集群管理系统有用,而服务健康检查对负载均衡器有用。 ^26271721-160-954-1053
    • ⏱ 2021-12-31 15:23:22

第23章 管理关键状态:利用分布式共识来提高可靠性

  • 📌 分布式共识系统主要解决了在不稳定的通信环境下一组进程之间对某项事情达成一致的问题。 ^26271721-162-1146-1187
    • ⏱ 2021-12-31 15:40:21

使用共识系统的动力:分布式系统协调失败

  • 📌 事实上,很多分布式系统问题最后都归结为分布式共识问题的不同变种,包括领头人选举,小组成员信息,各种分布式锁和租约机制,可靠的分布式队列和消息传递,以及任何一种需要在多个进程中共同维护一致的关键状态的机制。 ^26271721-163-2283-2385
    • ⏱ 2021-12-31 16:18:44

分布式共识是如何工作的

  • 📌 拜占庭式问题指的是当某个进程由于程序Bug或者恶意行为发送不正确的消息的问题 ^26271721-164-869-914

    • ⏱ 2021-12-31 16:22:42
  • 📌 严格来讲,在有限时间内解决异步式分布式共识问题是不可能的。 ^26271721-164-966-995

    • ⏱ 2021-12-31 16:23:32
  • 📌 在实际操作中,我们通过保证给系统提供足够的健康的副本,以及良好的网络连接状态来保障分布式共识算法在大多数情况下是可以在有限时间内达成共识的。同时整个系统还需要加入随机指数型延迟。这样,我们可以保障重试不会造成连锁反应,以及本章后面会提到的角斗士(dueling proposers)问题。 ^26271721-164-1123-1267

    • ⏱ 2021-12-31 16:24:34
  • 📌 Paxos概要:协议示例 ^26271721-164-1584-1596

    • ⏱ 2021-12-31 16:33:09

分布式共识的系统架构模式

  • 📌 基于其他的非共识算法实现的系统经常简单地依赖于时间戳来决定返回哪些数据。时间戳在分布式系统中问题非常大,因为在多个物理机器上保证时间同步是不可能的。 ^26271721-165-2141-2215

    • ⏱ 2021-12-31 16:57:23
  • 📌 唯一的领头人是一种保证粗粒度互斥性的方法。这种设计类型在服务领头人的工作量是分片的,或者可以被一个进程所满足的情况下是合理的。 ^26271721-165-2441-2533

    • ⏱ 2021-12-31 16:59:02
  • 📌 屏障(barrier)在分布式计算中是一种原语,可以用来阻挡一组进程继续工作,直到某种条件被满足 ^26271721-165-3130-3185

    • ⏱ 2021-12-31 17:03:26
  • 📌 屏障也可以用一个RSM系统来实现。 ^26271721-165-3608-3625

    • ⏱ 2021-12-31 17:04:47
  • 📌 采用队列模式的系统可以很容易地处理某个工作节点的失效情况。然而,系统必须保证已经被领取的任务都被成功处理了。由于这个原因,建议采用某种租约系统 ^26271721-165-4119-4218

    • ⏱ 2021-12-31 17:27:19
  • 📌 原子性广播是分布式系统的一个原语,意思是整个系统的参与者都可以可靠地接收到消息,并且以同样的顺序来处理这些消息。 ^26271721-165-4365-4428

    • ⏱ 2021-12-31 17:33:31
  • 📌 原子性广播和分布式共识本质上是一个问题。 ^26271721-165-4547-4567

    • ⏱ 2021-12-31 17:34:28
  • 📌 队列和消息系统经常需要非常好的系统吞吐量,但是并不一定追求低延迟(这些系统很少是直接面向用户的)。 ^26271721-165-5080-5129

    • ⏱ 2021-12-31 17:43:51
  • 📌 利用RSM来实现队列可以将危险性最小化,从而使得整个系统更加可靠。 ^26271721-165-4282-4315

    • ⏱ 2022-01-01 15:28:44
  • 📌 锁(lock)是另外一个很有用的协调性原语,可以用RSM实现。 ^26271721-165-3717-3755

    • ⏱ 2022-01-01 15:30:25
  • 📌 在实践中,使用可续租约(renewable Lease)而不是无限时间锁是很有必要的,避免某个进程崩溃而导致锁无限期被持有。 ^26271721-165-3818-3880

    • ⏱ 2022-01-01 15:30:55
  • 📌 布式锁是一个应该被小心使用的底层系统原语。大多数应用程序应该使用一种更高层的系统来提供分布式事务服务。 ^26271721-165-3907-3958

    • ⏱ 2022-01-01 15:31:11
  • 📌 领头人的工作通常是负责协调某个工作者池中的工作者进程。 ^26271721-165-2607-2634

    • ⏱ 2022-01-01 15:37:43
  • 📌 复制状态机(replicated state machine,RSM)是一个能在多个进程中用同样顺序执行同样的一组操作的系统。 ^26271721-165-1099-1169

    • ⏱ 2022-01-01 15:43:19
  • 📌 共识算法处理节点间对操作顺序的共识,RSM系统按照这个顺序来执行操作。 ^26271721-165-1432-1467

    • ⏱ 2022-01-01 15:45:05

分布式共识系统的性能问题

  • 📌 法定租约技术针对数据的一部分给系统中的法定人数进程发放了一个租约,这个租约是带有具体时间范围的(通常很短)。在这个法定租约有限期间,任何对该部分数据的操作都必须要被法定租约中的所有进程响应。如果租约中的任何一个副本不可用,那么该部分数据在租约过期前将无法被修改。 ^26271721-166-4467-4598

    • ⏱ 2022-01-01 16:24:34
  • 📌 使用法定租约(quorum lease)协议,在该协议下,某些副本被授予部分或者全部数据的一个租约,用一些写性能上的损失换来了强一致性的本地读操作的可能。 ^26271721-166-4044-4121

    • ⏱ 2022-01-01 16:25:56

分布式共识系统的部署

  • 📌 领头人进程会使用更多的计算资源,尤其是网络容量。这是因为,领头人进程会发送带有数据的提议,但是其他副本发送的都只是回应数据,相对较小。 ^26271721-167-5535-5602

    • ⏱ 2022-01-01 17:15:13
  • 📌 保证领头人进程在数据中心之间分布相对均衡是很有必要的。 ^26271721-167-5622-5649

    • ⏱ 2022-01-01 17:17:15
  • 📌 层级型的仲裁过程 ^26271721-167-7641-7649

    • ⏱ 2022-01-01 17:24:26
  • 📌 9个副本可能会被部署为3组,每组3个。仲裁过程可以由多数组完成,而每个组只有在多数成员可用的情况下才可用。 ^26271721-167-7665-7718

    • ⏱ 2022-01-01 17:24:50

Google Cron系统的构建过程

  • 📌 分布式Cron系统使用了一个单独的领头人任务,该副本是唯一一个可以修改共享状态的副本,也是唯一一个可以启动Cron任务的副本。 ^26271721-174-1541-1604

    • ⏱ 2022-01-02 00:05:56
  • 📌 各个副本利用Paxos协议同步的最重要的状态信息就是哪些Cron任务已经被启动了。该服务需要不停地以同步方式通知大多数的副本每个计划任务的启动和结束信息。 ^26271721-174-2193-2270

    • ⏱ 2022-01-02 00:13:41
  • 📌 Paxos 通信的同步性是很重要的 ^26271721-174-3129-3146

    • ⏱ 2022-01-02 00:25:12
  • 📌 追随者副本需要持续跟踪领头人进程提供的目前的系统状态,以便在需要的时候及时替换。所有的状态改变都是从领头人角色基于Paxos协议传递的。 ^26271721-174-3726-3794

    • ⏱ 2022-01-02 00:28:53
  • 📌 Cron任务启动过程的完成也需要通过Paxos协议同步通知给其他的副本。 ^26271721-174-3354-3390

    • ⏱ 2022-01-02 00:29:14
  • 📌 领头人进程是唯一一个主动启动Cron任务的进程。该领头人进程内部有一个内置调度器,与本章开头提到的简单的crond实现非常类似。该调度器按照预定的启动时间排序维护一个Cron任务列表。 ^26271721-174-2477-2569

    • ⏱ 2022-01-02 00:29:37
  • 📌 领头人进程和数据中心调度系统之间的单个任务启动的过程可能在多个RPC中间失败。 ^26271721-174-4308-4347

    • ⏱ 2022-01-02 00:35:05
  • 📌 为了能够判断RPC是否成功发送,下列情况中的一个必须被满足:● 所有需要在选举过后继续的,对外部系统的操作必须是幂等的(这样我们可以在选举过后重新进行该操作)。● 必须能够通过查询外部系统状态来无疑义地决定某项操作是否已经成功。 ^26271721-174-4647-4819

    • ⏱ 2022-01-02 00:36:44
  • 📌 一种解决幂等性问题的方案是提前构建一致的任务名称,并且分发给所有的Cron服务副本(这样就可避免在数据中心调度器上进行任何的修改操作)。如果领头人副本在启动过程中崩溃,新的领头人副本可以通过预计算的任务名称来查询任务的状态。 ^26271721-174-5070-5182

    • ⏱ 2022-01-02 00:44:22
  • 📌 除了在本地存储的日志和快照,以及分布式文件系统上的快照备份之外,一个刚刚启动的副本可以从另外一个已经运行的副本上获得最新的快照和日志。 ^26271721-174-6980-7047

    • ⏱ 2022-01-02 01:04:46

分布式环境中周期性数据流水线的缺点

  • 📌 “摩尔负载模式”(Moiré Load Pattern)。该问题是指两个或者更多的流水线任务同时运行时,某些执行过程重叠,导致它们同时消耗某个共享资源。 ^26271721-181-2876-2952
    • ⏱ 2022-01-02 01:32:30

数据完整性的强需求

  • 📌 保障超高数据完整性的手段是主动探测和快速修复能力。 ^26271721-187-1627-1652
    • ⏱ 2022-01-02 17:23:06

读书笔记

本书评论