一篇文章带你构建"分布式架构"知识图谱——极客时间《左耳听风》分布式系列专题总结

在极客时间上我订阅了陈皓开设的《左耳听风》专栏,其中有针对分布式架构的一系列文章,在粗略的学习之后,感触颇多,这里对主要的知识点进行简单的总结,作为后续在这方面学习时的纲要。

一、分布式系统架构的冰与火

使用分布式架构的主要原因
  • 增大系统容量。我们的业务量越来越大,而要能应对越来越大的业务量,一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。
  • 加强系统可用。我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。这样,整个系统不会因为一台机器出故障而导致整体不可用。所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。
单体应用vs分布式优缺点对比

二、分布式系统的难点

异构系统的不标准问题
  • 软件和应用不标准。
  • 通讯协议不标准。
  • 数据格式不标准。
  • 开发和运维的过程和方法不标准。
系统架构中的服务依赖性问题
  • 如果非关键业务被关键业务所依赖,会导致非关键业务变成一个关键业务。
  • 服务依赖链中,出现“木桶短板效应”——整个 SLA 由最差的那个服务所决定。
故障发生的概率更大
  • 分布式系统中,虽然故障的影响面可以被隔离,但是因为机器和服务多,出故障的频率也会多。另一方面,因为管理复杂,而且没人知道整个架构中有什么,所以非常容易犯错误。
    • 出现故障不可怕,故障恢复时间过长才可怕。
    • 出现故障不可怕,故障影响面过大才可怕。
多层架构的运维复杂度更大
  • 通常来说,我们可以把系统分成四层:基础层、平台层、应用层和接入层。
  • 对于这四层,我们需要知道:
    • 任何一层的问题都会导致整体的问题;
    • 没有统一的视图和管理,导致运维被割裂开来,造成更大的复杂度。

三、分布式系统的技术栈

关键的两件事
  • 大流量处理:通过集群技术把大规模并发请求的负载分散到不同的机器上。
    • 目的:提高整体架构的吞吐量,服务更多的并发和流量
  • 关键业务保护:提高后台服务的可用性,把故障隔离起来阻止多米诺骨牌效应(雪崩效应)。如果流量过大,需要对业务降级,以保护关键业务流转。
    • 目的:提高系统的稳定性,让系统的可用性更高。
提高架构的性能
提高架构的稳定性
分布式系统的关键技术
  • 服务治理:服务拆分、服务调用、服务发现,服务依赖,服务的关键度定义……服务治理的最大意义是需要把服务间的依赖关系、服务调用链,以及关键的服务给梳理出来,并对这些服务进行性能和可用性方面的管理。
  • 架构软件管理:服务之间有依赖,而且有兼容性问题,所以,整体服务所形成的架构需要有架构版本管理、整体架构的生命周期管理,以及对服务的编排、聚合、事务处理等服务调度功能。
  • DevOps:分布式系统可以更为快速地更新服务,但是对于服务的测试和部署都会是挑战。所以,还需要 DevOps 的全流程,其中包括环境构建、持续集成、持续部署等。
  • 自动化运维:有了 DevOps 后,我们就可以对服务进行自动伸缩、故障迁移、配置管理、状态管理等一系列的自动化运维技术了。
  • 资源调度管理:应用层的自动化运维需要基础层的调度支持,也就是云计算 IaaS 层的计算、存储、网络等资源调度、隔离和管理。
  • 整体架构监控:如果没有一个好的监控系统,那么自动化运维和资源调度管理只可能成为一个泡影,因为监控系统是你的眼睛。没有眼睛,没有数据,就无法进行高效的运维。所以说,监控是非常重要的部分。这里的监控需要对三层系统(应用层、中间件层、基础层)进行监控。
  • 流量控制:最后是我们的流量控制,负载均衡、服务路由、熔断、降级、限流等和流量相关的调度都会在这里,包括灰度发布之类的功能也在这里。
分布式系统核心

四、分布式系统关键技术:全栈监控

监控系统需要的功能
  • 全栈监控;
  • 关联分析;
  • 跨系统调用的串联;
  • 实时报警和自动处置;
  • 系统性能分析。
多层体系的监控
  • 基础层:监控主机和底层资源。比如:CPU、内存、网络吞吐、硬盘 I/O、硬盘使用等。
  • 中间层:就是中间件层的监控。比如:Nginx、Redis、ActiveMQ、Kafka、MySQL、Tomcat 等。
  • 应用层:监控应用层的使用。比如:HTTP 访问的吞吐量、响应时间、返回码,调用链路分析,性能瓶颈,还包括用户端的监控。
监控的标准化:
  • 日志数据结构化;
  • 监控数据格式标准化;
  • 统一的监控平台;
  • 统一的日志分析。
两大场景
  • “体检”
    • 容量管理:提供一个全局的系统运行时数据的展示,可以让工程师团队知道是否需要增加机器或者其它资源。
    • 性能管理:可以通过查看大盘,找到系统瓶颈,并有针对性地优化系统和相应代码。
  • “急诊”
    • 定位问题:可以快速地暴露并找到问题的发生点,帮助技术人员诊断问题。
    • 性能分析:当出现非预期的流量提升时,可以快速地找到系统的瓶颈,并可以帮助开发人员深入代码。
监控系统实现
  • 服务调用链跟踪
    • 从对外的 API 开始,然后将后台的实际服务给关联起来,再将这个服务的依赖服务给关联起来,直到最后一个服务(如 MySQL 或 Redis),这样就可以把整个系统的服务全部都串连起来了。这个事情的最佳实践是 Google Dapper 系统,其对应于开源的实现是 Zipkin。对于 Java 类的服务,我们可以使用字节码技术进行字节码注入,做到代码无侵入式。
  • 服务调用时长分布
    • 使用 Zipkin, 可以看到一个服务调用链上的时间分布,这样有助于我们知道最耗时的服务是什么。
  • 服务的 TOP N 视图
    • 所谓 TOP N 视图就是一个系统请求的排名情况。一般来说,这个排名会有三种排名的方法:1.按调用量排名,2.按请求最耗时排名,3.按热点排名(一个时间段内的请求次数的响应时间和)。
  • 数据库操作关联
    • 对于 Java 应用,我们可以很方便地通过 JavaAgent 字节码注入技术拿到 JDBC 执行数据库操作的执行时间。对此,我们可以和相关的请求对应起来。
  • 服务资源跟踪
    • 我们的服务可能运行在物理机上,也可能运行在虚拟机里,还可能运行在一个 Docker 的容器里,Docker 容器又运行在物理机或是虚拟机上。我们需要把服务运行的机器节点上的数据(如 CPU、MEM、I/O、DISK、NETWORK)关联起来。

五、分布式系统关键技术:服务调度

服务治理上的一些关键点
  • 服务关键程度
  • 服务依赖关系
  • 服务发现
  • 整个架构的版本管理
  • 服务应用生命周期全管理
服务关键程度和服务的依赖关系
  • 微服务是服务依赖最优解的上限,而服务依赖的下限是千万不要有依赖环。
  • 解决服务依赖环的方案一般是,依赖倒置的设计模式。在分布式架构上,你可以使用一个第三方的服务来解决这个事。比如,通过订阅或发布消息到一个消息中间件,或是把其中的依赖关系抽到一个第三方的服务中,然后由这个第三方的服务来调用这些原本循环依赖的服务。
  • 服务的依赖关系是可以通过技术的手段来梳理的,比如Zipkin
服务状态和生命周期的管理
  • 需要有一个服务注册中心,来知道这么几个事
    • 整个架构中有多少种服务?
    • 这些服务的版本是什么样的?
    • 每个服务的实例数有多少个,它们的状态是什么样的?
    • 每个服务的状态是什么样的?是在部署中,运行中,故障中,升级中,还是在回滚中,伸缩中,或者是在下线中……
  • 服务的生命周期
    • Provision,代表在供应一个新的服务;
    • Ready,表示启动成功了;
    • Run,表示通过了服务健康检查;
    • Update,表示在升级中;
    • Rollback,表示在回滚中。
    • Scale,表示正在伸缩中(可以有 Scale-in 和 Scale-out 两种)。
    • Destroy,表示在销毁中。
    • Failed,表示失败状态。
整个架构的版本管理
  • 除了各个项目的版本管理之外,还需要在上面再盖一层版本管理,如果我们要回滚一个服务的版本,就可以把与之有版本依赖的服务也一起回滚掉。
  • 要做到这个事,你需要一个架构的 manifest,一个服务清单,这个服务清单定义了所有服务的版本运行环境,其中包括但不限于:
    • 服务的软件版本;
    • 服务的运行环境——环境变量、CPU、内存、可以运行的结点、文件系统等;
    • 服务运行的最大最小实例数。
资源 / 服务调度
  • 服务状态的维持和拟合。
  • 服务的弹性伸缩和故障迁移。
  • 作业和应用调度。
  • 作业工作流编排。
  • 服务编排。
服务状态的维持和拟合
  • 服务运行过程中,状态也是会有变化的,这样的变化有两种
    • 一种是不预期的变化。比如,服务运行因为故障导致一些服务挂掉,或是别的什么原因出现了服务不健康的状态。而一个好的集群管理控制器应该能够强行维护服务的状态。在健康的实例数变少时,控制器会把不健康的服务给摘除,而又启动几个新的,强行维护健康的服务实例数。
    • 另外一种是预期的变化。比如,我们需要发布新版本,需要伸缩,需要回滚。这时,集群管理控制器就应该把集群从现有状态迁移到另一个新的状态。这个过程并不是一蹴而就的,集群控制器需要一步一步地向集群发送若干控制命令。这个过程叫“拟合”——从一个状态拟合到另一个状态,而且要穷尽所有的可能,玩命地不断地拟合,直到达到目的。
服务的弹性伸缩和故障迁移
  • 服务伸缩
    • 底层资源的伸缩;
    • 服务的自动化部署;
    • 服务的健康检查;
    • 服务发现的注册;
    • 服务流量的调度。
  • 故障迁移
    • 宠物模式:就是一定要救活,主要是对于 stateful 的服务。
      • 需要:服务的重新启动和服务的监控报警(如果重试恢复不成功,需要人工介入)
    • 奶牛模式:就是不救活了,重新生成一个实例。
      • 需要:服务的资源申请,服务的自动化部署,服务发现的注册,以及服务的流量调度。
服务工作流和编排
  • 传统的 SOA 通过 ESB(Choreography机制)
  • 微服务中使用 API Gateway 或一个简单的消息队列来做相应的编排工作(Orchestration机制)

六、分布式系统关键技术:流量与数据调度

流量调度的主要功能
  • 应具备的功能
    • 依据系统运行的情况,自动地进行流量调度,在无需人工干预的情况下,提升整个系统的稳定性;
    • 让系统应对爆品等突发事件时,在弹性计算扩缩容的较长时间窗口内或底层资源消耗殆尽的情况下,保护系统平稳运行。
  • 扩展能力
    • 服务流控:服务发现、服务路由、服务降级、服务熔断、服务保护等。
    • 流量控制:负载均衡、流量分配、流量控制、异地灾备(多活)等。
    • 流量管理:协议转换、请求校验、数据缓存、数据计算等。
流量调度的关键技术
  • 高性能:API Gateway 必须使用高性能的技术,所以,也就需要使用高性能的语言。
  • 扛流量:要能扛流量,就需要使用集群技术。集群技术的关键点是在集群内的各个结点中共享数据。这就需要使用像 Paxos、Raft、Gossip 这样的通讯协议。因为 Gateway 需要部署在广域网上,所以还需要集群的分组技术。
  • 业务逻辑:API Gateway 需要有简单的业务逻辑,所以,最好是像 AWS 的 Lambda 服务一样,可以让人注入不同语言的简单业务逻辑。
  • 服务化:一个好的 API Gateway 需要能够通过 Admin API 来不停机地管理配置变更的,而不是通过一个.conf 文件来人肉地修改配置。
状态数据调度
  • 一般来说,我们会通过“转移问题”的方法来让服务变成“无状态的服务”。也就是说,会把这些有状态的东西存储到第三方服务上,比如 Redis、MySQL、ZooKeeper,或是 NFS、Ceph 的文件系统中。
分布式事务一致性的问题
  • 要解决数据不丢的问题,只能通过数据冗余的方法,就算是数据分区,每个区也需要进行数据冗余处理。这就是数据副本。当出现某个节点的数据丢失时,可以从副本读到。数据副本是分布式系统解决数据丢失异常的唯一手段。简单来说:
    • 要想让数据有高可用性,就得写多份数据。
    • 写多份的问题会导致数据一致性的问题。
    • 数据一致性的问题又会引发性能问题。
  • 技术方案:
    • Master-Slave 方案
    • Master-Master 方案
    • 两阶段和三阶段提交方案
    • Paxos 方案

七、洞悉PaaS平台的本质

一家商业公司的软件工程能力主要体现在三个地方
  • 提高服务的 SLA:能提供多少个 9 的系统可用性
    • 高可用的系统
    • 自动化的运维
  • 能力和资源重用或复用
    • 软件模块的重用
    • 软件运行环境和资源的重用
  • 过程的自动化
    • 软件生产流水线
      • 软件运维自动化
PaaS 平台的总体架构
  • 调度层 – 主要是 PaaS 的自动化和分布式对于高可用高性能的管理。
  • 能力服务层 – 主要是 PaaS 真正提供给用户的服务和能力。
  • 流量调度 – 主要是与流量调度相关的东西,包括对高并发的管理。
  • 运营管理 – 软件资源库、软件接入、认证和开放平台门户。
  • 运维管理 – 主要是 DevOps 相关的东西。
PaaS 平台的生产和运维

总结

构建分布式系统,我们面临的主要问题:
  • 分布式系统的硬件故障发生率更高,故障发生是常态,需要尽可能地将运维流程自动化。
  • 需要良好地设计服务,避免某服务的单点故障对依赖它的其他服务造成大面积影响。
  • 为了容量的可伸缩性,服务的拆分、自治和无状态变得更加重要,可能需要对老的软件逻辑做大的修改。
  • 老的服务可能是异构的,此时需要让它们使用标准的协议,以便可以被调度、编排,且互相之间可以通信。
  • 服务软件故障的处理也变得复杂,需要优化的流程,以加快故障的恢复。
  • 为了管理各个服务的容量,让分布式系统发挥出最佳性能,需要有流量调度技术。
  • 分布式存储会让事务处理变得复杂;在事务遇到故障无法被自动恢复的情况下,手动恢复流程也会变得复杂。
  • 测试和查错的复杂度增大。
  • 系统的吞吐量会变大,但响应时间会变长。
解决方案:
  • 需要有完善的监控系统,以便对服务运行状态有全面的了解。
  • 设计服务时要分析其依赖链;当非关键服务故障时,其他服务要自动降级功能,避免调用该服务。
  • 重构老的软件,使其能被服务化;可以参考 SOA 和微服务的设计方式,目标是微服务化;使用 Docker 和 Kubernetes 来调度服务。
  • 为老的服务编写接口逻辑来使用标准协议,或在必要时重构老的服务以使得它们有这些功能。
  • 自动构建服务的依赖地图,并引入好的处理流程,让团队能以最快速度定位和恢复故障,详见《故障处理最佳实践:应对故障》一文。
  • 使用一个 API Gateway,它具备服务流向控制、流量控制和管理的功能。
  • 事务处理建议在存储层实现;根据业务需求,或者降级使用更简单、吞吐量更大的最终一致性方案,或者通过二阶段提交、Paxos、Raft、NWR 等方案之一,使用吞吐量小的强一致性方案。
  • 通过更真实地模拟生产环境,乃至在生产环境中做灰度发布,从而增加测试强度;同时做充分的单元测试和集成测试以发现和消除缺陷;最后,在服务故障发生时,相关的多个团队同时上线自查服务状态,以最快地定位故障原因。
  • 通过异步调用来减少对短响应时间的依赖;对关键服务提供专属硬件资源,并优化软件逻辑以缩短响应时间。
发布了35 篇原创文章 · 获赞 104 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/wk52525/article/details/91992556