背景
这周出现了一个重复请求的问题,两个请求之间刚好间隔一分钟,但是由于缺乏日志并不能判断这个是用户点击导致的,还是Gateway出现重复请求导致的,趁着周末有时间,再深入了解一下。
由于SpringCloud Gateway是基于Spring Webflux的,大量采用了Reactor,相比传统观念上的 单刀直入,理解上会更加麻烦一点。
单纯的去看代码本身其实是很低效的一个行为,所以去我给自己定了一个小目标,了解一下 Gateway 的重试是怎么实现的。
过程
初看其实挺简单的,Google一下,发现就是配置一下 RetryGatewayFilterFactory 中的几个参数,其实现也挺简单的,判断一下Response的stateCode,service状态码,以及异常是否符合(默认存在IO异常和超时异常)。
routes:- id: nacos-provideruri: lb://nacos-providerpredicates:- Path=/nacos-provider/**filters:- StripPrefix=1- name: Retryargs:routeId: nacos-providerretries: 3series:- SERVER_ERRORstatuses:- OKmethods:- GET- POST
加上好,启动项目,curl,发现并没有重试,最终原因如下,但是过程还是比较曲折的
- 打开debug日志
 - 日志太多啦—->不得不吐槽Nacos的日志
- 配置了好几回的logback都未生效
 - debug发现nacos jar包有一份logback日志,覆盖掉
 
 开始看日志,在
org.springframework.cloud.gateway.handler中发现如下日志[[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter@5dcf0772}, order = -2147483648],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@1b46392c}, order = -2147482648],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@421ead7e}, order = -1],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter@6826b70f}, order = 0],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter@781dac73}, order = 0],[[RewritePath /nacos-provider/?(?<remaining>.*) = '/${remaining}'], order = 1],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@c472300}, order = 10000],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter@446b64b3}, order = 10150],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.LoadBalancerServiceInstanceCookieFilter@35ac9ebd}, order = 10151],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@4df7d9ee}, order = 2147483646],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@56c0a61e}, order = 2147483647],[GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@5f6494c0}, order = 2147483647]]
显然没有
RetryGatewayFilterFactory中的Filter, 开始陷入为什么环节- 是不是
RetryGatewayFilterFactory由于自动装配没有注册上去,debug发现注册了 - 是不是没有加载进去,debug发现加载进去了
 - 最终找到原因如下链接所示
 
于是把
spring.cloud.gateway.discovery.locator.enable=true注释掉,再次curl成功了。但是具体原因我又没找到,于是开始找原因,上边链接的解释是enable=true会自动加载注册中心的服务,然后建立一些默认的配置,找默认配置就得找到enable在哪里使用的,为此不得不把源代码拉下来, 网络悲催,一直下载不下来全部的配置。
顶着一片红找到了路由刷新的地方,Nacos默认每隔30秒发送一个HeartbeatEvent事件,springcloud收到事件后,又发送一个RefreshRoutesEvent事件,在CachingRouteLocator和CachingRouteDefinitionLocator中找到了消费的地方,由于是reactor代码,到这里就有点迷糊了,so bad。
具体原因请看这里: SpringCloud Gateway【 路由刷新】拓展
为此我又拓展了一个思考题,或者说是面试题,如果我去设计一个Gateway会怎么去思考,随便写写。
- 是不是
 可用性
- 稳定
 - 路由: 最重要的过程,收到URL,路由映射,转发到后端服务
- header路由
 - path路由
 - query路由
 - cookie路由
 - 等等
 
 - 其他feature: 
- 路由刷新
 - 重试
 - websocket
 - 等等
 
 
- 性能
- 同步
 - 异步
 
 - 复杂性
- 满足可用性和性能的基础上,代码应该尽可能的简单,但又不能丢失拓展性,让更多的同学能够参与进来,群策群力。
 
 - 拓展性
 
