本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面一节,我们实现了 FeignClient 粘合 resilience4j 的 Retry 实现重试.细心的读者可能会问,为何在这里的实现,不把断路器和线程限流一起加上呢: @Bean public FeignDecorators.Builder defaultBuilder( Environment environment, RetryRegistry retryRegistry…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面两节,我们梳理了实现 Feign 断路器以及线程隔离的思路,并说明了如何优化目前的负载均衡算法.但是如何更新负载均衡的数据缓存,以及实现重试.断路器以及线程隔离的源码还没提,这一节我们会详细分析. 首先,从 spring.factories 引入,增加我们自定义 OpenFeign 配置的加载: spring.factories # AutoConfiguration org.sp…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面一节,我们利用 resilience4j 粘合了 OpenFeign 实现了断路器.重试以及线程隔离,并使用了新的负载均衡算法优化了业务激增时的负载均衡算法表现.这一节,我们开始编写单元测试验证这些功能的正确性,以便于日后升级依赖,修改的时候能保证正确性.同时,通过单元测试,我们更能深入理解 Spring Cloud. 验证重试配置 对于我们实现的重试,我们需要验证: 验证配置正确…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节针对我们的重试进行测试 验证针对限流器异常的重试正确 通过系列前面的源码分析,我们知道 spring-cloud-openfeign 的 FeignClient 其实是懒加载的.所以我们实现的断路器也是懒加载的,需要先调用,之后才会初始化线程隔离.所以这里如果我们要模拟线程隔离满的异常,需要先手动读取载入线程隔离,之后才能获取对应实例的线程隔离,将线程池填充满. 我们先定义…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节针对我们的重试进行测试 验证针对可重试的方法响应超时异常重试正确 我们可以通过 httpbin.org 的 /delay/响应时间秒 来实现请求响应超时.例如 /delay/3 就会延迟三秒后返回.这个接口也是可以接受任何类型的 HTTP 请求方法. 我们先来指定关于 Feign 超时的配置 Options: //SpringExtension也包含了 Mockito 相关…
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ 上图中演示了一个非常简单的微服务架构: 微服务会向注册中心进行注册. 微服务从注册中心读取服务实例列表. 基于读取到的服务实例列表,微服务之间互相调用. 外部访问通过统一的 API 网关. API 网关从注册中心读取服务实例列表,根据访问路径调用相应的微服务进行访问. 在这个微服务架构中的每个进程需要实现的功能都…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面一节,我们梳理了实现 Feign 断路器以及线程隔离的思路,这一节,我们先不看如何源码实现(因为源码中会包含负载均衡算法的改进部分),先来讨论下如何优化目前的负载均衡算法. 之前的负载均衡算法 获取服务实例列表,将实例列表按照 ip 端口排序,如果不排序即使 position 是下一个可能也代表的是之前已经调用过的实例 根据请求中的 traceId,从本地缓存中以 traceId…
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ Spring Cloud 官方文档说了,它是一个完整的微服务体系,用户可以通过使用 Spring Cloud 快速搭建一个自己的微服务系统.那么 Spring Cloud 究竟是如何使用的呢?他到底有哪些组件? spring-cloud-commons组件里面,就有 Spring Cloud 默认提供的所有组件功…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 接下来,将进入我们升级之路的又一大模块,即网关模块.网关模块我们废弃了已经进入维护状态的 zuul,选用了 Spring Cloud Gateway 作为内部网关.为何选择 Spring Cloud Gateway 而不是 nginx 还有 Kong 的原因是: 项目组对于 Java 更加熟悉,并且对于 Project Reactor 异步编程也比较熟悉,这个比较重要 需要在网关中使用我…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford spring-cloud-common 不再是一个纯依赖的项目,这个模块包括: spring-framework-common 的依赖 同步与异步微服务公共的依赖 同步与异步微服务公共的框架代码改造,这个我们后面分析框架以及我们设计的修改的时候,会详细分析,这里先跳过 同步与异步微服务公共的依赖包括: 代码请参考:h…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Log4j2 异步日志配置,防止日志过多的时候,成为性能瓶颈.这里简单说一下 Log4j2 异步日志的原理:Log4j2 异步日志基于高性能数据结构 Disruptor,Disruptor 是一个环形 buffer,做了很多性能优化(具体原理可以参考我的另一系列:高并发数据结构(disruptor)),Lo…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进行内部域名与服务映射,通过健康检查接口判断实例健康状态,然后直接使用 OpenFeign 生成对应域名的 Feign Client.Spring Cloud 生态中,对 OpenFeign 进行了封装,其中的 Feign Client 的各个组件,也是做了一定的定制化,可以实现在 OpenFeign Client…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在开始编写我们自己的日志 Filter 之前,还有一个问题我想在这里和大家分享,即在 Spring Cloud Gateway 中可能发生链路信息丢失的问题. 主要冲突 - Project Reactor 与 Java Logger MDC 之间的设计冲突 Poject Reactor 是基于异步响应式设计的编程模式的实现,它的主要实现思路是先编写执行链路,最后 sub 执行整个链路.但…
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ 之前我们提到了,不同的集群,使用的是同一套 Eureka 集群. 我们会动态在线发布每个微服务,在 K8s 的环境下,我们一般使用 ReplicaSet 将我们的微服务部署成无状态的微服务实例(参考:ReplicaSet):在这种情况下,新的微服务实例地址(ip)和原来的地址一般是不一样的.在这种情况下,我们想实…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 源代码文件:https://github.com/HashZhang/spring-cloud-scaffold/blob/master/spring-cloud-iiford/pom.xml 1. 使用 log4j2 异步日志所需要的依赖:需要排除默认的日志实现 logback,增加 log4j2 的依赖,并且添加…
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ spring-cloud-commons 中参考了 spring-cloud-netflix 的设计,引入了 NamedContextFactory 机制,一般用于对于不同微服务的客户端模块使用不同的 子 ApplicationContext 进行配置. spring-cloud-commons 是 Spring…
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ 我们实现的 Spring Cloud 微服务框架,里面运用了许多 Spring Cloud 组件,并且对于某些组件进行了个性化改造.那么对于某个 Spring Cloud 组件,我们一般是如何入手理解其中的原理呢?以及如何知道其中的扩展点呢?一般从下面两个方面入手: 通过 spring-boot SPI 机制查看…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford Log4j2 异步日志核心通过 RingBuffer 实现,如果某一时刻产生大量日志并且写的速度不及时导致 RingBuffer 满了,业务代码中调用日志记录的地方就会阻塞.所以我们需要对 RingBuffer 进行监控.Log4j2 对于每一个 AsyncLogger 配置,都会创建一个独立的 RingBuffer…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 在我们的项目中,我们没有采用默认的 Tomcat 容器,而是使用了 UnderTow 作为我们的容器.其实性能上的差异并没有那么明显,但是使用 UnderTow 我们可以利用直接内存作为网络传输的 buffer,减少业务的 GC,优化业务的表现.其实 Tomcat 也有使用直接内存作为网络传输的 buffer 的配置…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford server: undertow: # access log相关配置 accesslog: # 存放目录,默认为 logs dir: ./log # 是否开启 enabled: true # 格式,各种占位符后面会详细说明 pattern: '{ "transportProtocol":"%{TR…
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spring Boot 的 SPI 机制对 Undertow 进行订制,主要有如下两个方面: 需要在 accesslog 中打开响应时间统计. 期望通过 JFR 监控每个 Http 请求,同时占用空间不能太大. 接下来我们依次实现这两个需求: 首先,我们的框架作为基础组件,应该按照基础组件的标准来开发,使用…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 首先,我们给出官方文档中的组件结构图: 官方文档中的组件,是以实现功能为维度的,我们这里是以源码实现为维度的(因为之后我们使用的时候,需要根据需要定制这些组件,所以需要从源码角度去拆分分析),可能会有一些小差异. 负责解析类元数据的 Contract OpenFeign 是通过代理类元数据来自动生成 HTTP API 的,那么到底解析哪些类元数据,哪些类元数据是有效的,是通过指定 Con…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 需要重试的场景 微服务系统中,会遇到在线发布,一般的发布更新策略是:启动一个新的,启动成功之后,关闭一个旧的,直到所有的旧的都被关闭.Spring Boot 具有优雅关闭的功能,可以保证请求处理完再关闭,同时会拒绝新的请求.对于这些拒绝的请求,为了保证用户体验不受影响,是需要重试的. 云上部署的微服务,对于同一个服务,同一个请求,很可能不会所有实例都同时异常,例如: Kubernetes…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 上一节我们通过单元测试验证了重试的正确性,这一节我们来验证我们线程隔离的正确性,主要包括: 验证配置正确加载:即我们在 Spring 配置(例如 application.yml)中的加入的 Resilience4j 的配置被正确加载应用了. 相同微服务调用不同实例的时候,使用的是不同的线程(池). 验证配置正确加载 与之前验证重试类似,我们可以定义不同的 FeignClient,之后检查…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 上一节我们通过单元测试验证了线程隔离的正确性,这一节我们来验证我们断路器的正确性,主要包括: 验证配置正确加载:即我们在 Spring 配置(例如 application.yml)中的加入的 Resilience4j 的配置被正确加载应用了. 验证断路器是基于服务和方法打开的,也就是某个微服务的某个方法断路器打开但是不会影响这个微服务的其他方法调用 验证配置正确加载 与之前验证重试类似,…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 为何需要封装异步 HTTP 客户端 WebClient 对于同步的请求,我们使用 spring-cloud-openfeign 封装的 FeignClient,并做了额外的定制.对于异步的请求,使用的是异步 Http 客户端即 WebClient.WebClient 使用也比较简单,举一个简单的例子即: //使用 WebClient 的 Builder 创建 WebClient WebC…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们来测试下前面封装好的 WebClient,这里开始,我们使用 spock 编写 groovy 单元测试,这种编写出来的单元测试,代码更加简洁,同时更加灵活,我们在接下来的单元测试代码中就能看出来. 编写基于 spock 的 spring-boot context 测试 我们加入前面设计的配置,编写测试类: @SpringBootTest( properties = [ "webcli…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节,继续使用 spock 测试我们自己封装的 WebClient 测试针对 readTimeout 重试 针对响应超时,我们需要验证重试仅针对可以重试的方法(包括 GET 方法以及配置的可重试方法),针对不可重试的方法没有重试.我们可以通过 spock 单元测试中,检查对于负载均衡器获取实例方法的调用次数看出来是否有重试 我们通过 httpbin.org 的 '/delay/…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 网关由于是所有外部用户请求的入口,记录这些请求中我们需要的元素,对于线上监控以及业务问题定位,是非常重要的.并且,在这些元素中,链路信息也是非常重要的.通过链路信息,我们可以找到请求调用全链路相关的日志.并且,网关也是大部分请求链路起始的地方,记录请求中的元素的同时,也要带上链路信息. 我们需要在网关记录每个请求的: HTTP 相关元素: URL 相关信息 请求信息,例如 HTTP HE…
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们在这一节我们将继续讲解避免链路信息丢失做的设计,主要针对获取到现有 Span 之后,如何保证每个 GlobalFilter 都能保持链路信息.首先,我们自定义 Reactor 的核心 Publisher 即 Mono 和 Flux 的工厂,将链路信息封装进去,保证由这个工厂生成的 Mono 和 Flux,都是只要是这个工厂生成的 Mono 和 Flux 之间无论怎么拼接都会保持链路信…