Spring Cloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、路由配置、分布式链路追踪、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。最重要的是,跟SpringBoot框架一起使用的话,会让你开发微服务架构的云服务非常好的方便。
1. 重要组件说明
这里的说明借用网上一个很酷的分类方式来说明:润物无声类和独挑大梁类。
独挑大梁型:
独挑大梁,独自启动不需要依赖其它组件。
- Eureka,服务注册中心,特性有失效剔除、服务保护。(类似生活中的大堂,登记了整个项目的所有服务)
- Dashboard,Hystrix仪表盘,监控集群模式和单点模式,其中集群模式需要收集器Turbine配合。(类似生活中的保安监控室)
- Zuul,API服务网关,功能有路由分发和过滤。(类似交警叔叔,指挥道路交通)
- Config,分布式配置中心,支持本地仓库、SVN、Git、Jar包内配置等模式。(类似规章制度,每个人都从这里获取规定配置)
润物无声型:
润物无声,融合在每个微服务中、依赖其它组件并为其提供服务。
- Ribbon,客户端负载均衡,特性有区域亲和、重试机制。(类似nginx)
2. Hystrix,客户端容错保护,特性有服务降级、服务熔断、请求缓存、请求合并、依赖隔离。(怕访问过于频繁服务挂了,进行限流,太频繁的请求就直接拒绝)
3. Feign,声明式服务调用,本质上就是Ribbon+Hystrix。(用注解的方式进行服务调用,代码更好看了)
4. Stream,消息驱动,有Sink、Source、Processor三种通道,特性有订阅发布、消费组、消息分区。
5. Bus,消息总线,配合Config仓库修改的一种Stream实现。(用于广播消息,一说大家都知道了啦)
6. Sleuth,分布式服务追踪,需要搞清楚TraceID和SpanID以及抽样,如何与ELK整合。(服务多了,调用的线路就会很复杂,需要跟踪来知道你到底是怎么走的)
Spring Cloud 组件整体作用说明:
Spring Cloud是一个由独立项目组成的总体项目,原则上具有不同的发布节奏。前期的Spring Cloud版本是跟随SpringBoot的发布版本的,但是Spring Cloud的版本更新较快,而SpringBoot相对比较稳定,大版本更新较慢,所以后面Cloud就开始放纵自己,版本发布起飞。Cloud的版本是以伦敦地铁站来命名的。
2. 版本说明
下面的表格给出了Spring Cloud版本需要使用匹配的SpringBoot版本。注意一定要匹配,不然你可能会遇到各种奇怪的问题。
Spring Cloud版本 | SpringBoot版本 |
---|---|
Hoxton | 2.2.x |
Greenwich | 2.1.x |
Finchley | 2.0.x |
Edgware | 1.5.x |
Dalston | 1.5.x |
另外我们在官方还会见到这个版本说明:
版本说明:
- GA:General Availability,正式发布的版本,官方推荐使用此版本。在国外都是用GA来说明release版本的;
- PRE: 预览版,内部测试版. 主要是给开发人员和测试人员测试和找BUG用的,不建议使用;
- SNAPSHOT: 快照版,可以稳定使用,且仍在继续改进版本。
一般我们使用release版本即可。
下面的表格是详细的SpringCloud 与 SpringBoot对应的版本关系:(spring官方对应查看网址:https://start.spring.io/actuator/info):
SpringCloud版本 | SpringBoot版本 |
---|---|
Finchley.M2 | “Spring Boot >=2.0.0.M3 and <2.0.0.M5” |
Finchley.M3 | “Spring Boot >=2.0.0.M5 and <=2.0.0.M5” |
Finchley.M4 | “Spring Boot >=2.0.0.M6 and <=2.0.0.M6” |
Finchley.M5 | “Spring Boot >=2.0.0.M7 and <=2.0.0.M7” |
Finchley.M6 | “Spring Boot >=2.0.0.RC1 and <=2.0.0.RC1” |
Finchley.M7 | “Spring Boot >=2.0.0.RC2 and <=2.0.0.RC2” |
Finchley.M9 | “Spring Boot >=2.0.0.RELEASE and <=2.0.0.RELEASE” |
Finchley.RC1 | “Spring Boot >=2.0.1.RELEASE and <2.0.2.RELEASE” |
Finchley.RC2 | “Spring Boot >=2.0.2.RELEASE and <2.0.3.RELEASE” |
Finchley.SR4 | “Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT” |
Finchley.BUILD-SNAPSHOT | “Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3” |
Greenwich.M1 | “Spring Boot >=2.1.0.M3 and <2.1.0.RELEASE” |
Greenwich.SR3 | “Spring Boot >=2.1.0.RELEASE and <2.1.9.BUILD-SNAPSHOT” |
Greenwich.BUILD-SNAPSHOT | “Spring Boot >=2.1.9.BUILD-SNAPSHOT and <2.2.0.M4” |
Hoxton.M2 | “Spring Boot >=2.2.0.M4 and <2.2.0.BUILD-SNAPSHOT” |
Hoxton.BUILD-SNAPSHOT | “Spring Boot >=2.2.0.BUILD-SNAPSHOT” |
最后,如果你真的不能确定版本依赖关系,我还有一个终极大杀招:https://start.spring.io/。你可以在spring提供的init中先配置上你的SpringBoot版本,然后选择你要用到的Cloud组件,他会自动帮你匹配相应的版本:
比如我选择了SpringBoot 2.1.8,然后选了Eureka,那么他给我自动生成的pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
怎么样,这一下子就解决了所有的烦恼了吧。
3. Eureka 初接触
Eureka是SpringCloud全家桶中一个主要组件,用于服务的注册与发现。
SpringCloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现。Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server,并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。Spring Cloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个Java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。
Eureka Server接收到心跳时,会更新对应的服务实例的信息,如果实例信息发生变化,则将实例加入最近变更实例队列中。服务消费者会创建一个timer定时更新服务实例,第一次全量拉取服务实例,之后就是增量拉取,也就是从变更队列拉取变更实例信息。
我们先来搭建一个简单的单server Eureka实例,了解一下基本的服务注册流程。
整体工程目录结果如下,分为一个server模块和一个client模块:
server模块相关代码如下:
pom文件配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rickiyang.learn</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这里我使用的SpringBoot版本是2.0.3,使用的SpringCloud版本是Finchley.RELEASE。
下面看一下application.yml的配置:
server:
port: 8761
spring:
main:
allow-bean-definition-overriding: true
application:
name: eureka-server
eureka:
instance:
prefer-ip-address: true
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 60000
remote-region-registry-fetch-interval: 5
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:${server.port}/eureka/
registry-fetch-interval-seconds: 5
然后我们只用在启动类中加上@EnableEurekaServer
注解即可:
package com.rickiyang.learn.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
服务端的配置如上,客户端需要做的事情就是如何将客户端的服务注册到服务端并且能让服务端收到。客户端需要做的也只有两步:
-
引入Eureka相关的jar包;
-
在启动类打上
@EnableDiscoveryClient
标识
下面来看一下相关实现,首先是xml配置,要和服务端使用相同的SpringCloud版本,同样最好能保持一样的SpringBoot版本,这样能避免很多奇怪的问题。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.rickiyang.learn</groupId>
<artifactId>eureka-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
然后是application.yml配置:
server:
port: 8762
spring:
application:
name: eureka-client
main:
allow-bean-definition-overriding: true
# cloud:
# inetutils:
# # 忽略指定网卡(支持正则),假设你的电脑有 VM 那么该选项是非常有用的一个选项
# ignored-interfaces: #忽略 docker0 网卡以及 veth 开头的网卡
# - docker0
# - veth.*
# preferred-networks: # 使用指定网络地址,选择 eth0 网卡,当然也可以直接写 IP (192.168)
# - eth0
eureka:
instance:
# 此处建议写,不写默认是机器名
prefer-ip-address: true
# 优先级小于 application.properties ,如果你想知道当前注册上去的版本必须使用 application.properties 中的配置写法
# 因为 bootstrap.yml 最早初始化,那时候还无法读取到 pom.xml 中的属性
instance-id: ${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
# ip-address 强行指定此实例 IP ,不是很推荐,绝大多数情况 prefer-ip-address 与 preferred-networks 配合都够用了
client:
service-url:
# 划重点:此处的 defaultZone 千万别写成 default-zone
defaultZone: http://localhost:8761/eureka/
最后就是在启动类上加上@EnableDiscoveryClient
注解即可:
package com.rickiyang.learn.eurekaclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
工程搭建完毕,接下来可以启动Eureka服务端,启动没有问题,再启动客户端。然后打开服务端的地址:http://localhost:8761/
,我们会看到客户端已经注册成功。