一、应用框架演进

1 传统垂直应用架构

以经典的 MVC 垂直架构为例,通常分三层:

  1. View:视图展示层,使用 JSP/JS/HTML+CSS。
  2. Controller:调度控制层,请求的分发。
  3. Model:应用模型层,业务数据和业务执行逻辑,被多个视图重用。

标准的 MVC 模式并不包含数据访问层,但实际开发中需要专门的数据库连接池和统一的数据库访问接口对接数据库,于是 ORM 框架逐渐流行起来。

通常基于 MVC 架构开发的应用代码会统一打成一个 war 包,不同的应用功能之间通过本地 API 进行调用,基本不存在跨进程的远程服务调用。

通常的基于热双机备份,判断应用进程宕机或僵死后,应用切换备机,然后尝试重新拉起主机。
而在高并发、大流量的应用场景中,需要做集群,通常前端通过 F5 等负载均衡器做七层负载均衡,后端做对等集群部署。

2 RPC 架构

RPC 全称 Remote Procedure Call,它是一种进程间通信方式。允许像调用本地服务一样调用远程服务,具体实现可以不同。

2.1 RPC 框架原理

RPC 框架的目标就是让远程过程(服务)调用更加简单、透明,RPC 框架负责屏蔽底层的传输方式(TCP/UDP)、序列化方式(XML/JSON/二进制)和通信细节。
调用原理图如下:

  1. 远程服务提供者需要以某种形式提供服务调用相关的信息,包括但不限于服务接口定义、数据结构,或者中间态的服务定义文件,例如 Thrift 的 IDL 文件;服务调用者需要通过一定的途径获取远程服务调用相关信息,例如服务端接口定义 Jar 包导入,获取服务端 IDL 文件等。
  2. 远程代理对象:服务调用者调用的服务实际是远程服务的本地代理,对于 Java 语言,它的实现就是 JDK 的动态代理,通过动态代理的拦截机制,将本地调用封装成远程服务调用。
  3. 通信:RPC 框架与具体的协议无关。
  4. 序列化:远程通信,需要将对象转换成二进制码流进行网络传输,不同的序列化框架,支持的数据类型、数据包大小、异常类型及性能等都不同。有的甚至支持用户自定义序列化框架(Hadoop Avro)。

2.2 实现一个简单的 RPC 框架

  1. 分四个聚合项目:Provider、Consumer、RpcFramework、ServiceApi。为了简单期间,RPC 核心和 ServiceApi 合并一个项目 C。
  2. Provider 依赖 C 项目,Consumer 依赖 C 项目。这样 Provider 和 Consumer 都有了同一个顶级接口以及同版本的 RPC 框架。
  3. RPC 框架提供 export() 用于 Provider 发布自己的实现类、refer() 用于 Consumer 调用对应的顶级接口。
  4. refer() 方法用于生成代理,此代理每次执行方法都会调用 invoke() 方法,而 invoke() 方法实际通过 socket 连接 Provider ,将调用的方法名、参数等传递给 Provider。
  5. export() 方法用于获取 Consumer 传递的方法名,参数等,以及自己暴露的接口实现类,来反射执行获取结果,并返回给 Consumer。
  6. 代理对象获取到了结果,返回给调用者。
  7. Provider 使用了反射,用于将调用者的方法名、参数、自己暴露的服务调用执行获取结果。Consumer 使用了代理,每次执行方法,都会调用 invoke() 即将调用的方法名、参数、调用的接口传递给 Provider。实现远程服务的本地代理。
  8. 参考的 GITHUB 地址

2.3 业界主流 RPC 框架

  1. Facebook 的 Apache Thrift。
  2. Hadoop 的 Avro-RPC。
  3. caucho 的 Hession。
  4. Google 的 gRPC。

2.4 RPC 框架面临的挑战

  1. 提供服务的机器越来越多,服务 URL 配置管理变得非常困难(服务发布订阅中心)。
  2. 服务间依赖关系变得错综复杂,甚至分不清哪个应用要在哪个应用之前启动(链路追踪)。
  3. 某个服务调用量特别大,需要加机器。为了解决容量规划问题,需要采集服务调用 KPI 数据,进行汇总和分析,计算出服务部署实例数和服务器的配置规格。
  4. 服务上线容易下线难,下线通知,需要统一的服务生命周期管理流程进行管控,如何保证敏感服务不被误调用,服务的访问安全策略又如何制定?
  5. 服务治理问题。

3 SOA 服务化架构

SOA 是一种粗粒度、松耦合的以服务为中心的架构,接口之间通过定义明确的协议和接口进行通信。

3.1 面向服务设计的原则

  1. 服务可服用:不管是否存在即时复用的机会,服务均被设计为支持潜在的可复用。
  2. 服务共享一个标准契约:IDL 文件、Java 接口定义、甚至是一个接口说明文档。
  3. 服务是松耦合的:服务被设计为功能相对独立、尽量不依赖其它服务的独立功能提供者。
  4. 服务是底层逻辑的抽象:只有经服务契约所暴露的服务队外部世界可见,契约之外底层的实现逻辑是不可见的。
  5. 服务是可组合、可编排的:多个服务可能被编排组合成一个新的服务。
  6. 服务是可自治的:逻辑由服务所控制,并位于一个清晰的边界内,服务已经在边界内被控制,不依赖于其它服务。
  7. 服务是无状态的:这意味着要讲状态管理移至他处。
  8. 服务是可被自动发现的:服务发布上线后,允许被其它消费者自动发现。服务下线后,允许消费者接收服务下线通知。

3.2 服务治理

SOA 服务治理主要包括如下几个方面:

  1. 服务定义:SOA 治理最基础的方面就是监视服务的创建过程。
  2. 服务生命周期管理:服务需要进行规划、设计、实现、部署、维护、下线主要阶段。
  3. 服务版本治理:新版本的兼容性。
  4. 服务注册中心:服务提供者如何发布服务?服务消费者如何订阅服务?
  5. 服务监控:服务监控中心需要对服务的调用时延、成功率、吞吐率等数据进行实时采样和汇总。
  6. 运行期服务质量保障:包括服务限流、服务迁入迁出、服务升降级、服务权重调整和服务超时控制等,通过运行期的动态治理,可以在不重启服务的前提下达到快速提升服务运行质量的目标。
  7. 快速的故障定界定位手段:大规模分布式环境下海量业务/平台日志的采集、汇总和实时在线检索;分布式消息跟踪。
  8. 服务安全:是否允许任何人调用任何服务,数据敏感型服务是否允许所有用户访问所有数据,交互数据是否需要进行保护,服务的安全认证等。服务安全访问策略有多重,例如动态生成 Token 的方式做安全访问授权。

4 微服务架构

微服务架构(MSA)是一种服务化架构风格。
SOA 架构解决了应用服务化问题,但是随着服务规模越来越大、服务治理越来越多,微服务架构风格应运而生。微服务架构的主要特征如下:

  1. 原子服务。
  2. 高密度部署:利用LXC(例如 Docker)实现容器级部署。
  3. 敏捷交付:服务由小研发团队负责设计、开发、测试、部署、线上治理、灰度发布和下线,运维整个生命周期支撑,实现真正的 DevOps。
  4. 微自治:服务足够小,功能单一,可以独立打包、部署、升级、回滚和弹性伸缩,不依赖其它服务,实现局部自治。

相对于 SOA,主要差异如下:

  1. 服务拆分粒度。
  2. 服务依赖:SOA 尽量重用,微服务功能单一独立。
  3. 服务规模:SOA 服务粒度大,多数会采用多个服务合并打 war 包,因此服务实例数比较有限。微服务强调尽可能拆分,同时很多服务会独立部署。
  4. 架构差异。
  5. 服务治理。
  6. 敏捷交付。

5 个人理解总结

  1. MVC架构:在于多个功能部署同一个进程,一个 war 包,通过 HTTP 请求来实现互相的调用。重点在于前后端分离。
  2. RPC架构:将核心和公共业务抽取出来,独立运行进程,使用 RPC 调用服务屏蔽底层通信逻辑。重点在于业务复用以及通用拆分。
  3. SOA架构:服务生命周期管控和SOA服务治理是关键。
  4. 微服务架构:敏捷开发、持续交付、DevOps理论,基于 Docker 等轻量级容器。重点在于独立打包、部署和升级,小团队敏捷交付,交付周期短。