临时¶
分布式系统优缺点¶
使用分布式系统主要有两方面原因:
1. 增大系统容量
我们的业务量越来越大,而要能应对越来越大的业务量,
一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。
所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。
2. 加强系统可用
我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。
这样,整个系统不会因为一台机器出故障而导致整体不可用。
所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。
分布式系统还有一些优势,比如:
1. 因为模块化,所以系统模块重用度更高
2. 因为软件服务模块被拆分,开发和发布速度可以并行而变得更快
3. 系统扩展性更高
4. 团队协作流程也会得到改善
5. ……
分布式架构的问题:
1. 架构设计变得复杂(尤其是其中的分布式事务)
2. 部署单个服务会比较快,但是如果一次部署需要多个服务,流程会变得复杂
3. 系统的吞吐量会变大,但是响应时间会变长
4. 运维复杂度会因为服务变多而变得很复杂
5. 架构复杂导致学习曲线变大
6. 测试和查错的复杂度增大
7. 技术多元化,这会带来维护和运维的复杂度
8. 管理分布式系统中的服务和调度变得困难和复杂
备注
分布式系统架构的难点在于系统设计,以及管理和运维。
分布式系统的发展¶
分布式系统技术栈¶
构建分布式系统的目的是增加系统容量,提高系统的可用性,转换成技术方面,也就是完成下面两件事:
1. 大流量处理
通过集群技术把大规模并发请求的负载分散到不同的机器上。
2. 关键业务保护
提高后台服务的可用性,把故障隔离起来阻止多米诺骨牌效应(雪崩效应)。
如果流量过大,需要对业务降级,以保护关键业务流转。
即:
1. 提高整体架构的吞吐量,服务更多的并发和流量
2. 为了提高系统的稳定性,让系统的可用性更高
提高架构的性能¶
提高架构的稳定性¶
分布式系统的关键技术¶
1. 服务治理。
服务拆分、服务调用、服务发现、服务依赖、服务的关键度定义……
服务治理的最大意义是需要把服务间的依赖关系、服务调用链,以及关键的服务给梳理出来,
并对这些服务进行性能和可用性方面的管理。
2. 架构软件管理。
服务之间有依赖,而且有兼容性问题,
所以,整体服务所形成的架构需要有架构版本管理、整体架构的生命周期管理,
以及对服务的编排、聚合、事务处理等服务调度功能。
3. DevOps。
分布式系统可以更为快速地更新服务,但是对于服务的测试和部署都会是挑战。
所以,还需要 DevOps 的全流程,其中包括环境构建、持续集成、持续部署等。
4. 自动化运维。
有 DevOps 后,就可以对服务进行自动伸缩、故障迁移、配置管理、状态管理等一系列的自动化运维技术了。
5. 资源调度管理。
应用层的自动化运维需要基础层的调度支持,
也就是云计算 IaaS 层的计算、存储、网络等资源调度、隔离和管理。
6. 整体架构监控。
如果没有一个好的监控系统,那么自动化运维和资源调度管理只可能成为一个泡影,
因为监控系统是你的眼睛。没有眼睛,没有数据,就无法进行高效的运维。
所以说,监控是非常重要的部分。
这里的监控需要对三层系统(应用层、中间件层、基础层)进行监控。
7. 流量控制。
包括负载均衡、服务路由、熔断、降级、限流等和流量相关的调度
还包括灰度发布之类的功能也在这里。
分布式系统的”纲”¶
分布式系统有五个关键技术:
1. 全栈系统监控
2. 服务 / 资源调度
3. 流量调度
4. 状态 / 数据调度
5. 开发和运维的自动化
开发和运维的自动化,是需要把前四项都做到了,才有可能实现的
关键技术: 全栈监控¶
监控的标准化:
1. 日志数据结构化;
2. 监控数据格式标准化;
3. 统一的监控平台;
4. 统一的日志分析。
好的监控系统¶
监控系统都做不好有两个很大的问题:
1. 监控数据是隔离开来的。
因为公司分工的问题,开发、应用运维、系统运维,各管各的,
所以很多公司的监控系统之间都有一道墙,完全串不起来。
2. 监控的数据项太多。
有些公司的运维团队把监控的数据项多做为一个亮点到处讲,比如监控指标达到 5 万多个。
老实说,这太丢人了。
因为信息太多等于没有信息,抓不住重点的监控才会做成这个样子。
一个好的监控系统应该有以下几个特征:
1. 关注于整体应用的 SLA。
主要从为用户服务的 API 来监控整个系统。
2. 关联指标聚合。
把有关联的系统及其指标聚合展示。
主要是三层系统数据:基础层、平台中间件层和应用层。
最重要的是把服务和相关的中间件以及主机关联在一起
无论运行在哪里,我们都需要把服务的具体实例和主机关联在一起,
否则,对于一个分布式系统来说,定位问题犹如大海捞针。
3. 快速故障定位。
对于现有的系统来说,故障总是会发生的,而且还会频繁发生。
故障发生不可怕,可怕的是故障的恢复时间过长。
所以,快速地定位故障就相当关键。
快速定位问题需要对整个分布式系统做一个用户请求跟踪的 trace 监控,
需要监控到所有的请求在分布式系统中的调用链,这个事最好是做成没有侵入性的。
一个好的监控系统主要是为以下两个场景所设计的:
1. “体检”
a. 容量管理。
提供一个全局的系统运行时数据的展示,可以让工程师团队知道是否需要增加机器或者其它资源。
b. 性能管理。
可以通过查看大盘,找到系统瓶颈,并有针对性地优化系统和相应代码。
2. “急诊”
a. 定位问题。
可以快速地暴露并找到问题的发生点,帮助技术人员诊断问题。
b. 性能分析。
当出现非预期的流量提升时,可以快速地找到系统的瓶颈,并帮助开发人员深入代码。
一个好的监控系统应该实现的功能:
1. 服务调用链跟踪。
这个事情的最佳实践是 Google Dapper 系统
2. 服务调用时长分布
有助于我们知道最耗时的服务是什么
3. 服务的 TOP N 视图
有三种排名的方法:
a. 按调用量排名
b. 按请求最耗时排名
c. 按热点排名(一个时间段内的请求次数的响应时间和)
4. 数据库操作关联
执行数据库操作的执行时间
5. 服务资源跟踪
把服务运行的机器节点上的数据(如 CPU、MEM、I/O、DISK、NETWORK)关联起来
现象都是某个服务过慢:
1. 如果是因为 CPU 使用过多,我们就可以做弹性伸缩。
2. 如果是因为 MySQL 出现慢查询,就不能在应用层上做弹性伸缩,只能做流量限制,或降级操作
关键技术: 服务调度¶
备注
服务治理可能混合了流量调度等其它内容。
服务治理¶
服务治理上的关键技术:
1. 服务关键程度
2. 服务依赖关系
3. 服务发现
4. 整个架构的版本管理
5. 服务应用生命周期全管理
1. 服务关键程度¶
这不是使用技术可以完成的,
它需要细致地管理对业务的理解,才能定义出架构中各个服务的重要程度。
2. 服务依赖关系¶
依赖关系就像“铁锁连环”一样,一个服务的问题很容易出现一条链上的问题。
因此:
a. 传统的 SOA 希望通过 ESB 来解决服务间的依赖关系
b. 微服务希望服务间是没有依赖的,而让上层或是前端业务来整合这些个后台服务
真正做到服务无依赖,我认为还是比较有困难的:
我们只能是降低服务依赖的深度和广度,从而让管理更为简单和简洁
备注
微服务是服务依赖最优解的上限,而服务依赖的下限是千万不要有依赖环。
解决服务依赖环的方案:
依赖倒置的设计模式。
在分布式架构上,你可以使用一个第三方的服务来解决这个事。
比如:
1. 通过订阅或发布消息到一个消息中间件,
2. 把其中的依赖关系抽到一个第三方的服务中,由这个三方服务来调用这些原本循环依赖的服务
服务的依赖关系发现:
全链路追踪
备注
梳理完服务的重要程度和服务依赖关系之后,我们就相当于知道了整个架构的全局。就好像我们得到了一张城市地图,在这张地图上可以看到城市的关键设施,以及城市的主干道。再加上相关的监控,我们就可以看到城市各条道路上的工作和拥堵情况。这对于我们整个分布式架构是非常非常关键的。在解决一些高并发或是架构问题的时候,有这么一张地图非常方便。
3. 服务发现¶
“架构城市”是非常动态的,有的服务会新加进来,有的会离开,有的会增加更多的实例,有的会减少,有的服务在维护过程中(发布、伸缩等),所以我们需要有一个服务注册中心,来知道这么几个事:
1. 整个架构中有多少种服务
2. 这些服务的版本是什么样的
3. 每个服务的实例数有多少个,它们的状态是什么样的
4. 每个服务的状态是什么样的
部署中,运行中,故障中,升级中,回滚中,伸缩中,下线中
4. 整个架构的版本管理¶
备注
除了各个项目的版本管理之外,还需要在上面再盖一层版本管理。如:Linux 分发包中各个软件的版本上会再盖一层版本控制。毕竟,这些分发包也是有版本依赖的,这样可以解决各个包的版本兼容性问题。
一个架构的 manifest,一个服务清单,这个服务清单定义了所有服务的版本运行环境,其中包括但不限于:
1. 服务的软件版本
2. 服务的运行环境——环境变量、CPU、内存、可以运行的结点、文件系统等
3. 服务运行的最大最小实例数
5. 服务应用生命周期全管理¶
服务的生命周期通常会有以下几个状态:
1. Provision,代表在供应一个新的服务
2. Ready,表示启动成功了
3. Run,表示通过了服务健康检查
4. Update,表示在升级中
5. Rollback,表示在回滚中
6. Scale,表示正在伸缩中(可以有 Scale-in 和 Scale-out 两种)
7. Destroy,表示在销毁中
8. Failed,表示失败状态
资源 / 服务调度¶
备注
服务和资源的调度有点像操作系统。操作系统一方面把用户进程在硬件资源上进行调度,另一方面提供进程间的通信方式,可以让不同的进程在一起协同工作。
一些关键技术:
1. 服务状态的维持和拟合
2. 服务的弹性伸缩和故障迁移
3. 作业和应用调度
4. 作业工作流编排
5. 服务编排
1. 服务状态的维持和拟合¶
所谓服务状态不是服务中的数据状态,而是服务的运行状态:
换句话说就是服务的 Status,而不是 State
也就是上述服务运行时生命周期中的状态:
Provision,Ready,Run,Scale,Rollback,Update,Destroy,Failed
服务运行过程中,状态也是会有变化的,这样的变化有两种:
1. 一种是不预期的变化(服务状态维持)
如,服务运行因为故障导致一些服务挂掉,或是别的什么原因出现了服务不健康的状态。
而一个好的集群管理控制器应该能够强行维护服务的状态。
在健康的实例数变少时,控制器会把不健康的服务给摘除,而又启动几个新的,强行维护健康的服务实例数。
2. 另外一种是预期的变化(服务状态拟合)
如,我们需要发布新版本,需要伸缩,需要回滚。
这时,集群管理控制器就应该把集群从现有状态迁移到另一个新的状态。
这个过程并不是一蹴而就的,集群控制器需要一步一步地向集群发送若干控制命令。
当需要对集群进行 Scale 的时候,我们需要:
1. 先扩展出几个结点
2. 再部署服务
3. 然后启动服务
4. 再检查服务的健康情况
5. 最后把新扩展出来的服务实例加入服务发现中提供服务
备注
服务状态“拟合”是指在发布新版本、伸缩、回滚时,从一个状态拟合到另一个状态,而且要穷尽所有的可能,玩命地不断地拟合,直到达到目的。
2. 服务的弹性伸缩和故障迁移¶
弹性伸缩包括:
1. 底层资源的伸缩
2. 服务的自动化部署
3. 服务的健康检查
4. 服务发现的注册
5. 服务流量的调度
故障迁移有两种模式:
1. 宠物模式,就是一定要救活,主要是对于 stateful 的服务
2. 奶牛模式,就是不救活了,重新生成一个实例
1. 服务的健康监控(这可能需要一个 APM 的监控)
2. 宠物模式,需要:服务的重新启动和服务的监控报警(如果重试恢复不成功,需要人工介入)
3. 奶牛模式,需要:服务的资源申请,服务的自动化部署,服务发现的注册,以及服务的流量调度
5. 服务编排¶
Choreography VS Orchestration:
1. Orchestration
一个服务像大脑一样来告诉大家应该怎么交互,就跟乐队的指挥一样
参考《Service-oriented Design:A Multi-viewpoint Approach》
2. Choreography
在各自完成专属自己的工作的基础上,互相协作,就跟芭蕾舞团的舞者一样
流量与数据调度¶
备注
流量调度和服务治理区别:一方面,服务治理是内部系统的事,而流量调度可以是内部的,也可以是外部接入层的事。另一方面,服务治理是数据中心的事,而流量调度要做得好,应该是数据中心之外的事,也就是我们常说的边缘计算,是应该在类似于 CDN 上完成的事。所以,流量调度和服务治理是在不同层面上的,不应该混在一起,所以在系统架构上应该把它们分开。
流量调度的主要功能¶
流量调度系统的主要功能:
1. 依据系统运行的情况,自动地进行流量调度,在无需人工干预的情况下,提升整个系统的稳定性
2. 应对爆品等突发事件时,在弹性计算扩缩容的较长时间窗口内或底层资源消耗殆尽的情况下,保护系统平稳运行
本质还是为了提高系统架构的稳定性和高可用性
流量调度系统还可以完成以下几方面的事情:
1. 服务流控
服务发现、服务路由、服务降级、服务熔断、服务保护等
2. 流量控制
负载均衡、流量分配、流量控制、异地灾备(多活)等
3. 流量管理
协议转换、请求校验、数据缓存、数据计算等
流量调度的关键技术¶
一个好的 API Gateway 需要具备以下的关键技术:
1. 高性能
API Gateway 必须使用高性能的技术,所以,也就需要使用高性能的语言
2. 扛流量
要能扛流量,就需要使用集群技术。
集群技术的关键点是在集群内的各个结点中共享数据。
这就需要使用像 Paxos、Raft、Gossip 这样的通讯协议。
因为 Gateway 需要部署在广域网上,所以还需要集群的分组技术。
3. 业务逻辑
API Gateway 需要有简单的业务逻辑
所以,最好是像 AWS 的 Lambda 服务一样,可以让人注入不同语言的简单业务逻辑。
4. 服务化
一个好的 API Gateway 需要能够通过 Admin API 来不停机地管理配置变更
而不是通过一个.conf 文件来人肉地修改配置
分布式事务一致性的问题¶
数据副本是分布式系统解决数据丢失异常的唯一手段:
1. 要想让数据有高可用性,就得写多份数据
2. 写多份会引起数据一致性的问题
3. 数据一致性的问题又会引发性能问题
技术方案:
1. Master-Slave 方案
2. Master-Master 方案
3. 两阶段和三阶段提交方案
4. Paxos 方案
在应用层上解决事务问题,只有“两阶段提交”这样的方式,而在数据层解决事务问题,Paxos 算法则是不二之选。
数据结点的分布式方案¶
备注
真正完整解决数据 Scale 问题的应该还是数据结点自身。只有数据结点自身解决了这个问题,才能做到对上层业务层的透明,业务层可以像操作单机数据库一样来操作分布式数据库,这样才能做到整个分布式服务架构的调度。
对于一些需要文件存储的,则需要分布式文件系统的支持。试想,一个 Kafka 或 ZooKeeper 需要把它们的数据存储到文件系统上。(虽然 Kafka 和 ZooKeeper 是 HA 的,数据会在不同的结点中进行复制,但是我们也应该搬迁数据,这样有利用于新结点的快速启动。)
备注
真正解决数据结点调度的方案应该是底层的数据结点。在它们上面做这个事才是真正有效和优雅的。
PaaS平台的本质¶
软件工程能力主要体现在:
1. 提高服务的 SLA
a. 高可用的系统
b. 自动化的运维
因为故障是常态,如果没有自动化的故障恢复,就很难提高服务的 SLA
2. 能力和资源重用或复用
a. 软件模块的重用(软件抽象的能力)
软件抽象就是找出通用的软件模块或服务
b. 软件运行环境和资源的重用(软件标准化的能力)
软件标准化就是使用统一的软件通讯协议、统一的开发和运维管理方法
3. 过程的自动化
a. 软件生产流水线
CI/CD 的 DevOps 式的自动化
b. 软件运维自动化
软件工程的三个本质:
1. 分布式多层的系统架构
2. 服务化的能力供应
3. 自动化的运维能力
PaaS 跟传统中间件最大的差别:
1. 服务化是 PaaS 的本质
软件模块重用,服务治理,对外提供能力是 PaaS 的本质
2. 分布式是 PaaS 的根本特性
多租户隔离、高可用、服务编排是 PaaS 的基本特性
3. 自动化是 PaaS 的灵魂
自动化部署安装运维,自动化伸缩调度是 PaaS 的关键
一个完整的 PaaS 平台会包括以下几部分:
1. PaaS 调度层 – 主要是 PaaS 的自动化和分布式对于高可用高性能的管理
2. PaaS 能力服务层 – 主要是 PaaS 真正提供给用户的服务和能力
3. PaaS 的流量调度 – 主要是与流量调度相关的东西,包括对高并发的管理
4. PaaS 的运营管理 – 软件资源库、软件接入、认证和开放平台门户
5. PaaS 的运维管理 – 主要是 DevOps 相关的东西
【极客】左耳听风-分布式架构: https://time.geekbang.org/column/intro/48