网关系列之一:浅析SpringCloudGateway负载均衡实现
前言
心血来潮准备写一个网关项目,同时写一些文档心得来提升自己。几年前接触过api网关项目,当时感觉通过SCG改造得比较粗糙,但总的来说通过SCG网关比较符合我现在的想法:解决一些负载均衡、权限控制及静态资源解析等问题就能得到一个类似Nginx的轮子。
调试负载均衡
首先从配置文件定义一条负载均衡的路由,类似如下:
spring:
cloud:
discovery:
client:
simple:
instances:
test-service:
- uri: http://localhost:8081
- uri: http://localhost:8083
gateway:
routes:
- id: route1
uri: lb://test-service
predicates:
- YiFu=true,default
这里自定义了一个YIFU
的路由断言工厂,让请求包进入该条路由,同时向负载均衡器提供了两个下游服务8081、8083。
DispatcherHandler
和SpringMVC一样可以看作一个比较底层入口的调度者,经过调试发现它先调用了RouterFunctionMapping
组件,这个组件代理routeFunction 默认为空,直接返回,接着调用 RequestMappingHandlerMapping
,这个应该对应WebFlux的Controller中的@RequestMapping
注解的入口处理,然后调用到 RoutePredicateHandlerMapping
路由断言处理,这里应该是路由代理的入口。
在启动服务时,RoutePredicateHandlerMapping
默认注入,有关路由的FilteringWebHandler,及路由对象,请求达到时,根据路由进行断言,从而进入路由的代理过程
其中,FilteringWebHandler
中代理了11个Filter ,其中就包含了实现负载均衡的重要组件:ReactiveLoadBalancerClientFilter
路由到ReactiveLoadBalancerClientFilter
时,首先URI判定是否需要负载均衡, 如果不需要直接跳过Filter,如果需要负载均衡,会通过LoadBalancerClientFactory
来初始化以serviceId
为名的应用上下文,以此扫描出配Configuration配置来实例化负载均衡器,如下图,第一次从LoadBalancerClientFactory
getInstances 方法初始化上下文并实例化相关Bean
其中 实例化默认的负载均衡的组件为RoundRobinLoadBalancer
通过RoundRobinLoadBalancer
注入的 serviceInstanceListSingletonSupplier 来获取下游服务实例,可以看到这个supplier由DiscoveryClientServiceInstanceListSupplier
被CachingServiceInstanceListSupplier
包裹,从而具备缓存服务实例的功能。
当缓存中没有实例,则通过DiscoveryClientServiceInstanceListSupplier
get 获取
而DiscoveryClientServiceInstanceListSupplier
最终引用了SimpleReactiveDiscoveryClient
来获取实例。
总结
通过上面的负载均衡分析,学习到了一些spring的启动加载顺序,上下文初始化,懒加载,看似很简单的一块功能,放在我面前肯定不会考虑这么多,总结出下的负载均衡过程下图:
下一篇试着自定义实现下这个过程,将服务实例发现动态化管理。
文章作者:1900
文章链接:https://zhuty.cn/archives/gateway1
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0 许可协议,转载请注明出处!
评论