一、引子
其实有点小小的标题党啦,毕竟相信各位读者对“高性能”的追求是永无止境的。但如果你确实有打算自研一套API网关,那么我认为了解构建它的基本组成和架构是很有必要的,本篇博客主要是围绕这些东西做一个整体的介绍。
二、基本概念
1.网关的作用
简单来说,网关就是客户端与后端服务沟通的桥梁。网关负责接收客户端发来的请求,并将它转发到相应的后端服务上进行处理。因此,网关可以承接来自外部的Http协议请求,并将其转换为服务内部的协议请求,比如dubbo、grpc等。另外,既然作为访问后端服务的入口,那么监控统计、熔断限流等等都可以实现。
2.请求的生命周期
从客户端的请求到服务端返回处理的结果,大致经过了以下流程:
3.功能点详解
- 执行各种插件
我们在上面的作用里提到的那些功能都是由一个一个插件提供的,比如协议转换插件、认证鉴权插件、黑白名单插件等,通过各种各样的插件构建了网关强大的功能。在实际场景里,我们也可以根据自己的业务需求去开发插件。
- 规则
一次请求根据业务需求不一定要执行全部的插件,所以就需要规则去定义某个请求需要执行哪些插件,访问哪些路径。
三、技术选型
1.基础架构
Java原生-这里可能有的读者就有疑问了,Java和高性能有点“冲突”吧,市面上现在主流的网关Java写的也没几个,上来就整个Java算怎么回事呢?
这里提一嘴我对技术选型的看法:性能是很重要,但是我觉得还有一个重要的考虑点就是团队的规模。假如说当前你们是个小团队,大家就是Java用的最熟练,老板短期内也不考虑继续招人。这个时候选择不熟悉的技术,那应该是当前工作量不饱和了。在我眼里,稳定 > 性能!
2.网络通信框架
Netty-这个没什么好说的,既然语言选择了Java,网络通信框架选择它就是毋庸置疑的,高性能 + 高可靠。
3.注册中心和配置中心
Nacos-注册中心和配置中心是网关几乎必备的功能,这里的单一选择都是非常多的,就不赘述了。我来说明选择Nacos的原因。一方面它支持Java,另一方方面它把两个功能都集成了,维护成本-1。当然,它的功能也很强大,例如动态服务发现、服务配置、服务共享与管理等等。
四、设计要点
1.异步化设计
通过对请求生命周期的分析,在该异步化的地方就做异步化处理是提高性能的关键。例如:请求转发、请求响应、插件过滤等。并且对于不同的事件还需要采取不同的异步模式,例如插件过滤采用异步阻塞模式、请求响应则采用异步非阻塞模式。
2.充分使用缓存
缓存可以说是优化性能的大杀器,大家在日常工作中肯定对于redis也是常伴身边,但网关这里的缓存我们尽量还是使用内存作为缓存更为合适,相应的数据结构可以用Map、Queue等。为什么不用redis呢?因为和任何中间件进行通信都有IO成本,对于追求高性能的我们当然是要规避的。
3.合理使用串行化
有的读者看到这里可能会困惑,串行化不是和高性能相矛盾吗?我要并行!但事无绝对,从场景出发,如果是耗时较小的一系列任务,我们采用并行的方式执行,频繁的上下文切换带来的成本可能远远大于任务本身的执行成本。所以,对于那些耗时较久、任务之间并没有直接依赖关系,例如RPC远程调用才更适合并行化。
4.提高吞吐量
提高吞吐量其实就是提升缓冲能力,在流量高峰期间使用本地缓冲,例如Disruptor、MPMC等。
5.合适的工作线程
根据任务的类型选择合适的工作线程:
- CPU密集型
配置公式:CPU核数+1
- IO密集型
配置公式1:CPU核数*2
配置公式2:CPU核数 / (1-阻塞系数) 通常0.8-0.9之间
五、架构图
通过对上述内容的总结,我们可以抽象出该网关的标准的架构图: