Netflix推出Eureka、Ribbon、Zuul、Hystrix、Config
Alibab推出Nacos、Ribbon、Gateway、sentinel,其中Nacos集成了注册中心和配置中心,并且不是以工程形式搭建注册中心和配置中心,更方便实用

注册中心-Eureka/Nacos

Eureka

由于Eureka默认的心跳检测为30秒,3次心跳失败才会从Eureka中移除,所以Eureka最长90S后才能感知到服务提供者下线。直接关闭实例服务,会存在一段实例不可访问到Eureka检测到服务下线的时间段。

Nacos

Nacos 是阿里巴巴开源的集分布式配置中心、分布式注册中心为一体的分布式解决方案。
它的优点:

  1. 提供命令空间,方便管理不同环境的配置;
  2. 提供web界面,方便管理配置和服务;
  3. 支持配置版本管理,回滚;
  4. 支持服务管理,手动上线、下线服务。能够做到几乎实时的服务上/下线感知

简单灵活,支持更细粒度的命令空间,分组等为麻烦复杂的环境切换提供了方便;同时也很好支持动态路由的配置,只需要简单的几步即可,application.yml如下:

  1. spring:
  2. application:
  3. name: spring-cloud-gateway-demo
  4. cloud:
  5. nacos:
  6. discovery:
  7. server-addr: localhost:8848
  8. config:
  9. server-addr: localhost:8848
  10. file-extension: yml
  11. shared-configs[0]:
  12. data-id: gateway-routes.yml # 配置文件名-Data Id
  13. group: DEFAULT_GROUP # 默认为DEFAULT_GROUP
  14. refresh: true # 是否动态刷新,默认为false
  15. server:
  16. port: 8081
  • Namespace:默认public,用于区分部署环境或者租户的,如dev
  • GroupId:对不同的文件进行分组
  • DataId:具体某个文件id

image.png

Nacos下线实例

通过心跳检测,Nacos 发现实例不存在后,自动下线掉此实例。在关闭旧的实例到下线实例之间,存在一定的时间差,导致服务消费方调用接口会发生报错的情况,对业务操作造成一定影响

网关-Zuul/gateway【1】

网关的主要作用就是鉴权、限流、日志输出、路由
Zuul1.x用的是阻塞式的 API(BIO),不支持长链接如websocket;而Gateway用的是非阻塞式的 API(NIO)。
Zuul1.x和Gateway都是Spring Cloud全家桶的一部分,Gateway是基于java8、Spring5、Spring Boot2.0的,可以认为是Zuul1.x的升级版和替代版。
由于Zuul1.x的低效,Zuul2.x的最大改进就是基于Netty Server实现了异步IO接入请求,同时基于Netty Client实现到后端业务服务API的请求。Spring Cloud也是基于Netty实现的,比Zuul2.x实现的更早

Zuul1.x

基于同步IO,Spring Cloud全家桶一部分。主要的三种过滤器preroutingpost,分别作用与调用业务前请求处理、直接响应、调用业务后响应处理。
image.png

Zuul2.x

Zuul2.x基于netty实现,从而达到更高的性能、更低的延迟,同时也调整了filter类型,原先的三个核心filter显示命名为Inbound FilterEndpoint FilterOutbound Filter
image.png

Gateway

Spring Cloud Gateway明确区分Router和Filter。Gateway由三部分组成

  • 路由(Route):请求经过路由到对应的微服务中,每个路由有唯一id和对应的目的url,包含若干个断言和过滤器
  • 断言(Predicate):断言会根据配置的路由规则,对Http Request进行断言匹配
  • 过滤器(Filter):对流经的请求进行过滤,获取/修改参数或响应

Gateway内置了很多开箱即用功能,并且通过SpringBoot配置或手工编码链式调用来使用。比如内置了10种Rounter,可以直接配置一下随心所欲的根据Header、Path、Host或者Query来做路由。并且过滤器中支持OAuth2.0,统一集成授权、认证等功能。
整个请求路由过程如下:

  1. 客户端请求首先被GatewayHandlerMapping获取,根据断言(predicate)匹配找到对应路由
  2. 根据路由URL请求目标服务之前,经过一组前置过滤器,目标服务请求完获取响应
  3. 网关收到响应后,经过一组后置过滤器后,同样由Gateway Handler Mapping返回给客户端

image.png

应用

  • 通用的如:路由、日志、鉴权等。
  • 安全:身份认证、脱敏、流量清洗、黑名单
  • 灰度发布,利用权重路由weight
  • 监控:记录响应数据、api耗时、性能监控
  • 限流:流量控制
  • 路由:动态路由规则
  • 性能:API高可用、负载均衡、容错机制

GateWay API网关配置

方法1:写在Gateway项目代码里

  1. @SpringBootApplication
  2. public class DemogatewayApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(DemogatewayApplication.class, args);
  5. }
  6. @Bean
  7. public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
  8. return builder.routes()
  9. .route("user-service", r -> r.path("/user/*").uri("http://localhost:8071"))
  10. .route("order-service", r -> r.path("/order/*").uri("http://localhost:8061"))
  11. .build();
  12. }
  13. }

方法2:写在gateway配置文件application.properties

  1. spring.cloud.gateway.routes[0].id=order-service
  2. spring.cloud.gateway.routes[0].uri=http://localhost:8061
  3. spring.cloud.gateway.routes[0].predicates[0].name=Path
  4. spring.cloud.gateway.routes[0].predicates[0].args[pattern]=/order/*
  5. spring.cloud.gateway.routes[1].id=user-service
  6. spring.cloud.gateway.routes[1].uri=http://localhost:8071
  7. spring.cloud.gateway.routes[1].predicates[0].name=Path
  8. spring.cloud.gateway.routes[1].predicates[0].args[pattern]=/user/*

推荐使用配置文件方式,可以动态刷新配置文件,为动态刷新路由规则提供可能。

过滤器【2】

自定义过滤器

过滤器分为全局过滤器(GlobalFilterGatewayFilter)和网关过滤器。所有匹配到路由的请求都会经过全局过滤器,网关过滤器只有在指定路由上才会起作用。

内置过滤器

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: add_request_header_route
  6. uri: https://example.org
  7. filters:
  8. // 对于所有匹配的请求,将会给传给下游的请求添加一个请求头 X-Request-Foo:Bar
  9. - AddRequestHeader=X-Request-Foo, Bar
  10. // 对于所有匹配的请求,将给传给下游的请求添加一个查询参数 foo=bar
  11. - AddRequestParameter=foo, bar
  12. // 对于所有匹配的请求,添加一个响应头 X-Response-Foo:Bar
  13. - AddResponseHeader=X-Response-Foo, Bar
  14. // 所有匹配的请求都将加上前缀/mypath
  15. - PrefixPath=/mypath

熔断器功能的内置网关过滤器(Hystrix GatewayFilter Factory),需要引入 spring-cloud-starter-netflix-hystrix

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: ingredients
  6. uri: lb://ingredients
  7. predicates:
  8. - Path=//ingredients/**
  9. filters:
  10. - name: Hystrix
  11. args:
  12. name: fetchIngredients
  13. // 可选参数,断路之后请求将被重定向到匹配的这个URL,即http://localhost:9994
  14. fallbackUri: forward:/fallback
  15. - id: ingredients-fallback
  16. uri: http://localhost:9994
  17. predicates:
  18. - Path=/fallback

限流功能的内置网关过滤器(RequestRateLimiter GatewayFilter Factory),使用一个RateLimiter实现来决定是否当前请求可以继续往下走。如果不能,默认将返回HTTP 429 - Too Many Requests
借助于redis,使用令牌桶算法实现限流。需要引用 spring-boot-starter-data-redis-reactive

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: requestratelimiter_route
  6. uri: https://example.org
  7. filters:
  8. - name: RequestRateLimiter
  9. args:
  10. // 允许用户每秒处理多少个请求。这是令牌桶被填充的速率
  11. redis-rate-limiter.replenishRate: 10
  12. // 用户在一秒钟内允许执行的最大请求数。这是令牌桶可以容纳的令牌数量。将此值设置为0将阻塞所有请求。
  13. redis-rate-limiter.burstCapacity: 20

一个稳定的速率是通过将replenishRateburstCapacity设为相同的值来实现的。也可以将burstCapacity设得比replenishRate大,以应对临时爆发的流量。

动态路由配置(Gateway+Nacos)

  1. 通过监听Nacos下发的动态路由配置【3】
    1. 注册Nacos配置服务的监听器,待收到服务端配置(文件md5校验)变更的事件后主动刷新Gateway的路由缓存
  2. 直接借助nacos即可【4】

    限流

    监控

Hystrix/sentinel

Ribbon

分布式事务

2PC二阶段提交

2PC是一种尽量保证强一致性的分布式事务。引入事务协调者角色来协调管理各参与者的提交和回滚,二阶段分别指的是准备(投票)和提交两个阶段。适用于数据库层面的分布式事务场景,具体流程:

  1. 第一阶段:协调管理者会发送准备命令给各参与者,各参与者做完除事务提交外的所有业务,然后返回准备成功,协调管理者同步等待(同步阻塞协议,拥有超时机制)所有参与者的响应。
  2. 第二阶段:如果都是准备成功,那么协调者向所有参与者发送提交事务的命令,执行返回成功;如果有不成功的,那么发送回滚命令;

第一阶段协调者超时的话,判断事务失败,发送回滚命令;如果第二阶段失败的话,不论回滚还是提交都是不断重试。

缺点:

  • 同步阻塞总体效率较低
  • 协调器存在单点故障问题
  • 在极端情况下会存在数据不一致情况(协调器在下发二阶段命令过程中,协调器和某个参与者一起挂了,新选举出来的协调器不知道挂了的参与者是否成功执行了命令)

image.png

3PC三阶段提交

3PC是为了解决2PC的一些问题出现的。3PC包含三个阶段,准备阶段(CanCommit)、预提交阶段(PreCommit)和提交阶段(DoCommit)。3PC的准备阶段只是询问参与者的自身状态,是否有执行事务的能力,3PC的预提交阶段相当于2PC的准备阶段。
image.png
相比于2PC,参与者也引入了超时机制。如果2PC挂在了事务协调管理者提交阶段(提交请求还没发出去),参与者会一直阻塞等待,但3PC的参与者就不会傻等了,直接提交。
相比于2PC,准备阶段不直接执行事务锁资源,使得某些资源不可用的参与者都阻塞着;
预提交阶段起到了统一状态的作用,预提交表明之前所有的参与者都回应了。从维基百科上看,3PC 的引入是为了解决提交阶段 2PC 协调者和某参与者都挂了之后新选举的协调者不知道当前应该提交还是回滚的问题。
3PC的缺点是增加了一个阶段多了交互,性能下降并仍存在数据不一致问题。

TCC(Try-Confirm-Cancle)二阶段事务补偿

和2PC很像,具体流程是:
阶段1:主业务尝试(try)调从业务,从业务并不立即执行,而是进行一个预留操作,如预扣库存冻结资源
阶段2:从业务都返回yes后,主业务会确认(confirm)之前的预留操作,如果不全都是yes,调用取消(cancel),取消之前的预留操作,如扣减库存,释放资源。

与2PC对比:
两者都是二阶段提交,流程相似,但是2PC是数据库层面的,对开发者来说无感知。TCC是业务层面的,TCC的代码耦合度很高,如第一阶段try预留操作。
TCC是最终一致性的,不需要长时间持有资源锁,每一个事务相对孤立,效率高。

参考

【1】如何评价 spring cloud gateway? 对比 zuul2.0 主要的优势是什么?
https://www.zhihu.com/question/280850489
【2】微服务网关 Spring Cloud Gatewayhttps://www.cnblogs.com/cjsblog/p/11099234.html
【3】Nacos + Spring Cloud Gateway动态路由配置:https://mp.weixin.qq.com/s?src=11&timestamp=1634389185&ver=3378&signature=nARYGXcvcBdyBGoqNE3YDixB2JAe7YsTObPFvzo7KgkWoz7h-t6bKOHmCmPDSA7ydb4aUSre0le1-uHxCd3cw9d0g1Pjxv0yRlTwI9sXqaNWlX79GihyfUEj4GbSldSt&new=1
【4】Nacos + Gateway 实现动态刷新路由:https://blog.csdn.net/itkfdektxa/article/details/119772401
【5】Nacos 发布0.3.0版本,迄今为止最好看的版本
https://my.oschina.net/u/1464083/blog/2875110
【6】通过Nacos动态刷新Spring Cloud Gateway的路由:
https://www.jianshu.com/p/0d408fd4afe3