Skip to content
字数
7958 字
阅读时间
29 分钟

高性能网关需求分析

系统功能性需求

功能性需求规定开发人员在产品中根据需要实现的软件功能来完成任务,满足业务需求。

  1. Netty服务端模块:网关需要处理大量并发连接,确保高性能和低延迟。服务端需要支持异步通信,以提高吞吐量,Netty服务端模块负责处理客户端的请求,进行数据的接收和响应。它保证了数据传输的可靠性和高效性,是整个网关的入口点。
  2. Netty客户端模块:使用Netty客户端模块来进行异步请求构建。这个模块是网关向外部服务发起交互的关键部分。
  3. 网关注册中心模块:对网关进行服务动态注册和发现服务实例,支持健康检查和服务下线通知,通过注册中心模块,网关能够实时获取可用的服务实例列表,提高服务的可用性和可靠性。
  4. 网关配置中心模块:提供统一的配置管理,支持动态配置更新同步,配置中心模块用于管理网关的配置信息,支持动态调整配置以适应不同的业务需求,确保网关配置的一致性和可维护性。
  5. 网关负载均衡过滤器模块:提供多种负载均衡算法,确保请求流量的合理分配,通过负载均衡过滤器,网关能够将请求均匀地分配到多个服务实例上,防止某个实例过载,提高系统的整体性能和稳定性。
  6. 网关路由过滤器模块:基于HTTP方法、请求头等条件的路由,路由过滤器模块根据负载均衡获取到的实例进行请求转发,确保请求能够准确地到达目标服务,支持灵活的路由策略和精细化的流量管理。
  7. 网关限流过滤器模块:通过固定窗口限流算法对请求进行限流,防止系统过载,限流过滤器模块进行控制请求数量,保护后端服务免受大规模请求的冲击,确保系统的稳定运行。
  8. 网关熔断降级模块:实现熔断器机制,当某个服务出现故障或响应时间过长时,自动进行熔断和降级处理,通过熔断和服务降级过滤器,网关能够快速响应进行熔断,避免故障蔓延,提升系统的容错能力和用户体验。
  9. 网关鉴权器模块:使用JWT对请求进行身份验证和权限校验,保证鉴权过滤器模块只有合法用户才能访问服务,保护系统的安全性和数据的完整性。
  10. 网关灰度发布模块:支持灰度发布策略,根据请求是否为灰度发布请求进行将流量分配到灰度服务上面,通过选取一部分请求来进行降低新版本发布的风险,提高系统的稳定性和用户体验。
  11. 网关接口Mock模块:测试环境下模拟服务响应,用于开发和测试,通过Mock模块,可以进行模拟根据设定好的请求路径来进行响应提前设定好的值,进行功能测试和故障排除,确保网关的正确性和稳定性。
  12. 网关日志和缓存优化模块:提供完善的日志记录,支持日志的实时分析,快速定位问题和优化性能,提升系统的可维护性和运行效率。

系统可行性需求

技术可行性: 分析 Netty 是一个高性能的网络应用框架,通过Netty 框架的高性能与低延迟,可以进行设计用于快速开发可维护的高性能网关。根据Netty的非阻塞I/O模型和事件驱动架构能够有效减少网络延迟,提高吞吐量,并且还具有扩展性和灵活性。使用了Nacos作为注册中心进行服务注册与服务实例发现,Nacos还可以进行动态配置管理,通过Nacos的配置管理功能,可以实现配置的动态更新,提高系统的灵活性和可维护性。

系统非功能性需求分析

  1. 性能需求:使用 Netty 进行异步网络编程,Netty 是一个高性能的网络应用程序框架,能够处理大量的并发连接。Netty 的非阻塞 IO 机制使其在处理高并发请求时表现优越,适用于需要高吞吐量和低延迟的应用场景。此外,为了提升性能,可以使用 Caffeine 作为本地缓存。Caffeine 是一个高性能的本地缓存库,适用于短期缓存,提升系统响应速度。
  2. 安全性需求:使用JWT 能够安全地传递用户身份信息,并在客户端和服务器之间传递认证和授权数据。通过使用 JWT进行网关鉴权,提高了系统的安全性。
  3. 扩展性需求:通过Java SPI机制进行加载新模块。Java SPI 是一种服务提供者接口机制,允许应用程序在运行时动态地发现和加载服务实现。通过这种方式,可以轻松地添加新功能或替换现有模块,而无需修改核心代码,保持系统的高扩展性和灵活性。

系统架构

系统架构可以使得代码的重用性更高,因为它将组件之间的依赖性分离并且将每个组件的职责和功能进行了明确定义。系统架构是一个软件系统的基石,确保了其质量性、可维护性、可扩展性和可用性。设计出合理的系统架构,有助于进一步分析和优化系统性能和减少开发成本和时间,发现并解决潜在问题,提高开发效率和准确性,方便后期扩展和修改。

针对网关功能进行分解,可以将网关分为网络通信板块服务注册统一配置板块请求过滤器链板块这四个方面进行构建。

  1. 通信模块使用Netty进行开发,Netty是基于Java的异步事件驱动的网络应用框架,用于快速开发高性能、高可靠性的网关。
  2. 注册中心允许网关动态地发现和调用服务,每个服务启动时,会将自己的地址和端口信息注册到注册中心,网关可以根据这些信息路由请求到正确的实例,注册中心也可以帮助网关实现负载均衡。网关可以从注册中心获取所有可用的服务实例,并将请求分配给其中一个实例,从而实现负载均衡,当某个服务实例不可用时,注册中心可以通知网关,从而实现故障转移,使得网关可以重新路由请求到其他可用的实例,当新的服务实例上线或下线时,注册中心会更新注册信息。
  3. 配置中心可以将一些网关需要用到的参数进行配置,然后可以在网关进行处理请求的时候,从配置中心进行拿到需要的参数。
  4. 请求过滤器模块,则是主要包括了负载均衡过滤器,路由转发过滤器,请求限流过滤器,熔断降级过滤器,用户鉴权过滤器,灰度发布过滤器,接口模拟过滤器,当网关请求进入的时候,通过负载均衡过滤器选取合适的后端服务,并且通过限流过滤器进行限制请求的数量,防止后端服务压力过大,对于一些请求,在必要的时候会主动进行熔断降级,让网关资源先支持核心模块使用,然后在请求进入的时候会鉴权来进行判断是否是合法的请求,通过鉴权校验后才可以进行正常的访问资源,然后会进行判断请求是否灰度请求来进行执行灰度过滤器,针对一些前端的请求,当后端还没有实现功能的时候,可以先返回一些提前设定好的数据给前端,通过接口模拟过滤器进行实现将提前定好的数据返回,最后通过路由过滤器进行请求转发,将数据写回前端。根据上面对系统架构的分析,得到下图作为系统的整体架构结构图。 请求过滤器链分为负载均衡过滤器、路由转发过滤器、请求限流过滤器、熔断降级过滤器、用户鉴权过滤器、灰度发布过滤器、接口模拟过滤器这几个部分。 网络通信使用Netty进行开发,所以分为Netty客户端和Netty服务端这两部分。 服务注册和配置,会将自己的地址和端口信息注册到注册中心,以及将进行配置一些信息进行请求过滤器链构建,所以分为注册中心和配置中心。

网关通信设计

Netty客户端设计

Netty客户端在网关中的主要功能是启动网关的时候会通过异步客户端构建器进行创建和管理基于Netty的异步HTTP客户端,进行设置事件循环组的个数,设置连接超时事件,设置请求超时时间,设置最大重定向次数以及设置最大的连接数,最后创建出AsyncHttpClien异步HTTP客户端,然后创建出的这个异步HTTP客户端的配置将会等待路由转发过滤器进行请求转发,并且还提供了start()方法进行启动客户端,进行初始客户端模块,进行请求转发的准备,最后发送完毕后,可以进行关闭客户端释放资源。

Netty服务端设计

Netty服务端在网关中的主要功能是启动网关的时候进行监控绑定配置的端口,然后根据请求构建网关请求上下文和执行过滤器链,具体设计如下:

  1. ServerBootstrap模块设计:负责进行配置和启动服务器的Netty ServerBootstrap对象,通过传入事件循环对象,进行配置请求的服务器参数,进行建立服务器端的套接字通道,以及使用编解码器进行数据编码,将请求报文聚合成FullHttpRequest类型,然后启动服务器。
  2. **Netty服务器的处理器模块设计**:负责将请求进行处理,将请求的信息msg和通道上下文ctx封装为对象传递进入执行请求的逻辑模块,在执行请求的逻辑块中,进行构建网关请求上下文和执行过滤器链用于处理请求。

配置中心和注册中心设计

配置中心设计

Nacos提供了许多强大的功能,其中一个就是Nacos提供了可视化的控制台方便进行可视化管理。Nacos提供了动态配置服务,可以通过动态化的方式管理网关需要用到的配置参数,并且Nacos的社区非常活跃,代码也更加容易阅读,所以选择使用Nacos作为配置中心,具体设计如下:

  1. 配置中心接口设计:定义一个配置中心接口来初始化配置中心的配置和进行配置中心信息变更的监听,然后传入配置中心地址和环境进行初始化,当配置中心的配置变更的时候将进行实时监听变更的配置。
  2. 配置拉取实现:进行了配置中心接口的定义后,需要进行配置的拉取,先需要进行引入Nacos的Client,然后可以通过Nacos提供的configService,通过这个类的方法根据DataId和Group就可以进行快速的拉取Nacos设置的配置,然后进行解析获取到配置,转换为自定义的数据。
  3. **配置变更事件订阅设计**:当配置进行变更的时候需要进行订阅,使用Nacos提供的configService的addListener方法通过在网关配置的DataId和Group的参数将会向Nacos的监听器列表中添加一个监听器,当Nacos的配置发生变更之后,就可以监听到这个事件,并且将配置进行更新。

注册中心设计

Nacos提供了许多强大的功能,其中一个就是Nacos提供了一个可视化的控制台进行可视化管理。Nacos提供对服务的实时的服务发现和服务注册。并且Nacos的社区非常活跃,代码也更加容易阅读,所以选择使用Nacos作为注册中心,实现了配置中心和注册中心的统一操作,提高了开发效率。具体设计如下:

  1. 注册中心接口设计:定义一个注册中心接口,进行定义服务初始化方法,服务注册方法,取消服务注册方法,服务订阅方法,通过这个接口,可以进行实现了服务的初始化,注册,取消注册以及服务变更的监控。
  2. 服务信息加载设计:基于上面的注册中心接口,进行封装服务定义和服务实例,通过封装的服务定义和服务实例,作为参数传入服务初始化方法、服务注册方法和订阅事件变更方法。
  3. 实现将网关注册到注册中心:服务注册方法设计中,使用Nacos客户端提供的NamingMaintainFactory和NamingFactory这两个服务注册的方法向传入的服务定义和服务实例这两个参数进行注册服务定义和服务实例到Nacos中。
  4. **实现服务的订阅**:实现服务订阅,首先需要拉取Nacos上面的所有的服务的信息,由于服务信息会不断的更新变化,所以进行设计了使用定时任务的方式不断的更新服务订阅信息。 实现对Nacos服务信息的订阅的时候,通过Nacos的事件监听器NamingEven事件对象进行监听服务变化,可以根据这些变化来动态的更新服务实例列表,如果服务发生了改变,就进行更新服务定义和服务实例,保持与注册中心的数据同步。

请求过滤器链条的设计

过滤器链的设计思想

通过责任链模式进行设计一个过滤器链,提高网关的可扩展性和维护性,因为每个过滤器执行的顺序不一样,所以在设计过滤器链的基础需要进行设计成一个有序的过滤器链,过滤器链是由多个过滤器组成的,通过过滤器链实现每个过滤器都可以根据自身规则和顺序进行处理请求,一个过滤器执行完毕过滤流程之后,就会根据定义的执行顺序转发该请求到下一个过滤器继续执行,从而完成对请求和响应的处理。具体设计如下:

  1. 过滤器顶级接口设计:过滤器顶级接口设计,进行定义执行过滤器链的doFilter方法和返回过滤器顺序的getOrder()方法。通过这两个方法进行设计后续过滤器。
  2. GatewayContext的构建:每个请求的信息都会被封装到GatewayContext中,通过这个网关上下文内定义的参数进行构建过滤器链。
  3. 过滤器链工厂:因为每个不同的请求都可能触发不同的过滤器链规则,所以需定义一个过滤器链工厂接口,这个接口定义了构建过滤器链条和通过过滤器ID获取过滤器这两个方法,通过对过滤器链工厂的实现为每个不同的请求生成特定的过滤器链。 通过上面可以设计出一个有序执行的过滤器链。

负载均衡算法设计

网关的请求转发到后端服务的时候,可能会出现单一服务压力过大的情况,所以需要进行负载均衡,将请求按照实现的负载均衡算法进行转发,达到将请求分散到各个服务,因此设计了一个负载均衡过滤器,具体设计如下:

  1. 负载均衡接口的设计:创建负载均衡接口,进行定义通过由请求构建的网关上下文拿到对应的服务实例方法和通过服务ID拿到服务实例这两个方法,获取根据负载均衡策略选择到的后端服务实例。
  2. 轮询的负载均衡算法设计:对于实现轮询的负载均衡算法,需要维护一个线程安全的全局的索引编号,起始数值设置为1,并且每次执行都不断自增,然后对服务实例数量进行取余,这样就实现了轮询获取后端服务实例。
  3. **随机的负载均衡算法设计**:实现随机的负载均衡算法, 需要根据得到的服务id,然后进行保存当前服务id对应的所有服务实例,最后从服务实例中随机返回一个即可。

路由转发设计

路由转发是在网关处理完所有过滤逻辑后的最后操作,可以进行请求的修改,可以进行修改请求的各个部分,包括请求头、请求体、请求参数等,进行适应目标服务的要求,实现请求路由的动态性,具体设计如下:

  1. 请求转发:使用的异步的方式去发送http请求,通过Netty配合AsyncHttpClient的方式来实现的异步IO通信功能,最后执行负载均衡策略将请求转发到后端服务,以确保请求均匀的分发到不同的服务实例。
  2. **请求重试**:当请求出现IO异常或者请求超时的时候会进行请求重试,所以在路由过滤器中会添加一个重试的函数进行再次执行路由过滤器, 每当出现IO异常或者请求超时的时候都会再次调用重试函数,然后重试次数可以从配置中心进行获取,通过配置中心获取得到的值来进行设定重试的次数。 根据上面的详细设计,可以设计出路由过滤器。

请求限流设计

网关限流设计中,对于限流这一块,需要在配置中心配置限流需要的参数,如限流时间,限流时间内的限流次数,以及限流的路径参数配置,进行灵活的配置限流规则,通过配置中心根据路径进行限流。具体设计如下:

  1. 设计一个限流接口:创建一个限流通用接口,定义根据拿到配置中心限流的规则和服务ID这两个方法,进行执行限流规则的方法。
  2. 根据路径进行限流:根据请求获取对应的限流规则,获取到指定的限流规则之后,根据路径进行限流,每当对应的请求到来时,就从缓存根据路径中获取对应的限流规则,如果能够获取到,说明存在限流,就开始进行限流逻辑,设定限流时间和次数使用Redis进行限流。
  3. 基于Redis实现固定窗口限流算法:根据获取到的限流规则,可以得到限流时间和次数,通过引入Redis里面的Jedis来进行操作,创建出一个JedisPoolConfig实例,用于配置连接池参数,进行设置连接池的最大连接数,设置连接池的最大空闲连接数,创建JedisPool实例,连接redis连接池,最后调用jedis的evalsha方法,传入执行的redis的代码和限流时间以及次数,最后实现固定窗口限流策略。

熔断降级设计

网关项目使用的是基于Hystrix的熔断降级,需要将服务整合Hystrix,引入依赖之后,进行使用Hystrix编写熔断限流,需要在配置中心的配置中添加出Hystrix的配置,分别是熔断请求超时时间,熔断降级触发熔断返回的值,以及熔断降级触发的路径等。熔断降级具体设计如下:

  1. 熔断逻辑设计:因为执行逻辑是走过滤器的,所以过滤器链的路由过滤器中添加额外的对Hystrix的配置,来监测最后转发请求的时候,如果请求路径是是设置的熔断降级触发的路径,需要进行设置熔断超时时间参数,如果超时后就进行熔断,执行降级逻辑,如果路径不是熔断降级触发的路径,则正常进行执行请求转发逻辑。
  2. 实现降级逻辑:如果请求的时间超过设置的熔断时间就会执行熔断,进入Hystrix降级逻辑方法,在降级逻辑中,设计的网关降级逻辑就是直接将数据返回客户端进行提醒“用户请求不可用,请稍后重试”。

用户鉴权设计

网关作为应用程序的单一入口点,所有请求都经过网关,因此在网关中进行验证和授权用户的时候可以确保所有请求都受到相同的安全策略,所以需要进行网关鉴权的设计,具体设计如下:

  1. 正常鉴权流程
    1. 客户端携带令牌访问资源服务获取资源。
    2. 资源服务远程请求认证服务校验令牌的合法性。
    3. 如果令牌合法,资源服务向客户端返回资源。
  2. 使用JWT进行鉴权优化:如果使用这个正常鉴权流程进行网关鉴权,会导致性能降低,当每次客户端访问的时候都会进行一次远程校验令牌,执行性能较低。如果资源服务可以自主校验令牌的合法性,就可以省去远程请求认证服务的成本,提高性能。 这里使用JWT鉴权解决这个问题,用户认证通过后会得到一个JWT令牌,JWT令牌中包括了用户相关的信息,客户端只需携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务。 用户首先请求用户登录接口的时候可以获取JWT的token信息,并将token信息写入到请求头中。之后,当请求其他需要使用token信息的接口时,并且验证 Cookie 中的身份信息,从而实现客户端的身份验证的时候。可以从请求头中获取当前的用户信息。

灰度发布设计

在灰度发布中,新版本的后端服务不会一次性全部暴露给所有用户,而是逐渐引入一小部分用户,然后根据观察结果决定是否需要继续推广新版本,还是需要进行回滚到旧版本,在网关层面进行实现灰度发布,具体设计如下:

  1. 判断请求是否为灰度发布:网关请求进入后需要判断当前请求是否为灰度发布后的版本,可以通过在请求头中设定一个 gray 字段,如果该字段为 true,则表示当前请求为灰度发布的版本,如果请求头的gray不为true,就进行选择一部分请求进行灰度发布,具体实现方式是使用一个简单的哈希计算方法来判断当前请求是否属于灰度流量。如果当前请求是灰度流量,但没有可用的灰度实例,那么就无法选取具体服务进行负载均衡,系统将报错,否则选择在灰度发布的服务内进行执行。
  2. 灰度发布后的后端服务整合:如果确定了当前请求是灰度发布的请求,将这个请求传递下去,并在网关核心上下文中设置当前请求为灰度发布的请求,最后在负载均衡选择后端服务的时候,只在有灰度发布标识的服务中进行选取。

接口模拟设计

在网关层面设计接口mock。mock(模拟)是一种测试技术,如果在前端开发的过程中,需要后端数据,但是如果后端服务还没有实现,可以进行mock,将提前定义好的数据返回给前端,不影响前端开发进度,可以大大提高开发效率,具体设计如下:

  1. mock触发逻辑:通过在配置中心进行配置,根据路径的触发mock,如果网关进行的请求是配置中心设定的触发mock路径参数,则直接触发mock,将提前封装好的数据写回客户端。
  2. 模拟数据写回客户端 通过在配置中心,可以进行设置触发路径,当路径触发mock逻辑的时候,返回在配置中心设置好的响应值返回给客户端。

日志模块设计

网关需要日志记录是为了当系统出现问题或故障时,日志记录可以帮助快速定位和解决问题。通过查看日志,可以了解系统在发生问题之前和之后的状态,确定导致问题的原因,所以对于一个网关,日志是必须的一个组成部分,具体设计如下:

  1. 控制台日志输出配置:采取Log4j日志框架,需要在Log4j2.xml配置文件中进行配置,设置日志的时间,日志级别,线程名称,类名,日志内容,换行符这些功能,最后实现将日志打印到控制台。
  2. **访问日志输出配置**:通过Log4j2.xml配置,将访问日志设计为日志的时间,执行耗时,客户端ip,请求服务 http名字,http路径,http返回状态码和http返回报文大小这些功能,可以在网关需要记录日志的地方进行日志采集然后输出到文件。 根据上面的详细设计,可以设计出日志模块。

本章小结

分析了基于Netty实现的高性能网关在技术上的可行性,依靠其高性能非阻塞I/O模型、事件驱动架构和丰富的扩展能力,结合Nacos服务管理处理来确保系统性能和稳定性,经济上,通过利用开源技术和社区支持,显著降低开发和维护成本,系统功能需求涵盖了从高并发连接管理、动态配置,路由与过滤规则到负载均衡、限流、熔断、鉴权等模块,非功能需求强调性能,安全性,扩展性和高可用性,使用Caffeine缓存和设计插件架构等手段来进行性能优化,本章先进行项目的总体设计,然后进行了系统架构的设计,网关通信层的设计,网关配置中心和注册中心的设计,网关规则的设计,网关过滤器链的设计,网关负载均衡算法的设计,网关路由的设计,网关重试和限流的设计,网关熔断降级的设计,网关鉴权的设计,网关灰度发布的设计,网关接口mock的设计以及最后的网关日志设计,通过设计这些有效的,可靠的和高性能的功能模块,确保了网关流程的逻辑正确性和效率,使网关实现功能过程变得高效、可靠、灵活和可管理。

贡献者

The avatar of contributor named as breatheCoder breatheCoder

文件历史

撰写