【技术·真相】分布式系统之旅:解锁高性能与弹性的钥匙

170 阅读11分钟

行动永远不会晚。想做一件事,最好的时间是十年前,其次是现在。

郑重说明:本文适合对游戏开发感兴趣的初级及中级开发和学习者,本人力图将技术用简单的语言表达清楚。鉴于水平有限,能力一般,文章如有错漏之处,还望批评指正,谢谢。


描述一件事情,通常有三个思维角度:

  • what(是什么);
  • why(为什么);
  • How(怎么做)。

我们就尝试从这几个角度来谈一谈分布式系统。


一、why(为什么)

分布式系统是相对于单体架构来说的。

单体架构是一种传统的软件架构模式,它将一个应用程序作为一个整体单元进行开发、部署和维护。在单体架构中,应用程序的各个功能模块都运行在同一个进程中,共享同一个数据库和资源。

image.png

这种架构模式通常适用于小型项目和简单应用,其中的模块之间通过函数调用或直接方法调用来实现交互。

一些项目的初期,如早期的淘宝,由于时间紧,需要快速产出验证产品,也常用单体应用来搭建架构,等后续用户量上来之后再变更架构。

现在,随着业务的复杂度越来越高,单体架构已经不能满足需求了。

分布式系统应运而生。

使用分布式系统主要有几个方面的原因。

  • 增大系统容量。我们的业务量越来越大,而要能应对越来越大的业务量,一台机器的性能已经无法满足了,我们需要多台机器才能应对大规模的应用场景。所以,我们需要垂直或是水平拆分业务系统,让其变成一个分布式的架构。
  • 加强系统可用。我们的业务越来越关键,需要提高整个系统架构的可用性,这就意味着架构中不能存在单点故障。这样,整个系统不会因为一台机器出故障而导致整体不可用。所以,需要通过分布式架构来冗余系统以消除单点故障,从而提高系统的可用性。
  • 可扩展性:分布式系统可以通过添加更多的节点来扩展其处理能力,而单体结构则很难实现这一点。
  • 可维护性。按模块来替换、更新分布式系统中的业务节点。增量化开发、更新、维护,符合快速迭代的思维方式及事物进化的规律。而且,不同部分可以采用不同的技术栈。

不止在软件开发领域,分布式系统得到广泛应用;在很多其他学科中,也有类似的用分布式系统来解决问题的思想。

例如,在生态学中,生态系统通常是一个分布式系统,由许多不同的物种和环境因素组成,是没有一个中心控制的。这些物种和环境因素相互作用,形成一个复杂的生态系统,从而实现了资源的分配、物种的生长和生态系统的稳定性;在交通运输领域,交通网络也是一个分布式系统,由许多不同的路段和交通工具组成,通过协调和管理这些不同的组成部分,可以实现高效的交通运输。

分布式的思想还有:

  • 多个廉价的节点组成性能强劲的集群来解决问题,即云计算
  • 使用功能简单的GPU代替CPU做大量的并行计算
  • 社会经济生活中,各行各业及产业链上下游的分工
  • 比特币的分布式机制
  • SpaceX的巨型火箭发动机由多个普通发动机组合而成
  • 电动汽车的电池组由功能简单的电池并联而成

二、What(是什么):架构发展历史

分布式系统大致经历了以下几个发展时期:

  1. 单体架构
  2. 分层架构:表示层、业务逻辑层、数据访问层,各层之间通过接口进行通信。这种架构可以提高系统的可维护性和可扩展性,但仍然存在单点故障和性能瓶颈等问题。
  3. SOA架构。这种架构可以提高系统的可扩展性和灵活性,但需要考虑服务的版本控制、服务的拆分和合并等问题。
  4. 微服务架构

image.png


三、How(怎么做):实现一个基本的分布式

3.1 分布式系统的基本组成


  1. 任务分解:分布式系统具体怎么拆分?

既然是分布式协作的系统,自然要区分各个节点的职责,也就是业务怎么划分的问题。

有一些不同的拆分维度:

  • 根据功能划分:如一个电商系统拆分为商品、订单、支付、秒杀等。
  • 根据系统重要性,将主要的功能和非主要功能拆分开,防止非主要功能异常时影响主要功能。

  1. 服务之间怎么通信?

实现一个分布式系统也要节点之间网络通信方式的问题。

  • 原生socket通信,基于tcp或者udp。Socket编程需要程序员自己处理数据的格式和传输,因此开发复杂度相对较高。有较高的灵活性;跨语言和平台;但是实现和调试复杂。

  • 基于http协议的web服务,常见的 Web 服务包括 RESTful API、SOAP 等。跨平台跨语言;通信效率较低,需要高版本的http来实现推送等功能。

  • 远程过程调用(Remote Procedure Call,RPC)。RPC 通常基于传输层协议(如TCP或UDP或http)实现,使用类似于本地函数调用的方式进行通信。可以看成对socket通信或http通信的封装。RPC 通常采用点对点的通信方式,扩展性不好,分布式系统中扩容时需要结合服务发现;同步阻塞方式,需要额外控制超时、重试等机制。

  • 消息队列。消息传递是一种异步通信机制,借助第三方的消息队列来解耦。消息传递可以基于点对点或广播通信方式实现,常见的消息传递中间件包括 RabbitMQ、Kafka 等。可靠性较高,因为消息传递通常具有重试、超时、事务等机制,可以保证数据传输的可靠性;可扩展性较好,因为消息传递可以采用广播等方式进行通信,增加节点时不需要进行修改和配置;适用于异步通信场景,可以实现解耦和高并发;但消息队列比较重量级,使用和调试起来比较复杂,消费消息时自行处理消息的重试、幂等性等问题;通信效率降低,需要额外的序列化到消息队列中。

在实际应用中,通常会选择一种或多种通信机制进行组合使用,以实现分布式系统中的数据交换和进程通信。


  1. 通信节点之间怎么找到对方?

选择了节点之间通信的方式,我们还得知道怎么找到别的节点。

  • 如果采用同步点对点的通信,如socket通信、http协议、RPC 通信,往往采用服务注册和发现的方式。分布式系统中的节点启动时向第三方注册自己,并监听感兴趣的节点。

  • 如果采用异步通信如消息队列,所有消息并不直接发往不同的节点,而是经由第三方消息队列来存储和消费,不需要服务发现机制。


  1. 业务流量怎么在分布式系统中分配?

这里的流量分配是指不同的任务如何分配到不同的节点。包括:分配到哪种类型的节点? 一个任务分配到哪一台具体的机器?

业务流量一般分为两种,外部流量和内部流量。

外部流量:就是从用户流入分布式系统的上行请求,对接的往往是负载均衡组件,知名的有 nginx、Haproxy、各种云厂商的 LB 服务。

内部流量:一个业务,比如用户下单买东西,往往不会只经过一个分布式节点,往往是由多个节点协作完成的。在实现时,一个消息在分布式系统中是如何流转的?怎么去某种类型的服务,去具体哪个机器?

简单的可以使用一些路由算法来做到内部的负载均衡:轮询算法(Round Robin)、随机算法、Hash算法、一致性hash算法等。

如果分布式节点上有状态,就更复杂一些,需要专门的路由管理模块来存储某些状态对应的节点路由信息以便查询。


  1. 分布式系统的协作

如果一个逻辑是排他性的,需要协调执行者: 例如对于一种类型的多个节点,某逻辑只能在其中的一个节点上执行,那就要利用分布式锁来获取执行权。

如果分区后的数据在多个节点都有,还要协调保证数据空间上的一致性,这就需要数据同步。基于日志的同步技术通常用于分布式数据库、分布式存储系统等应用中;还有一些知名的数据同步算法如 raft算法、paxos 算法等。

如果一个业务可能修改多份数据,一个典型的例子就是银行转账,可能修改两个人的账户余额,这样不同部分的数据有原子性,要协调保证数据时间上的一致性,这往往需要分布式事务机制来保证。


3.2 易用性的问题

考虑前面一些问题,实现一个基本的分布式系统之后,我们还要改进这个系统的易用性,如:

  1. 多个服务间往往有依赖关系,哪个先启动哪个后启动?

  2. 这么多分布式的节点,管理配置文件在运维上是一件很困难的事情,我们可能要考虑集中式的配置中心来做智能管理。

  3. 一个完整的业务涉及多个节点,人工去这么多节点机器上查询日志是不现实的。日志收集查看、业务日志追踪的需求也随之而来。

  4. 分布式系统作为一个协作的系统,出了问题要能及时发现并排查,业务指标监控也要做起来。有了系统健康监控,就能尽快发现问题,调试。

  5. 部署和迁移:考虑分布式系统中哪个节点部署在什么配置的机器上,是一件繁琐的事情,而且随着业务流量的变化,可能要不停的增加或缩减资源,此外,分布式的机器节点也可能有故障,需要做迁移。如果有统一的智能硬件资源分配、调度系统,可以解决很多问题。


3.3 分布式带来的问题

分布式系统为我们带来了很多好处,也存在自己的问题:

  • 节点多,部署复杂,管理难度大;

  • 流量被分配到多个节点之后,同时能处理的能力增加,吞吐量增大,但是性能相比单机下降了:很明显,一个业务经过多个节点才能处理完毕,中间有调度损失、网络延迟等。

  • 业务经过的链条加长,debug 和 定位问题的难度加大,出问题容易引起连锁反应,问题源头不易发现。

如何解决这些问题?

比如性能问题,我们要尽可能来解决该问题:

  • 用合适的单服模型来提高单个节点的性能

  • 使用缓存

  • 性能问题可能不是长时间的,而是在高峰期比较难扛过去,此时就需要削峰填谷,如引入消息队列

有时候问题无法得到根本解决,如果资源有限,也要留一定的安全边际:

  • 特定拆分方法,隔离重要性不同的服务
  • 限流,超过承载能力的请求直接丢弃
  • 降级,如果个别业务已经出问题,就关闭对应的业务,使得其他业务不受影响
  • 做必要的冗余,故障时可以做迁移。但迁移对有状态服务有挑战。

介绍了这么多。我们来看下另外一个问题:什么时候不适合用分布式系统?更好的选择是单机系统或者集中式系统?

  • 数据量较小,要求较低的场合(阿里早期的架构,后来才逐渐发展)
  • 单个比较复杂,复杂的事务处理

四、未来发展趋势

分布式系统的技术也在不停的发展,一些未来的发展趋势有:

  • 云原生架构
  • Serverless架构

小结

通过本文,我们介绍了分布式系统的:

  • why、what、how(基本实现)
  • 发展历史
  • 未来趋势

作者:我是码财小子,会点编程代码,懂些投资理财;期待你的关注,不要错过我后续的文章更新。