临时 #### 分布式系统优缺点 ================ 使用分布式系统主要有两方面原因:: 1. 增大系统容量 我们的业务量越来越大,而要能应对越来越大的业务量, 一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。 所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。 2. 加强系统可用 我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。 这样,整个系统不会因为一台机器出故障而导致整体不可用。 所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。 分布式系统还有一些优势,比如:: 1. 因为模块化,所以系统模块重用度更高 2. 因为软件服务模块被拆分,开发和发布速度可以并行而变得更快 3. 系统扩展性更高 4. 团队协作流程也会得到改善 5. …… .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/compare-monolithic1.png 单体应用和分布式架构的优缺点 分布式架构的问题:: 1. 架构设计变得复杂(尤其是其中的分布式事务) 2. 部署单个服务会比较快,但是如果一次部署需要多个服务,流程会变得复杂 3. 系统的吞吐量会变大,但是响应时间会变长 4. 运维复杂度会因为服务变多而变得很复杂 5. 架构复杂导致学习曲线变大 6. 测试和查错的复杂度增大 7. 技术多元化,这会带来维护和运维的复杂度 8. 管理分布式系统中的服务和调度变得困难和复杂 .. note:: 分布式系统架构的难点在于系统设计,以及管理和运维。 分布式系统的发展 ================ .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/compare-soa.webp SOA 架构的演化图 分布式系统技术栈 ================ 构建分布式系统的目的是增加系统容量,提高系统的可用性,转换成技术方面,也就是完成下面两件事:: 1. 大流量处理 通过集群技术把大规模并发请求的负载分散到不同的机器上。 2. 关键业务保护 提高后台服务的可用性,把故障隔离起来阻止多米诺骨牌效应(雪崩效应)。 如果流量过大,需要对业务降级,以保护关键业务流转。 即: 1. 提高整体架构的吞吐量,服务更多的并发和流量 2. 为了提高系统的稳定性,让系统的可用性更高 提高架构的性能 -------------- .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/tune-tech-method-performance.webp 提高系统性能的常用技术 提高架构的稳定性 ---------------- .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/tune-tech-method-stability.webp 提高系统系统稳定性的一些常用技术 分布式系统的关键技术 -------------------- :: 1. 服务治理。 服务拆分、服务调用、服务发现、服务依赖、服务的关键度定义…… 服务治理的最大意义是需要把服务间的依赖关系、服务调用链,以及关键的服务给梳理出来, 并对这些服务进行性能和可用性方面的管理。 2. 架构软件管理。 服务之间有依赖,而且有兼容性问题, 所以,整体服务所形成的架构需要有架构版本管理、整体架构的生命周期管理, 以及对服务的编排、聚合、事务处理等服务调度功能。 3. DevOps。 分布式系统可以更为快速地更新服务,但是对于服务的测试和部署都会是挑战。 所以,还需要 DevOps 的全流程,其中包括环境构建、持续集成、持续部署等。 4. 自动化运维。 有 DevOps 后,就可以对服务进行自动伸缩、故障迁移、配置管理、状态管理等一系列的自动化运维技术了。 5. 资源调度管理。 应用层的自动化运维需要基础层的调度支持, 也就是云计算 IaaS 层的计算、存储、网络等资源调度、隔离和管理。 6. 整体架构监控。 如果没有一个好的监控系统,那么自动化运维和资源调度管理只可能成为一个泡影, 因为监控系统是你的眼睛。没有眼睛,没有数据,就无法进行高效的运维。 所以说,监控是非常重要的部分。 这里的监控需要对三层系统(应用层、中间件层、基础层)进行监控。 7. 流量控制。 包括负载均衡、服务路由、熔断、降级、限流等和流量相关的调度 还包括灰度发布之类的功能也在这里。 分布式系统的"纲" ---------------- 分布式系统有五个关键技术:: 1. 全栈系统监控 2. 服务 / 资源调度 3. 流量调度 4. 状态 / 数据调度 5. 开发和运维的自动化 开发和运维的自动化,是需要把前四项都做到了,才有可能实现的 .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/keytech0.png 构建分布式系统最最核心的东西 关键技术: 全栈监控 ================== .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/keytech1-monitor1.png 全栈监控 监控的标准化:: 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 出现慢查询,就不能在应用层上做弹性伸缩,只能做流量限制,或降级操作 .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/keytech1-monitor2.webp 最重要的事就是把监控系统做好。在把数据收集好的同时,更重要的是把数据关联好。这样,我们才可能很快地定位故障,进而才能进行自动化调度。 关键技术: 服务调度 ================== .. note:: 服务治理可能混合了流量调度等其它内容。 服务治理 -------- 服务治理上的关键技术:: 1. 服务关键程度 2. 服务依赖关系 3. 服务发现 4. 整个架构的版本管理 5. 服务应用生命周期全管理 1. 服务关键程度 ^^^^^^^^^^^^^^^ :: 这不是使用技术可以完成的, 它需要细致地管理对业务的理解,才能定义出架构中各个服务的重要程度。 2. 服务依赖关系 ^^^^^^^^^^^^^^^ 依赖关系就像“铁锁连环”一样,一个服务的问题很容易出现一条链上的问题。 因此:: a. 传统的 SOA 希望通过 ESB 来解决服务间的依赖关系 b. 微服务希望服务间是没有依赖的,而让上层或是前端业务来整合这些个后台服务 真正做到服务无依赖,我认为还是比较有困难的:: 我们只能是降低服务依赖的深度和广度,从而让管理更为简单和简洁 .. note:: 微服务是服务依赖最优解的上限,而服务依赖的下限是千万不要有依赖环。 解决服务依赖环的方案:: 依赖倒置的设计模式。 在分布式架构上,你可以使用一个第三方的服务来解决这个事。 比如: 1. 通过订阅或发布消息到一个消息中间件, 2. 把其中的依赖关系抽到一个第三方的服务中,由这个三方服务来调用这些原本循环依赖的服务 服务的依赖关系发现:: 全链路追踪 .. note:: 梳理完服务的重要程度和服务依赖关系之后,我们就相当于知道了整个架构的全局。就好像我们得到了一张城市地图,在这张地图上可以看到城市的关键设施,以及城市的主干道。再加上相关的监控,我们就可以看到城市各条道路上的工作和拥堵情况。这对于我们整个分布式架构是非常非常关键的。在解决一些高并发或是架构问题的时候,有这么一张地图非常方便。 3. 服务发现 ^^^^^^^^^^^ “架构城市”是非常动态的,有的服务会新加进来,有的会离开,有的会增加更多的实例,有的会减少,有的服务在维护过程中(发布、伸缩等),所以我们需要有一个服务注册中心,来知道这么几个事:: 1. 整个架构中有多少种服务 2. 这些服务的版本是什么样的 3. 每个服务的实例数有多少个,它们的状态是什么样的 4. 每个服务的状态是什么样的 部署中,运行中,故障中,升级中,回滚中,伸缩中,下线中 4. 整个架构的版本管理 ^^^^^^^^^^^^^^^^^^^^^ .. note:: 除了各个项目的版本管理之外,还需要在上面再盖一层版本管理。如: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,表示失败状态 资源 / 服务调度 --------------- .. note:: 服务和资源的调度有点像操作系统。操作系统一方面把用户进程在硬件资源上进行调度,另一方面提供进程间的通信方式,可以让不同的进程在一起协同工作。 一些关键技术:: 1. 服务状态的维持和拟合 2. 服务的弹性伸缩和故障迁移 3. 作业和应用调度 4. 作业工作流编排 5. 服务编排 1. 服务状态的维持和拟合 ^^^^^^^^^^^^^^^^^^^^^^^ 所谓服务状态不是服务中的数据状态,而是服务的运行状态:: 换句话说就是服务的 Status,而不是 State 也就是上述服务运行时生命周期中的状态: Provision,Ready,Run,Scale,Rollback,Update,Destroy,Failed 服务运行过程中,状态也是会有变化的,这样的变化有两种:: 1. 一种是不预期的变化(服务状态维持) 如,服务运行因为故障导致一些服务挂掉,或是别的什么原因出现了服务不健康的状态。 而一个好的集群管理控制器应该能够强行维护服务的状态。 在健康的实例数变少时,控制器会把不健康的服务给摘除,而又启动几个新的,强行维护健康的服务实例数。 2. 另外一种是预期的变化(服务状态拟合) 如,我们需要发布新版本,需要伸缩,需要回滚。 这时,集群管理控制器就应该把集群从现有状态迁移到另一个新的状态。 这个过程并不是一蹴而就的,集群控制器需要一步一步地向集群发送若干控制命令。 当需要对集群进行 Scale 的时候,我们需要:: 1. 先扩展出几个结点 2. 再部署服务 3. 然后启动服务 4. 再检查服务的健康情况 5. 最后把新扩展出来的服务实例加入服务发现中提供服务 .. note:: 服务状态“拟合”是指在发布新版本、伸缩、回滚时,从一个状态拟合到另一个状态,而且要穷尽所有的可能,玩命地不断地拟合,直到达到目的。 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 在各自完成专属自己的工作的基础上,互相协作,就跟芭蕾舞团的舞者一样 流量与数据调度 ============== .. note:: 流量调度和服务治理区别:一方面,服务治理是内部系统的事,而流量调度可以是内部的,也可以是外部接入层的事。另一方面,服务治理是数据中心的事,而流量调度要做得好,应该是数据中心之外的事,也就是我们常说的边缘计算,是应该在类似于 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 算法则是不二之选。 数据结点的分布式方案 -------------------- .. note:: 真正完整解决数据 Scale 问题的应该还是数据结点自身。只有数据结点自身解决了这个问题,才能做到对上层业务层的透明,业务层可以像操作单机数据库一样来操作分布式数据库,这样才能做到整个分布式服务架构的调度。 对于一些需要文件存储的,则需要分布式文件系统的支持。试想,一个 Kafka 或 ZooKeeper 需要把它们的数据存储到文件系统上。(虽然 Kafka 和 ZooKeeper 是 HA 的,数据会在不同的结点中进行复制,但是我们也应该搬迁数据,这样有利用于新结点的快速启动。) .. note:: 真正解决数据结点调度的方案应该是底层的数据结点。在它们上面做这个事才是真正有效和优雅的。 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 相关的东西 .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/distributes/zuoertingfengs/architecture1.webp PaaS 平台的总体架构 * 【极客】左耳听风-分布式架构: https://time.geekbang.org/column/intro/48