Netty+Nacos+Disruptor自研企业级API网关

385 阅读5分钟

Netty+Nacos+Disruptor自研企业级API网关

download: 3w ukoou com

吃透网关底层原理

为什么需要 API 网关 在 SpringBoot 单体架构中,一般只有一个后端服务,如下图所示:

单体架构访问示例图

但是在 SpringCloud 微服务架构中,往往有多个微服务,这些微服务可能部署在不同的机器上,而且一个微服务可能会扩容成多个相同的微服务,组成微服务集群。

微服务架构访问示例图

这种情况下,会存在如下问题:

如果需要添加鉴权功能,则需要对每个微服务进行改造。

如果需要对流量进行控制,则需要对每个微服务进行改造。

跨域问题,需要对每个微服务进行改造。

存在安全问题,每个微服务需要暴露自己的 Endpoint 给客户端。Endpoint 就是服务的访问地址 + 端口。比如下 灰度发布、动态路由需要对每个微服务进行改造。

这个问题的痛点是各个微服务都是一个入口,有没有办法统一入口呢?

解决这个问题的方式就是在客户端和服务器之间加个中间商就好了呀,只有中间商一个入口,这个中间商就是网关。 image.png

Netty+Nacos+Disruptor自研企业级API网关服务网关之Gateway

我们先要明白微服务解决了什么问题?大方面上应该就是应用层面和人层面的问题

  • 应用层面: 单体服务的架构很简单,项目开发和维护成本低是它无争议的优点。但是臃肿耦合又会给基础设施带来了过重的负担。如果某个应用处理资源占用了大量的CPU,就会导致其他处理资源饿死的现象,系统延迟增高,直接影响系统的可用性。
  • 人层面: 独立多语言生态 也是微服务的标签。在单体服务中,投入的人力资源越多不见得越高效,反而越容易出错。但微服务不同,每个服务都是独立出来的,团队可以更加容易的协作开发,甚至一套系统,多个服务,多种语言,毫无冲突。

① 路由判断;客户端的请求到达网关后,先经过 Gateway Handler Mapping 处理,这里面会做断言(Predicate)判断,看下符合哪个路由规则,这个路由映射后端的某个服务。

② 请求过滤:然后请求到达 Gateway Web Handler,这里面有很多过滤器,组成过滤器链(Filter Chain),这些过滤器可以对请求进行拦截和修改,比如添加请求头、参数校验等等,有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-Filters,Pre 可以理解为“在...之前”。

③ 服务处理:后端服务会对请求进行处理。

④ 响应过滤: 后端处理完结果后,返回给 Gateway 的过滤器再次做处理,逻辑上可以称作 Post-Filters,Post 可以理解为“在...之后”。

⑤ 响应返回:响应经过过滤处理后,返回给客户端。

小结:客户端的请求先通过匹配规则找到合适的路由,就能映射到具体的服务。然后请求经过过滤器处理后转发给具体的服务,服务处理后,再次经过过滤器处理,最后返回给客户端。

1. Gateway 依赖

最关键的一步便是引入网关的依赖

<!--gateway网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
复制代码
2. 项目结构

我这里简单的创建了一个微服务项目,项目里有一个 store-gateway 服务网关 和一个 store-order 订单服务。因为我们这篇只说明服务网关的作用,不需要太多服务提供者和消费者!

store-order订单服务中只有一个控制器OrderController,里面也只有一个简单到发指的API

@RestController
@RequestMapping("order")
public class OrderController {
    
    @GetMapping("/{id:.+}")
    public String detail(@PathVariable String id) {
        return StringUtils.join("获取到了ID为", id, "的商品");
    }
    
}
复制代码

我们分别启动两个服务,然后访问订单服务的API:

结果肯定是符合预期的,不至于翻车。8001 是订单服务的接口,这个时候我们可以了解到,原来微服务架构每个服务独立启动,都是可以独立访问的,也就相当于传统的单体服务。

我们想想看,如果用端口来区分每个服务,是否也可以达到微服务的效果?理论上好像是可以的,但是如果成百上千个服务呢?端口爆炸,维护爆炸,治理爆炸... 不说别的,心态直接爆炸了!这个时候我们就想着如果只用统一的一个端口访问各个服务,那该多好!端口一致,路由前缀不一致,通过路由前缀来区分服务,这种方式将我们带入了服务网关的场景。是的,这里就说到了服务网关的功能之一 --- 路由转发

Netty+Nacos+Disruptor自研企业级API网关Spring Cloud Gateway 的断言

断言(Predicate)这个词听起来极其深奥,它是一种编程术语,我们生活中根本就不会用它。说白了它就是对一个表达式进行 if 判断,结果为真或假,如果为真则做这件事,否则做那件事。

在 Gateway 中,如果客户端发送的请求满足了断言的条件,则映射到指定的路由器,就能转发到指定的服务上进行处理。

断言配置的示例如下,配置了两个路由规则,有一个 predicates 断言配置,当请求 url 中包含 api/thirdparty,就匹配到了第一个路由 route_thirdparty。(代码示例来自我的开源项目 PassJava)