分布式架构的发展历史与背景
理解分布式架构
软件架构的发展历史
参考:https://blog.csdn.net/fdxcg_x/article/details/115708922

单体架构
优点
- 小项目开发快 成本低
- 架构简单
- 易于测试
- 易于部署
缺点
- 大项目模块耦合严重,不易开发,维护,沟通成本高
- 新增业务困难
- 核心业务与边缘业务混合在一块,出现问题互相影响
垂直架构

根据业务把项目垂直切割成多个项目,因此这种架构称之为垂直架构。此时用于加速前端页面开发的**Web框架(MVC)**是关键
优点
1、项目架构简单、前期开发成本低,周期短,适合小型项目
2、通过垂直拆分,原来的项目不至于无线扩大
3、不同项目可以采用不同的技术
4、可针对核心业务服务增加集群节点
1、系统拆分实现了流量切割,降低单体时的流量集中
2、业务拆分,可以针对不同模块优化部署迭代,互不影响
3、方便水平扩展、负载均衡、容错率高
缺点
1、服务之间的调用方式、接口协议不统一
2、服务监控不到位
3、服务ip和端口发生变更时,不好维护
4、搭建集群之后,实现负载均衡比较复杂。比如:内网负载,在迁移得时候会影响调用方的路由,导致线上故障
分布式架构(SOA(Service Oriented Architecture))
“面向服务的架构,是一个架构模型或者一种设计方法,而并不是服务解决方案。其中包含多个服务, 服务之间通过相互依赖或者通过通信机制,来完成相互通信的,最终提供一系列的功能。一个服务通常以独立的形式存在与操作系统进程中。各个服务之间通过网络调用 。
跟 SOA 相提并论的还有一个 ESB(企业服务总线),简单来说ESB就是一根管道,用来连接各个服务节点。为了集成不同系统,不同协议的服务,ESB 可以简单理解为:它做了消息的转化解释和路由工作,让不同的服务互联互通;

SOA 所解决的核心问题
- 系统集成:站在系统的角度,解决企业系统间的通信问题,把原先散乱、无规划的系统间的网状结构,梳理成规整、可治理的系统间星形结构,这一步往往需要引入 一些产品,比如 ESB、以及技术规范、服务管理规范;这一步解决的核心问题是【有序】
- 系统的服务化:站在功能的角度,把业务逻辑抽象成可复用、可组装的服务,通过服务的编排实现业务的快速再生。目的:把原先固有的业务功能转变为通用的业务服务,实现业务逻辑的快速复用;这一步解决的核心问题是【复用】
- 业务的服务化:站在企业的角度,把企业职能抽象成可复用、可组装的服务;把原先职能化的企业架构转变为服务化的企业架构,进一步提升企业的对外服务能力;前面两步都是从技术层面来解决系统调用、系统功能复用的问题。第三步,则是以业务驱动把一个 业务单元封装成一项服务。这一步解决的核心问题是 【高效】
优点
1、服务以接口为粒度,对调用者屏蔽接口底层细节
2、业务分层后架构更加清晰,业务模块化后职责单一,便于业务功能转化实现快速复用
3、服务间统一的通信协议
缺点
1、服务拆分粒度把控复杂,容易造成服务模块边界不清晰
2、服务接口剧增,调用链路长,容易超时等
微服务架构

SOA架构的一种拓展和变种,强调去中心化、服务拆分粒度更小。
优点
1、能够被一个团队单独进行敏捷开发(开发、测试、部署、运维)实现DevOps开发运维一体化
2、各服务功能单一、粒度小
3、服务间的依赖性弱、独立性强、各个服务可以独立部署
缺点
1、难以管理、服务边界问题
2、调用链路长、链路跟踪、问题定位难度较大
3、分布式事务问题
分布式架构带来的问题
问题
1、分布式事务
2、分布式任务
3、服务依赖关系复杂,调用链路长,需考虑服务降级、熔断、限流等
4、部署运维成本增加
5、不允许服务有状态
无状态服务是指对单次请求的处理,不依赖其他请求,也就是说,处理一次请求所需的全部信息,要么都包含在这个请求里,要么可以从外部获取到(比如说数据库),服务器本身不存储任何信息。
6、分布式会话
此仅针对应用层服务,不能将Session 存储在一个服务器上。
改造面临的风险
1、新功能与旧bug需要2套代码同时维护
2、业务的拆分、完整性问题
3、团队协作方式的转变
4、开发人员的技能提升
5、系统交付部署方式的改变
些问题解决涉及业务部门及整个技术部门(开发、测试、运维)协商与工作标准的制定。业务相关问题暂不做讨论,技术架构上应该要清楚自己的职责是,如何通过技术手段把业务波动降至最低、开发成本最低、实施风险最低?
如何选型分布式架构
RPC远程调用技术
| 协议 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| RMI | JAVA 远程方法调用、使用原生二进制方式进行序列化 | 简单易用、SDK支持,提高开发效率 | 不支持跨语言,不支持负载均衡 |
| Web Service | 比较早系统调用解决方案 ,跨语言, 其基于WSDL 生成 SOAP 进行消息的传递。 | SDK支持、跨语言 | 实现较重,发布繁琐 |
| Http | 采用http +json 实现 | 简单、轻量、跨语言 | 不支持SDK |
| Hessian | 采用http +hessian 序列化实现 | 简单,轻量、sdk支持 | 不能跨语言 |
RPC调用需要解决的问题
微服务调用中中,如何实现A->B的负载均衡、服务发现、健康监测、容错的功能呢?
负载均衡:这么多个机器调用哪一台?
服务发现:样发现新的服务地址呢?
健康检测:服务关宕机或恢复后怎么办?
容错:如果调用其中一台调用出错了怎么办?
3种代理架构比较
参考文档:https://blog.csdn.net/adparking/article/details/114577835
1、集中式负载均衡(4层代理(F5硬件代理)+7层代理(Nginx软件代理))

2、嵌入应用内部的去中心化架构(服务发现与注册 consul nacos ribbon)

3、基于独立代理进程的Service Mesh(服务网格)架构

| 模式 | 优点 | 缺点 | 适应场景 | 案例 |
|---|---|---|---|---|
| 集中式负载架构 | 简单集中式治理与语言无关 | 配置维护成本高多了一层IO单点问题(硬件F5+软件nginx两层负载,F5以主从HA部署,nginx则以集群多实例部署) | 大部分公司都适用,对运维有要求 | 亿贝、携程、早期互联网公司 |
| 客户端嵌入式架构 | 无单点性能更好 | 客户端复杂语言栈要求 | 中大规模公司、语言栈统一 | Dubbo 、Twitter finagle、Spring Cloud Ribbon |
| 独立进程代理架构 | 无单点性能更好与语言无关 | 运维部署复杂开发联调复杂 | 中大规模公司对运维有要求 | Smart StackService Mesh |
RMI 远程调用架构
Java RMI,即 远程方法调用(Remote Method Invocation),一种用于实现远程过程调用(RPC)(Remote procedure call)的Java API, 能直接传输序列化后的Java对象和分布式垃圾收集。它的实现依赖于Java虚拟机(JVM),因此它仅支持从一个JVM到另一个JVM的调用。

1、注册中心(可以是服务提供者本身):
1 | |
2、注册远程服务
1 | |
3、引用远程服务,并发起调用
1 | |
Dubbo架构与设计说明
架构图

流程说明
- Provider(提供者)绑定指定端口并启动服务
- 指供者连接注册中心,并发本机IP、端口、应用信息和提供服务信息发送至注册中心存储
- Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心
- 注册中心根据 消费 者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。
- Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。
- Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer
这么设计的意义:
- Consumer 与Provider 解偶,双方都可以横向增减节点数。
- 注册中心对本身可做对等集群,可动态增减节点,并且任意一台宕掉后,将自动切换到另一台
- 去中心化,双方不直接依懒注册中心,即使注册中心全部宕机短时间内也不会影响服务的调用
- 服务提供者无状态,任意一台宕掉后,不影响使用
Dubbo 整体设计

- config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
- proxy 服务代理层:服务接口透明代理,生成动态代理 扩展接口为 ProxyFactory
- registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
- cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
- monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
- protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter
- exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
- transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec
- serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool
协作流程如下:

Dubbo 中的SPI机制
java的SPI:具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类java.util.ServiceLoader

1 | |
Dubbo的SPI机制:
dubbo spi 目录文件
dubbo spi 文件内容:
luban=tuling.dubbo.server.LubanFilter
装配自定义Filter

配置关系图

Dubbo调用模块
dubbo调用模块核心功能是发起一个远程方法的调用并顺利拿到返回结果,其体系组成如下:
透明代理:通过动态代理技术,屏蔽远程调用细节以提高编程友好性。
负载均衡:当有多个提供者是,如何选择哪个进行调用的负载算法。
容错机制:当服务调用失败时采取的策略
调用方式:支持同步调用、异步调用
透明代理:
参见源码:
com.alibaba.dubbo.config.ReferenceConfig#createProxy
com.alibaba.dubbo.common.bytecode.ClassGenerator
com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
负载均衡
Dubbo 目前官方支持以下负载均衡策略:
- 随机(random):按权重设置随机概率。此为默认算法.
- 轮循(roundrobin):按公约后的权重设置轮循比率。
- 最少活跃调用数(leastactive):相同活跃数的随机,活跃数指调用前后计数差。
- 一致性Hash(consistenthash ):相同的参数总是发到同一台机器
为避免热点问题,一致性哈希使用虚拟节点,增大节点数量,根据指定的参数的hash的结果分散在0-2 31-1 之间
一致性哈希(Consistent Hashing)是一种在分布式系统中用于负载均衡的技术。它的主要目标是在动态添加或删除服务器时,最小化已经存在的键-值对与服务器之间的映射关系的变化。
在传统的哈希表中,键通过哈希函数映射到一组固定的桶中,每个桶对应一个特定的服务器或节点。但是,在动态环境中,当节点数量发生变化时,这种静态的映射可能会导致大量的数据迁移,影响系统性能。
一致性哈希通过引入虚拟节点(Virtual Nodes)和一种特殊的哈希函数来解决这个问题。具体来说,一致性哈希将哈希空间映射到一个环上,每个服务器或节点在环上对应一个位置。虚拟节点是对实际节点的多次复制,每个节点对应多个虚拟节点,它们也均匀地分布在环上。
当需要存储或检索数据时,首先将数据的键哈希到环上的一个位置,然后沿着环顺时针查找,直到找到第一个不小于该位置的节点,这个节点就是负责处理这个键的节点。这样做的好处是,当节点被添加或删除时,只有部分数据会受到影响,大部分数据仍然映射到原来的节点上,从而减少了数据迁移的开销。
一致性哈希在构建分布式缓存、分布式数据库等系统时广泛应用,能够提高系统的可扩展性和容错性。

容错
Dubbo 官方目前支持以下容错策略:
- 失败自动切换:调用失败后基于retries=“2” 属性重试其它服务器
- 快速失败:快速失败,只发起一次调用,失败立即报错。
- 勿略失败:失败后勿略,不抛出异常给客户端。
- 失败重试:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作
- **并行调用: **只要一个成功即返回,并行调用指定数量机器,可通过 forks=”2” 来设置最大并行数。
- 广播调用:广播调用所有提供者,逐个调用,任意一台报错则报错
异步调用
异步调用是指发起远程调用之后获取结果的方式。
- 同步等待结果返回(默认)
- 异步等待结果返回
- 不需要返回结果
Dubbo 中关于异步等待结果返回的实现流程如下图:
消费者订阅原理


什么是Dubbo
Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,核心功能包含服务自动发现与注册、负载均衡、高可用容错、降级、服务监控等。让开发者像调用本地方法一样去调用远程服务,无需关注底层细节,支持SPI做可插拔配置(选择用那种底层通信协议:默认dubbo协议,REST、Hession、Http、WebService、Thrift、gRpc)