- Spring Cloud升级之路 - Hoxton - 1.背景
- Spring Cloud升级之路 - Hoxton - 9. 针
- Spring Cloud升级之路 - Hoxton - 8. 修
- Spring Cloud Gateway + Spring Cl
- 使用Consul实现服务发现:instance-id自定义(3种
- 【spring cloud hoxton】Ribbon 真的能被
- Spring Cloud — Ribbon 负载均衡
- Spring Cloud升级之路 - Hoxton - 7. 后
- Spring Cloud升级之路 - Hoxton - 2.入口
- Spring Cloud升级之路 - Hoxton - 4. 使
本系列示例与胶水代码地址: https://github.com/HashZhang/spring-cloud-scaffold
Spring Cloud还是比较活跃的,更新一直很快。我一般考虑最新版本SR2发布之后,再考虑升级(一般SR1还有SR2会有一些新老框架的兼容性升级)。而且由于需要我们线上稳定,结合我们的发布周期来看,跳一个大版本升级是一个更好的选择(也就是一年做一次大版本升级)。例如我们之前的升级路线就是:Brixton -> Daltson -> Finchley -> 当前的Hoxton
做了这么多次升级,感觉可以出这个系列,来分享我们项目使用Spring cloud
框架实现的框架功能,在升级中遇到的坑,以及如何升级等等。每个版本都会有实例代码,并在上一版本实现的功能基础上,实现更多更实用的功能。所有示例代码都在开头提到的项目中,每个版本系列的最后,还会附上功能测试流程。
在Hoxton版本Release的同时,Spring Cloud也宣布,其中的这些项目,已经进入维护模式(不再开发新功能),用户最好做如下的替换:
- Spring Cloud Netflix Ribbon -> Spring Cloud Load Balancer
- Spring Cloud NetFlix Zuul -> Spring Cloud Gateway
- Spring Cloud Hystrix -> Spring Cloud Circuit Breaker + Resilience4J
- Spring Cloud Netflix Turbine -> Micrometer + Promethus
- Spring Cloud Netflix Archaius -> Spring Cloud Config Server
可以看出,Spring Cloud netflix中的zuul, ribbon, hystrix都基本上算是废了,我们也可以抛弃掉Sprnig Cloud Netflix了。还有一个体系也在官方中,就是Spring Cloud Alibaba,但是通过Spring Cloud netflix这件事,我个人感觉这种依赖性质的胶水项目,最好还是我们架构组自己维护,这块是比较容易有坑的,自己维护自己用更新起来更高效,而且不会有粘合的项目都不更新了替换起来要人命的代价。
Spring Cloud Hoxton,至少对于官方文档来说,是一个里程碑式的变化。官方文档终于将所有项目的文档分开了,并且做了比较多的整理,可以看出,这个Hoxton一定是有人下定决心要做一个变革了。并且,Spring Cloud在这个版本引入了更多的虚拟化,云原生依赖,例如Spring-Cloud-kubernetes,确实,有些服务发现,调用策略什么的,Spring Cloud和k8s体系重复了,这个依赖可以使我们灵活地切换这些功能到底交给谁来做,期待这个项目的完善成熟。
这篇文章,会主要列出升级步骤与详细说明,以及对应的源代码,和实现的功能。以及如何替换Spring Cloud Netflix体系为新的组件。
原有的功能以及之前的实现
1. 微服务
以前的体系:
- 注册中心:Eureka
- 客户端封装:OpenFeign
- 客户端负载均衡:Ribbon
- 断路器与隔离: Hystrix
实现的功能:
- 所有集群公用同一个公共Eureka集群,集群之间不互相调用,通过实例的
metamap
中的zone
配置,来区分不同集群的实例。之前通过Ribbon
的配置ServerListFilter
实现,使用com.netflix.loadbalancer.ZoneAffinityServerListFilter
作为ServerListFilter
,参考:Spring cloud实现FeignClient指定Zone调用 - 微服务之间调用,有重试,只对GET请求进行重试,连接超时,读取超时还有 4xx 和 5xx 的状态码都会重试。这个之前是通过加入
spring-retry
重试通过ribbon配置实现的。参考:Spring Cloud Finchley OpenFeign的重试配置相关的坑 - 微服务调用有线程隔离,例如微服务1调用微服务2和微服务3,调用微服务2的线程和微服务3的线程不一样。之前是通过
Hystrix
配置实现hystrix.threadpool.default.coreSize=50
- 实现了实例级别的熔断,而不是微服务级别的。当调用微服务的两个实例的时候,当一个实例一直异常,则将这个实例断路器打开一段时间,而不是整个微服务都不能工作。之前通过
Ribbon
的配置LoadBalancerRule
实现,使用com.netflix.loadbalancer.AvailabilityFilteringRule
作为LoadBalancerRule
。参考:Ribbon的AvailabilityFilteringRule的坑
2. 网关
以前的体系:
- API网关:Zuul
实现的功能:
- 重试,只对GET请求进行重试,连接超时,读取超时还有 4xx 和 5xx 的状态码都会重试。这个之前是通过加入
spring-retry
重试通过ribbon配置实现的。 - 微服务调用有线程隔离,例如微服务1调用微服务2和微服务3,调用微服务2的线程和微服务3的线程不一样。之前是通过
Hystrix
配置实现hystrix.threadpool.default.coreSize=50
- 实现了实例级别的熔断,而不是微服务级别的。当调用微服务的两个实例的时候,当一个实例一直异常,则将这个实例断路器打开一段时间,而不是整个微服务都不能工作。之前通过
Ribbon
的配置LoadBalancerRule
实现,使用com.netflix.loadbalancer.AvailabilityFilteringRule
作为LoadBalancerRule
。参考:Ribbon的AvailabilityFilteringRule的坑 - 特定接口 request body 解密与特定接口 response body 的加密。
3. Eureka-Server
实现的功能:
- 实例的快速上线下线,参考:Eureka 服务实例实现快速下线快速感知快速刷新配置解析
现在要实现的功能
1. 微服务
- 微服务之间调用依然基于利用 open-feign 的方式,有重试,仅对GET请求并且状态码为4xx和5xx进行重试(对4xx重试是因为滚动升级的时候,老的实例没有新的 api,重试可以将请求发到新的实例上)
- 某个微服务调用其他的微服务 A 和微服务 B, 调用 A 和调用 B 的线程池不一样。并且调用不同实例的线程池也不一样。也就是实例级别的线程隔离
- 实现实例级别的熔断。
- 使用 zone 隔离,不同 zone 之间不能互相调用
- 负载均衡的轮询算法,需要请求与请求之间隔离,不能共用同一个 position 导致某个请求失败之后的重试还是原来失败的实例
2. 网关
- 转发请求,有重试,仅对GET请求并且状态码为4xx和5xx进行重试
- 不同微服务的不同实例线程隔离
- 实现实例级别的熔断。
- 使用 zone 隔离,仅转发请求到同 zone 的实例
- 负载均衡的轮询算法,需要请求与请求之间隔离,不能共用同一个 position 导致某个请求失败之后的重试还是原来失败的实例
3. Eureka
- 实现服务实例快速上下线
新的pom依赖
1. 微服务
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
</parent>
<properties>
<disruptor.version>3.4.2</disruptor.version>
<resilience4j-spring-cloud2.version>1.1.0</resilience4j-spring-cloud2.version>
</properties>
<dependencies>
<!--内部缓存框架统一采用caffeine-->
<!--这样Spring cloud loadbalancer用的本地实例缓存也是基于Caffeine-->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!--日志需要用log4j2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--lombok简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--注册到eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--spring cloud rpc相关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--调用路径记录-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!--暴露actuator相关端口-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--暴露http接口, servlet框架采用nio的undertow,注意直接内存使用,减少GC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-cloud2</artifactId>
<version>${resilience4j-spring-cloud2.version}</version>
</dependency>
<!--log4j2异步日志需要的依赖,所有项目都必须用log4j2和异步日志配置-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>${disruptor.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<!--最好用JDK 12版本及以上编译,11.0.7对于spring-cloud-gateway有时候编译会有bug-->
<!--虽然官网说已解决,但是11.0.7还是偶尔会出现-->
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
2. 网关
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
</parent>
<properties>
<disruptor.version>3.4.2</disruptor.version>
<resilience4j-spring-cloud2.version>1.1.0</resilience4j-spring-cloud2.version>
</properties>
<dependencies>
<!--内部缓存框架统一采用caffeine-->
<!--这样Spring cloud loadbalancer用的本地实例缓存也是基于Caffeine-->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!--日志需要用log4j2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--lombok简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</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-gateway</artifactId>
</dependency>
<!--调用路径记录-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!--暴露actuator相关端口-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-cloud2</artifactId>
<version>${resilience4j-spring-cloud2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
<!--log4j2异步日志需要的依赖,所有项目都必须用log4j2和异步日志配置-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>${disruptor.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<!--最好用JDK 12版本及以上编译,11.0.7对于spring-cloud-gateway有时候编译会有bug-->
<!--虽然官网说已解决,但是11.0.7还是偶尔会出现-->
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3. Eureka-Server
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
</parent>
<properties>
<disruptor.version>3.4.2</disruptor.version>
</properties>
<dependencies>
<!--内部缓存框架统一采用caffeine-->
<!--这样Spring cloud loadbalancer用的本地实例缓存也是基于Caffeine-->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!--日志需要用log4j2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!--lombok简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--调用路径记录-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!--暴露actuator相关端口-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--暴露http接口, servlet框架采用nio的undertow,注意直接内存使用,减少GC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!--log4j2异步日志需要的依赖,所有项目都必须用log4j2和异步日志配置-->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>${disruptor.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<!--最好用JDK 12版本及以上编译,11.0.7对于spring-cloud-gateway有时候编译会有bug-->
<!--虽然官网说已解决,但是11.0.7还是偶尔会出现-->
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
网友评论