内容简介
本书针对 Spring Cloud Alibaba 生态下的技术组件从应用到原理进行全面的分析,设计的技术组件包括分布式服务治理的 Dubbo、服务配置和服务注册中心 Nacos、分布式限流与熔断 Sentinel、分布式消息通信 RocketMQ、分布式事务 Seata 及微服务网关 Spring Cloud Gateway。由于 Spring Cloud 中所有的技术组件都是基于 Spring Boot 微服务框架来集成的,所以对于 Spring Boot 的核心原理也做了比较详细的分析。
本书中涉及的所有技术组件,笔者都采用“场景→需求→解决方案→应用→原理”高效技术学习模型进行设计,以便让读者知其然且知其所以然。在“原理”部分,笔者采用大量的源码及图形的方式来进行分析,帮助读者达到对技术组件深度学习和理解的目标。
第 1 章 微服务的发展史
技术作为业务的支撑,它永远是伴随着业务的发展而发展的,所以作为一名技术开发者,我们需要不断地学习新的技术去解决新的技术问题。但是随着年龄的增长,我们能够投入的时间和精力越来越少,掌握科学的学习方法并且让自己的思维方式和对技术的理解层次前置于新技术就显得很重要了。其实现在很多程序员是很幸运的,他们进入 Java 开发这个领域,各个方面的技术提现都非常成熟,遇到任何问题都有非常成熟的解决方案,所以只需要了解并且会用这些技术就能够解决几乎所有的问题。但是他们也会因为缺少对于技术发展过程的了解,而导致对于技术解决方案的了解过于片面。我遇到的很多学员都问过我这样一个问题:“SOA 和微服务有什么区别?”这个问题单纯靠网上各种文章去理解会比较困难,但是如果经历过 SOA 到微服务的发展过程,就很容易理解了。
我会从架构发展的角度来描述技术的发展过程,根据不同阶段所面临的问题来推动架构的演变,从而更好地理解微服务的本质以及它所带来的好处。大家会发现很多书的第 1 章都写一些基础新或者架构演进的内容,我也不例外,因为这块内容主要会通过架构的演进帮助大家建立一个整体的意识,从而更好地掌握微服务体系。
1.1 从单体架构到分布式架构的演进
任何现在看起来非常复杂和庞大的架构,一定都是随着业务产品中用户量和数据量增长而不断演变来的。而架构的发展可能都会经历单体架构、垂直化和集群、SOA(面向服务架构)、微服务架构等。当然不是所有的公式都会严格按照这个架构的顺序来演进,每个公司遇到的问题不一样,架构的发展
1.1.1 单体架构
1.1.2 集群及垂直化
1.1.3 SOA
1.1.4 微服务架构
业务系统实施服务化改造之后,原本共享的业务被拆分形成可复用的服务,可以在最大程度上避免共享业务的重复建设、资源连接瓶颈等问题。那么被拆分出来的服务是否也需要业务功能为纬度进行拆分和独立部署,以降低业务的耦合及提升容错性呢?
微服务就是这样一种解决方案,从名字上来看,面向服务(SOA)和微服务本质上都是服务化实现的一种体现。如果 SOA 是面向服务开发思想的雏形,那么微服务就是针对可重用服务的更进一步优化,我们可以把 SOA 看成微服务的超集,也就是多个微服务可以组成一个 SOA 服务。伴随着服务粒度的细化,会导致原本 10 个服务可能拆分成了 100 个微服务,一旦服务规模扩大就意味着服务的构建、发布、运维的复杂度也会成倍增加,所以实施微服务的前提是软件交付链路及基础设施的成熟化。因此微服务在我看来并不是一个新的概念,它本质上是服务化思想的最佳实践方向。
由于 SOA 和微服务两者的关注点不一样,造成了两者有非常大的区别:
- SOA 关注的时服务的重用性及解决信息孤岛问题。
- 微服务关注的是解耦,虽然解耦合可复用性从特定的角度来看是一样的,但本质上是有区别的,解耦是降低业务之间的耦合度,而重用性关注的是服务的复用。
- 微服务会更多地关注在 DevOps 的持续交付上,因为服务粒度细化之后使得开发运维变得更加重要,因此微服务与容器化技术的结合更加紧密。
如图 1-4 所示,将每个具体的业务服务构成可独立运行的微服务,每个微服务只关注某个特定的功能,服务之间采用轻量级通信机制 REST API 进行通信。细心的读者会发现 SOA 中的服务和微服务架构中的服务粒度是一样的,不是说 SOA 是微服务的超集吗?其实我们可以把用户服务拆分得更细,比如用户注册服务、用户鉴权服务等。实际上,微服务到底要拆分到多大的粒度没有统一的标准,更多的时候是需要在粒度和团队之间找平衡的,微服务的粒度越小,服务独立性带来的好处就越多,但是管理大量的微服务也会越复杂。
1.2 微服务架构带来的挑战
从单体架构到微服务架构,极速架构随着产品的复杂度和访问的压力增大不断地进行变化,最终的目的都是更好地服务业务,使得用户在使用产品时获得更好地体验。而微服务架构之所以能够被广泛地使用,自然有它的优势,先来简单分析一下微服务架构的优点。
1.2.1 微服务架构的优点
微服务架构有很多好处,下面简单罗列了几个比较突出的点。
- 复杂度可控:通过对共享业务服务更细粒度的拆分,一个服务只需要关注一个特定的业务领域,并通过定义良好的接口清晰表述服务边界。由于体积小、复杂度低,开发、维护会更加简单。
- 技术选型更加灵活:每个微服务都由不同的团队来维护,所以可以结合业务特性自由选择技术栈。
- 可扩展
1.2.2 微服务机构面临的挑战
第 3 章 Spring Cloud 的核心之 Spring Boot
Spring Cloud 是基于 Spring Boot 提供的一套微服务解决方案,配置中心、服务注册和负载均衡等,都是在 Spring Boot 这个框架上来构建的,所以 Spring Boot 其实是构建 Spring Cloud 生态的基石,那么到底什么是 Spring Boot 呢?简单来说,Spring Boot 是帮助开发者快速构建一个基于 Spring Framework 及 Spring 生态体系的应用解决方案,也是 Spring Framework 对于“约定大于配置(Conversion over Configuration)”理念的最佳实践。如果想更加深入地了解 Spring Boot,有必要花一点时间了解一下 Spring 的起源。
3.1 重新认识 Spring Boot
Spring Framework 的起源需要追溯到 2002 年,当时很多知名公司都在用 Java EE标准及 EJB 容器作为主要的软件解决方案,其中 EJB 是 J2EE 规范的核心内容,也与我们要说的 Spring Framework的诞生密切相关。
3.1.1 Spring IoC/DI
IoC(Inversion of Control)和 DI(Dependency Injection)的全称分别是控制反转和依赖注入。如何理解这两个概念呢?
IoC(控制反转)实际上就是把对象的生命周期托管到 Spring 容器中,而反转是指对象的获取方式被反转了,这个概念可能不是很好理解,咱们通过两张图来了解一下 IoC 的作用。图 3-1 表示的是传统意义上对象的创建方式,客户端类如果需要用到 User 及 UserDetail,需要通过 new 来构建,这种方式会使代码之间的耦合度非常高。
当使用 Spring IoC 容器之后,客户端类不需要通过 new 来创建这些对象,如图 3-2 所示,在图 3-1 的基础上增加了 IoC 容器之后,客户端类获得 User 及 UserDetail对象实例时,不再通过 new 来构建,而是直接从 IoC 容器中获得。那么 Spring IoC 容器中的对象是什么时候构建的呢?在早期的 Spring 中,主要通过 XML 的方式来定义 Bean,Spring 会解析 XML 文件,把定义的 Bean 转载到 IoC 容器中。
DI
DI(Dependency Inject),也就是依赖注入,简单理解就是 IoC 容器在运行期间,动态地把某种依赖关系注入组件。为了彻底搞明白 DI 的概念,我们继续看一下图 3-2。在 Spring 配置文件中描述了两个 Bean,分别是 User 和 UserDetail,这两个对象从配置文件上来看是没有任何关系的,但实际上从类的关系图来看,它们之间存在聚合关系。如果我们希望这个聚合关系在 IoC 容器中自动完成注入,也就是像这段代码一样,通过 user.getUserDetail来获得 UserDetail 实例,该怎么做呢?
其实很简单,我们只需要在 Spring 的配置文件中描述 Bean 之间的依赖关系,IoC 容器在解析该配置文件的时候,会根据 Bean 的依赖关系进行注入,这个过程就是依赖注入。
实现依赖注入的方法有三种,分别是接口注入、构造方法注入和 setter 方法注入。不过现在基本上都是基于注解的方式来描述 Bean 之间的依赖关系,比如@Autowired、@Inject 和@Resource。但是不管形式怎么变化,本质上还是一样的。
3.1.2 Bean 装配方式的升级
基于 XML 配置的方式很好地完成了对象声明周期的描述和管理,但是随着项目规模的不断扩大,XML 的配置也逐渐增多,使得配置文件难以管理。另一方面,项目中依赖关系越来越复杂,配置文件变得难以理解。这个时候迫切需要一种方式来解决问题。
3.2 快速构建 Spring Boot 应用
一个 Spring Boot 应用应该是什么样子,或者 Spring Boot 的优势在哪里?接下来演示基于 Spring Boot 构建一个 Web 项目的例子。
构建 Spring Boot 应用的方式有很多,比如在 https://start.spring.io 网站上可以通过图形界面来完成创建。如果大家使用 IntelliJ IDEA 这个开发工具,就可以直接在这个工具上来创建 Spring Boot 项目,默认也是使用 https://start.spring.io 来构建的。
构建完成后会包含以下核心配置和类。
- Spring Boot 的启动类 SpringBootDemoApplication:
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
- resource 目录,包含 static 和 templates 目录,分别存放静态资源及前端模版,以及 application.properties 配置文件。
- Web 项目的 starter依赖包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
在不做任何改动的情况下,可以直接运行 SpringBootDemoApplication 中的 main 方法来启动 Spring Boot 项目。当然,由于默认情况下没有任何 URI 映射,所以看不出效果,我们可以增加一个 Controller 来发布 Restful 接口,代码如下:
/**
* A simple controller that returns a greeting.
*/
@RestController
public class HelloController {
/**
* Returns a greeting.
*
* @return a greeting
*/
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
接着,直接运行 SpringBootDemoApplication 类,服务启动成功后再浏览器中输入 http://localhost:8080/hello,即可访问刚刚发布的 Restful 接口。
3.3 Spring Boot 自动装配的原理
在 Spring Boot 中,不得不说的一个点是自动装配,它是 Starter 的基础,也是 Spring Boot 的核心,那么什么叫自动装配呢?
简单来说,就是自动将 Bean 装配到 IoC 容器中,接下来,我们通过一个 Spring Boot 整合 Redis 的例子来了解一下自动装配。
- 添加 Starter 依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 在 application.properties 中配置 Redis 的数据源:
spring:
application:
name: spring-boot-demo
data:
redis:
host: localhost
port: 6379
- 在 HelloController 中使用 RedisTemplate 实现 Redis 的操作:
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* A simple controller that returns a greeting.
*/
@RestController
public class HelloController {
@Autowired
RedisTemplate<String, String> redisTemplate;
@GetMapping("/hello")
public String hello() {
redisTemplate.opsForValue().set("key", "value");
return "Hello, World!";
}
}
3.5 本章小结
本章主要分析了 Spring Boot 中自动装配的基本原理,并且通过实现一个自定义 Starter 的方式加深了大家对于自动装配的理解。由于 Spring Cloud 生态中组件,都是基于 Spring Boot 框架实现的,了解 Spring Boot 的基本原理将有助于大家对后续内容的理解,磨刀不误砍柴工,笔者还是那句话,比了解技术的基本使用方法更重要的时了解技术产生的背景及核心原理。
第 4 章 微服务架构下的服务治理
众所周知,服务与服务之间的远程通信是分布式架构最基本的组成部分,传统意义上的远程通信,更多的时候是解决信息孤岛及数据互联互通问题的,它主要关注的是数据的共享。随着 SOA 生态的不断完善以及微服务架构思想的落地,服务与服务之间的远程通信需求更多来自服务的解耦。同时,业务规模的不断增长会使得微服务的数量增加,那么问题也就随之产生了,比如:
- 如何协调线上运行的服务,以及保障服务的高可用性。
- 如何根据不同服务的访问情况来合理地调控服务器资源,提高机器的利用率。
- 线上出现故障时,如何动态地对故障业务做降级、流量控制等。
- 如何动态地更新服务中的配置信息,比如限流阈值、降级开关等。
- 如何实现大规模服务集群所带来的服务地址管理和服务上下线的动态感知。
为了解决这些问题,就需要一个统一的服务治理框架对服务进行统一、有效的管控,从而保障服务的高效、健康运行,而 Dubbo 就是一个这样的框架。
Dubbo 是阿里巴巴内部使用的一个分布式服务治理框架,于2012 年开源。由于 Dubbo 在服务治理这一领域的优势,以及它本身在阿里巴巴经过大规模的业务样子,所以在很短的时间内,Dubbo 就被很多互联网公司采用,笔者就是在 2013 年的时候开始接触 Dubbo 的,当时是在公司内部把 Webservice 切换到 Dubbo 框架。
由于某些原因 Dubbo 在 2014 年停止了维护,所以那些使用 Dubbo 框架的公司开始自己维护,比较知名的是当当网开源的 DubboX。值得高兴的是,2017 年 9 月,阿里巴巴重启了 Dubbo 的维护并且做好了长期投入的准备,也对 Dubbo 的未来做了很多规划。2018 年 2 月份,Dubbo 进入 Apache 孵化,这意味着它将不只是阿里巴巴的 Dubbo,而是属于开源社区的,也意味着会有更多的开源贡献者参与到 Dubbo 的开发中来。
2019 年 5 月,Apache Dubbo 正式从孵化器中毕业,代表着 Apache Dubbo 正式成为Apache 的顶级项目。笔者在写这本书的时候,Apache Dubbo 的最新版本是 2.7.5。
本章主要围绕 Apache Dubbo 框架的基本解决方案,以及它背后的一些实现原理和设计思想进行展开,帮助大家更好地了解 Apache Dubbo。
4.1 如何理解 Apache Dubbo