# ApiGateWay **Repository Path**: hgh411/ApiGateWay ## Basic Information - **Project Name**: ApiGateWay - **Description**: 基于 Netty,Nacos,NacosConfig 开发的一款开箱即用的“微内核+插件”架构的 API 网关,可配置接口粒度的网关路由规则,可实时热更新路由规则。具有负载均衡, 多维度流,MOCK 模拟,灰度发布,多维度黑名单限制,短链系统,超时重试等功能。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 4 - **Created**: 2024-04-18 - **Last Updated**: 2024-04-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 1,项目介绍: 一款开箱即用的“微内核+插件”架构的 API 网关,可配置接口粒度的网关路由规则,可实时热更新路由规则。具有负载均衡,多维度限流,MOCK 模拟,灰度发布,多维度黑名单限制,短链系统,超时重试等功能。 ### 2,项目技术栈: Netty nacos-2.1.2 Disruptor SpringBoot相关扩展 JAVA SPI ### 3,项目架构 ![输入图片说明](https://foruda.gitee.com/images/1694880431453666357/74c876b8_10810312.png "屏幕截图") 1,各个下游服务在启动时会扫描各个controller,并且扫描controller里面各个接口,然后将接口对应的网关路由规则生成,最后写入配置中心。配置文件名称为URL-RULES- + 服务名 例如 URL-RULES-HDU-STUDENT。 2,各个下游服务在启动时会将该服务定义,服务实例注册到注册中心。 3,网关服务启动的时候,会从配置中心拉取各个下游服务器的网关路由规则配置文件,服务实例列表。 4,同时网关服务会监听配置中心各个下游服务器的网关路由规则的变化,并及时更新。同时也会监听各个下游服务器的服务列表变化,并及时更新 ### 4,一次请求经过网关的流程 ![输入图片说明](https://foruda.gitee.com/images/1694881302790917594/a684f977_10810312.png "屏幕截图") 1,请求首先会进入netty的handler处理过程,netty的会将其根据HTTP协议解析为HttpFullRequest,然后传进我们自己定义的NettyHttpServer 2,NettyHttpServer并不会继续处理我们的请求,而是将请求直接放入环形缓冲区即可。 - 2.1,这样做我们接收请求的上限并不会受限于Netty的woker线程,woker线程的职责只是负责将请求放入环形缓冲队列。接收请求的上限只受制于环形缓冲队列的大小。 - 2.2,Netty的boss线程组只负责处理连接事件,Netty的woker线程只负责将请求放入到环形缓冲队列,并不需要负责请求的后续处理流程,环形缓冲队列里面的消费线程将会负责请求的后续处理流程。这样的职责分离模式效率会更加的高,而且从某种程度上来讲也进行了解耦。 3,环形缓冲队列里面的消费线程会负责请求的后续处理流程,后续会进入过滤器链。 4,该网关的拦截器分为两种,一种是动态过滤器(并非每一个请求都会拥有,开发者可以根据自己的业务需求选择是否添加动态过滤器),必须过滤器(一些必须的过滤器,例如负载均衡过滤器,路由过滤器)。 5,该网关具有的功能有: - 短链系统(非默认过滤器,开发者只需在需要生成短链的接口方法上面添加@GenerateShortUrl注解即可自动生成短链。) - 多维度黑名单限制(非默认过滤器,现已实现根据IP限制,根据IP所属地限制,如果需要扩展,只需要SPI规范即可) - Mock模拟数据(非默认过滤器,开发者只需要在需要Mock模拟的接口上添加注解@Mock("this is mock value" , mock注解里面的值则会被请求时mock模拟返回给前端) - 热点参数限流(非默认过滤器,可针对某个接口的某个参数进行限流,当这个参数值多次相同的时候,就会触发限流策略。热点参数限流提供分布式/单机限流两种模式,底层采用令牌桶算法) - 快速失败限流(非默认过滤器,请求如果遭到限流,会直接返回。可配置针对IP,针对IP省份所属地,针对用户名等多维度限流,提供分布式/单机限流两种模式,底层采用滑动窗口算法) - 排队等待限流(非默认过滤器,一连很多请求进入该过滤器,过滤器以恒定的速率放过请求,其余的请求会进行排队,如果预估排队时间过长,会直接返回。底层采用漏桶算法) - 灰度发布(非默认过滤器,我们可以通过请求头gray字段设置为true,该请求即可被路由到灰度服务。同时也可能以一定概率路由到灰度服务(开发者可以自定义这个概率)) - 负载均衡过滤器(默认过滤器,提供了,随机,加权随机,轮询,加权轮询,平滑加权轮训,一致性哈希等负载均衡算法,开发者只需要在接口上添加注解@LoadBalance(balanceType) ,该接口即可采用对用的负载均衡策略) - 路由过滤器(默认过滤器,该过滤器会最后将请求发送给对应的下游服务,该过滤器还具有超时重试,熔断降级(待实现),等功能) ### 5,使用示例 ``` @GenerateShortLink @FailFastControl(controlType = FLOW_CTL_MODEL_SINGLETON, qps = 5, windowCount = 1) @RetryTimes(3) @LoadBalance(FilterConst.LOAD_BALANCE_STRATEGY_RANDOM) @Limit(value = {LimitType.IP}, ipConfig = {"127.0.0.1.1", "192.168.1.1.2"}) @Gray(2048) @GetMapping("/http-server/ping1") public String ping1() { return "pong1"; } 该接口的路由规则是: 1,会自动为其生成短链。 2,限流策略采用快速失败,1s内允许通过的最大请求为5次,采用的是单机限流。 3,该接口是一个灰度接口,除开强制指定访问灰度接口,那么普通请求将有1/2048的概率路由到该灰度接口。 4,该接口会对IP为"127.0.0.1.1", "192.168.1.1.2"的请求进行限制。 5,该接口最后采用的负载均衡算法是随机。 ``` ``` @GenerateShortLink @Limit(value = {LimitType.IP, LimitType.PROVINCE}, ipConfig = {"127.0.0.1.1", "192.168.1.1.2"}, provinceConfig = {"重庆", "四川"}) @Mock("this api is developing , this is the mockValue ! thanks!") @GetMapping("/http-server/ping1") public String ping1() { return "pong1"; } 该接口的路由规则是: 1,该接口会自动生成短链。 2,该接口会限制请求ip所属省份为 "重庆", "四川" 的请求。并且限制IP为 "127.0.0.1.1", "192.168.1.1.2" 的用户 3,如果顺利通过限制,该接口会mock模拟返回数据,返回的数据为 this api is developing , this is the mockValue ! thanks! ``` ``` @LoadBalance(value = "consistentHash", replicaNumber = 320, params = {"username"}) @HotParamControl(paramName = "username", windowCount = 20, qps = 2, controlType = FLOW_CTL_MODEL_DISTRIBUTED) @GetMapping("/http-server/ping1") public String ping1() { return "pong1"; } 该接口的路由规则是: 1,该接口会对 username这个参数进行热点参数限流,并且为分布式热点限流,20s内如果username的参数值相同, 那么就会被限制。例如 20s 内 两次请求的 username 都是 qyh , 那么第三次请求 username 还是 qyh的话,就会被限制 2,该接口采用的负载均衡算法是一致性哈希算法,每个服务实例生成的虚拟节点个数 是 320 ,会对username 做哈希运算,然后在哈希环计算得服务实例。 ``` ``` @QueueWaitControl(windowCount = 1 , qps = 5 , maxWaitTime = 2 , controlType = FLOW_CTL_MODEL_SINGLETON) @GetMapping("/http-server/ping1") public String ping1() { return "pong1"; } 该接口的路由规则是: 1,该接口采用排队等待限流方式,1s内会匀速放过5个请求,也就是说每200ms放过一个请求,最大等待时间为2s 也就是说如果某个请求前面有很多请求,该请求经过预估后发现等待时间超过了2s,那么就会被直接限制访问。 ``` ``` 最后,如果觉得添加在接口上面的注解过多。我们可以使用复合注解 @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @GenerateShortLink @Limit(value = {LimitType.IP, LimitType.PROVINCE}, ipConfig = {"127.0.0.1.1", "192.168.1.1.2"}, provinceConfig = {"重庆", "四川"}) @Mock("this api is developing , this is the mockValue ! thanks!") public @interface Ping1GateWayRule { } @Ping1GateWayRule @GetMapping("/http-server/ping1") public String ping1() { return "pong1"; } 这样就可以做到对一些网关路由规则的重用,还有接口也更加简洁。 ``` ### 6,项目一些亮点 - 项目采用了大量的设计模式,例如策略,模板方法,责任链,单例,工厂,组合,观察者,适配器,建造者模式等。 - 项目大量使用缓存,根据每个URL的网关路由规则,会缓存其各个对应的组件,例如这个URL对应的拦截器链,他如果有限流相关策略,则会缓存他的滑动窗口/令牌桶/漏桶等数据结构。同时考虑到网关路由规则会实时更新,项目中采用事件派发机制来应对内存规则和配置中心规则一致性。 - 项目使用无锁高性能消息队列 Disruptor 进行优化,得益于其消除缓存为共享,减少gc,采用cas等好的性能优化手段。 - 项目实现了“微内核+插件”的架构设计思想。网关所有组件,过滤器,限流器,负载均衡器,黑名单限制器等均可方便的进行扩展,增强,替换。内核只负责组装插件。 - 项目基于SpringMVC的组件,实现了自动化接口粒度网关路由规则生成,网关路由规则只需开发者显式地声明在接口上即可生效。 - 项目实现了多维度负载均衡器,例如随机,加权随机,轮询,加权轮询,平滑加权轮训,一致性哈希等负载均衡算法。如有需要还可以继续扩展。 - 实现多维度限流,单机/分布式两种模式,提供滑动窗口,令牌桶,漏桶等限流算法应对热点参数限流,快速失败,排队等待等不同场景。 - 基于 SpringBoot的扩展,利用自动装配,监听器等扩展为下游服务提供开箱即用的客户端依赖。使其可以自动注册服务,自动生成接口级别网关路由规则