手把手指导构建一个Spring Cloud服务,体系化认识微服务

语言: CN / TW / HK

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1. Spring cloud微服务的架构是什么?

对于微服务的理解,首先要了解原先的单体服务:

对比说明区别

混编军团(单体服务):具有很强的功能,但是兵种(业务)互相掺杂哦,典型的就是戚继光的鸳鸯阵(盾牌手+长枪手+刀手+火枪手);好处是什么情况都能应付点,但是不专业,越大的约不灵活,适合小微项目。 独立军团(微服务);具有强大的作战能力和拓展能力业务划分清晰(独立炮团,独立坦克团,独立航空兵团,独立后勤部);好处是各团专业能力强,便于拓展(当前团的副官拉出来就能组建新的兵团,技能培养更加专业化和体系化),对于复杂项目和大型项目比较适合,针对不同的场景可以像积木一样自由组合不同的兵团应对不同的战场需求;

2. 需要用到哪些服务组件

组件搭配原则:服务注册与发现组件+配置中心组件+网关组件+负载均衡与熔断组件(可选)

完整搭配参考图片

Spring初始化流程-完整版-Spring Cloud架构.png

3. 服务组件的作用说明和安排

Cloud项目的父组件依赖, 务必使用依赖的统一管理!

Boot与Cloud版本对照关系参考:http://spring.io/projects/spring-cloud

image.png

image.png

3.1. Spring Cloud Netflix(Eureka服务注册与发现)

作用: - 服务发现:可以注册 Eureka 实例,客户端可以使用 Spring 管理的 bean 发现实例 - 服务发现:可以使用声明性 Java 配置创建嵌入式 Eureka 服务器 - 断路器:可以使用简单的注释驱动方法装饰器构建 Hystrix 客户端 - 断路器:具有声明性 Java 配置的嵌入式 Hystrix 仪表板 - 声明式 REST 客户端:Feign 创建用 JAX-RS 或 Spring MVC 注释装饰的接口的动态实现 - 客户端负载均衡器:功能区 - 外部配置:从 Spring 环境到 Archaius 的桥梁(使用 Spring Boot 约定启用 Netflix 组件的本地配置) - 路由器和过滤器:自动注册 Zuul 过滤器,以及一种简单的约定优于配置的方法来创建反向代理

使用: - Eureka分为客户端和服务端 - Eureka客户端(注解@EnableEurekaClient)会尝试联系Eureka服务端(注解@EnableEurekaServer;默认注册地址:http://localhost:8761)

服务端启动界面:

image.png 关键代码:

image.png 主流注册中心对比: 个人推荐使用:Nacos image.png

3.2. Hystrix(熔断)

启用Hystrix仪表板:

配置注解:@EnableHystrixDashboard

image.png

image.png 测试接口熔断: - 1. 单独在接口上配置熔断条件 // 3秒超时就熔断 @HystrixCommand( commandProperties = { @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "3000") } ) @LoadBalanced @PostMapping("/printStr") public String printStr(@Param("str") String str) throws Exception { Long sleep = RandomUtils.nextInt(10000) * 1L; Thread.sleep(sleep); if (sleep % 3 == 0) { throw new Exception(); } System.out.println(str); return str; } - 2. 查看指标监控数据

image.png - 3. 熔断情况图如下 页面会展示熔断情况和正常情况,此处是手动加的代码,可以自己去配置

image.png

3.3. Robbin(负载均衡)

常用负载均衡策略: - 轮询策略 按照顺序,依次对所有的服务进行访问。

通过重写IRule的choose方法,来选择并返回决定调用的服务,在源码中,List allServers = lb.getAllServers(); 获得了所有的服务实例,int nextServerIndex = this.incrementAndGetModulo(serverCount); 保存了当前调用的实例的序号,然后就可以按照顺序调用下一个服务了 - 随机策略

对多个服务的随机调用,所以不存在规律,如下源码中int index = this.chooseRandomInt(serverCount); 通过随机数来选择下标,所以对user服务的调用是随机的 - 响应时间加权重策略 根据多个服务的响应时间来分配权重,响应时间越长的服务,权重越低,那么被调用的概率也就越低。相反,响应时间越短的服务,权重越高,被调用的概率也就越高

响应时间加权重策略的实现分为两步:

  1. WeightedResponseTimeRule实现类中默认情况下每隔30秒会统计一次每个服务的权重,在此30秒内,用的是轮询策略
  2. 30秒之后,会根据统计的结果来分配每个实例的权重,然后根据权重来分配调用次数
  3. 重试策略 通过轮询策略选出一个实例,然后去访问,如果此实例为null或者已经失效,那么会重试其他的实例,answer = this.subRule.choose(key);

会根据轮询策略选择一个实例,然后if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline)判断如果实例为null或者失效,那么会重新选择 - 最低并发策略 根据每个服务实例的并发数量来决定,访问并发数最少的那个服务,int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);

会获得当前遍历的实例的并发数,然后和其他的实例的并发数进行判断,最终访问并发量最少的那个实例 - 可用过滤策略 会聪明的过滤掉一直失败并被标记为circuit tripped的user服务,而且会过滤掉那些高并发的user服务 - 自定义策略

本身并没有实现什么特殊的处理逻辑,但是可以通过重置LoadBalancer来达到自定义一些高级策略的目的,可以重写initWithNiwsConfig和setLoadBalancer

3.4. Gateway

Spring Cloud Gateway 特点: - 基于 Spring Framework 5、Project Reactor 和 Spring Boot 2.0 构建 - 能够匹配任何请求属性的路由。 - 谓词和过滤器特定于路由。 - 断路器集成。 - Spring Cloud Discovery客户端集成 - 易于编写谓词和过滤器 - 请求速率限制 - 路径重写 关键代码:

image.png 测试效果: - 1. 使用Eureka服务注入(Gateway,Eureka-Client1) - 2. 通过访问网关,将请求转发到Client1 - 3. 后期接口请求可以接入统一的身份认证