首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud Gateway结合注册中心使用路由失败?那就自己定制路由功能呗

Spring Cloud Gateway结合注册中心使用路由失败?那就自己定制路由功能呗

作者头像
吴就业
发布2020-08-27 17:37:36
1.6K0
发布2020-08-27 17:37:36
举报
文章被收录于专栏:Java艺术Java艺术

关注 “Java艺术” 我们一起成长!

使用API网关可统一流量入口,对客户端屏蔽内部多个微服务的域名,实现负载均衡,并可以统一鉴权、接口访问控制、流量管控。

作为网关,代理了所有流量,对性能要求更高,介于网关核心功能是路由、代理后端服务,主要处理请求转发,如果使用同步阻塞方式,后端接口响应耗时越长,对网关性能的影响就越大。nginx作为反向代理中的佼佼者,基于nginx开发的Kong网关性能更是毋庸置疑。但作为内部网关,我们需要更好的定制,选择Java系的网关对我们来说更容易驾驭。

在选定编程语言后,我们就需要考虑性能问题。而网关的性能损耗无非就是I/O阻塞,只有纯异步才能有更好的性能表现,所以我们选择至少是基于实现Reactive Streams规范的反应式编程库开发的网关。

Spring cloud gateway作为spring cloud生态系统中的网关,基于Spring Boot、Project Reactor开发,不仅实现异步非阻塞,并且更快速与spring cloud生态中的其它组件整合,这是我们选择Spring cloud gateway的原因。

我们基于Spring Cloud Gateway开发内部微服务网关,并结合注册中心实现自动服务发现路由。

就在最近将项目部署测试环境的Kubernetes集群上时,发现路由失败。经调试源码发现是因为没有导入Ribbon的依赖,所以Gateway注册的是非负载均衡路由过滤器(NoLoadBalancerClientFilter),当路由规则配置以"lb://"开头时,该路由过滤器直接响应503(目标服务不可达)。

Gateway使用全局过滤器实现路由功能,其按照全局过滤器指定的排序值顺序调用,每个过滤器都可终止请求的调用。

Gateway允许每个全局过滤器重写路由URL,通过将重写后的URL更新到请求的attribute向下传递,下游过滤器可重新修改路由URL,最初的路由URL从路由规则取得。

// 从ServerWebExchange#getAttribute取得路由url
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);

Gateway使用一个链表将每个过滤器替换前的路由URL串起来,如果想获取URL被替换为目标服务URL过程的变化,可获取该链表、遍历该链表。

// 记录修改前的url
addOriginalRequestUrl(exchange, url);
// 
public static void addOriginalRequestUrl(ServerWebExchange exchange, URI url) {
    exchange.getAttributes().computeIfAbsent(GATEWAY_ORIGINAL_REQUEST_URL_ATTR,
        s -> new LinkedHashSet<>());
    LinkedHashSet<URI> uris = exchange
        .getRequiredAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
    uris.add(url);
}

Gateway接收到一个请求后,请求从FilteringWebHandler传送到全局过滤器链上(GatewayFilterChain),在过滤器链上向下传递,经过中间过滤器将请求URL替换后,由最后的请求转发过滤器(ForwardRoutingFilter)将请求交给DispatcherHandler向目标服务发起请求并将结果响应给调用端。

在了解路由失效的原因后、在尝试依赖Ribbon的starter包依然路由失败后,笔者决定自己实现路由功能,并使用Ribbon实现的负载均衡算法在网关实现负载均衡。

由于项目是基于Spring Cloud Kubernetes开发的微服务项目,使用Kubernetes云原生服务作为“注册中心”,服务无需注册,可通过kubernete API读取Service或Endpoints资源,并且spring-cloud-kubernete-core提供了读取Service或Endpoints资源的API,因此自己实现路由功能相比于依赖一堆无关紧要的jar包更轻量。

负载均衡功能是次要的,如果不需要在网关实现负载均衡,则可以将服务发现模式改为Service,读取Kubernetes中的Service资源的Cluster IP;如果想要在网关实现负载均衡,而可以将服务发现模式改为Pod,读取Kubernetes的Endpoints资源。

自实现路由功能分为以下几个步骤:

  • 1、使用spring cloud kubernetes core提供访问kubernetes资源的客户端接口定时拉取服务目录缓存到本地;
  • 2、自实现负载均衡算法,或使用Ribbon的ribbon-loadbalancer包提供的负载均衡算法(IRule),每次路由根据算法从服务列表中选择一个节点调用;
  • 3、自定义实现理由功能的全局过滤器(GlobalFilter),指定该过滤器排在Gateway注册的非负载均衡过滤器之前,在它之前完成将url中的“lb://serviceId”替换为"http://ip:port"。

如果觉得本文对你有帮助,记得点个赞哟!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java艺术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档