微服务网关的产生背景
当我们系统复杂度越来越高,团队协作效率越来越低时,我们通常会想到通过"拆分"来应对,这是典型的"化繁为简,分而治之"的思想。在落地过程中,我们通常会引入"SOA"或者"微服务"架构手段,如下图所示:
技术更新日新月异,站在当下去看,"微服务"、"API网关"、"云原生"、"service mesh"...这些早已不是什么新鲜概念。但只有完整经历过架构演进,才能倒出其中缘由,因为架构演进并非一蹴而就的。
时光回到2014年,很多公司在忙着对遗留系统做"前后端分离"和"服务化拆分",不管是追潮流,还是真解决问题,反正很多公司都在这么干。架构大概是这个样子的:
简单描述一下,这里的Web Server通常是我们熟悉的Nginx,它承担了2个职责。第一,作为反向代理和七层负载均衡器,负责将浏览器或者APP端的请求转发到指定的后端服务中。第二,它也作为前端静态站的Web容器。
这个架构有很多问题,典型的问题如下:
- 端上直接请求后端服务,强耦合,如果后端服务做字段修改了很可能会影响到端上
- 客户端需要多次请求服务,完成一个页面的渲染
- 很多通用的逻辑没有收敛,比如:用户身份验证,所以你可能在服务上面看到各种Filter、切面
- ...
为了解决上面这些问题,所以很多公司又引入了一个中间层。这也再次印证了那句话--在计算机系统的世界里,没有问题是不能通过引入"第三者"解决的。架构如下:
这一层中间层,用现在流行的叫法叫做"BFF"。有些公司可能会是前端同学通过Node.js来实现,也有些是后端同学来实现的。当然,由于我主导的很多系统都经历过单体(前后端不分离)、前后端分离、网站应用垂直拆分、无线化、开放平台、SOA服务化(服务下沉)等演进历程。在SOA改造的过程中,本质上我们是通过服务下沉的方式,把一些共享的能力做接口抽象和复用,自然也有保留一套或者多套比较薄的Web应用做中间层,去接收前端和APP端的请求,做一些字段裁剪、接口响应内容的拼接等等。所以,我并没有踩过上面的坑。因为每一步演进都是为了解决真问题,所以也很自然。那个时候我没有关注什么"微服务"、"BFF"之类的概念,只不过解法和套路都是类似的。
但是呢。因为团队越来越大,业务越来越多,这种"中间层"应用也越来越多,大概成了这个样子:
在这些中间层应用里面,同样还是存在一些重复的逻辑没有收敛,典型的如下:
- 请求身份验证,鉴权等
- 切面的日志打印,QPS和耗时统计等
- 请求的限流、熔断等
既然要解决这些问题,把一些非业务属性且公共的逻辑剥离出来,那很自然的会想到"在BFF的前面再加一层"。这也就是我们今天要介绍的"API网关",或者叫"微服务网关"。
当然,这个图里面省去了最前面的DNS/CDN/GSLB,LVS/HAProxy/Nginx等网络接入和负载均衡等细节。
简单总结一下网关的职责:
- 请求流量的路由转发、负载均衡
- 安全验证(身份认证、请求鉴权等)
- 限流、熔断
- 日志、指标度量等
- 协议适配
- 请求缓存
- ...
微服务网关的生态
Java社区的微服务网关
在很长的一段时间里,Java社区的微服务网关主要由Spring Cloud生态来提供,所以选择也不多。
这两者,可以满足一般中小型公司的业务场景和需求,但是他们存在一些共同的问题:
- 缺少动态配置和动态更新能力,需要整合配置中心做二次开发
- 缺少可视化的操作和维护界面。无论是从体验还是从效率的角度来看,可视化都非常重要
- 缺少限流、降级,日志、监控等完整的方案,需要各种整合和二次开发
- 缺少协议转换的能力,后端服务如果是直接通过RPC协议暴露的则无法被前端访问
- ...
Nginx/OpenResty体系的网关
Nginx算是网关吗?回答这个问题之前我们先仔细想想,Nginx的职责和功能和我们上面说的网关好像是有一些重叠的。例如:请求转发、负载均衡、限流(借助模块)、安全认证等等。基于Nginx/Openresty生态衍生出来的,比较具有代表意义的主要有老牌的Kong,以及近两年比较火的APISIX这两款。详细对比如下:
从广义上来讲,Nginx/Openresty也是网关,这个并没有权威的定义。通常,我们可以把网关又细分为:
流量网关,顾名思义就是控制流量进入集群的网关。
业务网关,更加贴合业务服务的,也就是我们说的微服务网关。
当然,这两者并没有绝对的界限。所以,通常我们在实际应用场景中都是搭配使用的。
云原生网关
进入云原生时代之后,Kubernetes 已经成为了云原生应用底座的事实标准。而我们要想应用暴露给外部访问,首先绕不开的就是Ingress 控制器。
上面这张图比较老,大概是2021年前后的。Ingress和云原生API GATEWAY这个市场的玩家特别多,还包括Service Mesh数据面事实标准Envoy推出的Envoy Gateway**,**最近比较火的阿里云基于Envoy改造的Higress,以及淘系基于Tengine改造的Tengine-Ingress等等。
为什么推荐你直接使用Apache shenyu
Apache shenyu的特性包含:
- 请求代理:支持Apache Dubbo,Spring Cloud,gRPC,Motan,SOFA,TARS,WebSocket,MQTT等协议的转换
- 安全性:签名,OAuth 2.0,JWT插件,WAF插件
- API治理:请求、响应、参数映射、限流熔断、流量灰度、接口文档
- 可观测性:跟踪、指标、日志记录插件
- 仪表板:动态流量控制,可视化操作
- 高性能:基于Netty,纯异步非阻塞模式
- 高扩展:插件机制,热插拔,SPI按需动态加载
- 热更新:数据实时同步,无需重启集群
- 集群:NGINX、Docker、Kubernetes
- 语言:提供.NET,Python,Go,Java客户端用于API注册
- 开箱即用:功能丰富稳定,开箱即用,简单添加引用就能接入,几乎没有业务侵入性和接入成本
- 生态友好:目前已集成常见的中间件,包括服务框架、限流熔断、服务发现、配置中心等。目前也在积极拥抱云原生
- 社区活跃:Apache顶级项目,目前社区有来自全球贡献者超过300名,github star超过8K,据观察几乎每天都有代码提交更新和PR合并动作。社区活跃程度**是选择开源软件的首要考虑项 **
更多信息,请参考Apache shenyu网站和github主页:
https://github.com/apache/shenyu** ,**https://shenyu.apache.org/zh/docs/index
如果你们公司系统是Java体系的,对功能、性能、扩展性等方面又比较有追求,但又没有自研能力和时间,那我推荐你直接使用Apache shenyu 来做微服务网关,几乎满足绝大部分公司对网关的诉求。
为什么我不推荐你单独使用云原生网关?
这些云原生网关确实都很优秀,有很多吸引人的特性,甚至时不时有"取代传统微服务网关"的声音。但是,优秀的未必就适合你,简单总结有如下原因:
- 云原生已经普及了好几年,大部分公司的应用系统也都逐渐跑在了Kubernetes之上。但是,大部分公司的应用还是基于Dubbo/Spring Cloud + ZK/Nacos/Consul这种传统的微服务架构,并非天生就是基于Kubernetes的Service体系构建的,也不是直接基于Service Mesh体系来构建的。所以,云原生网关目前对你来说还是属于那种看起来或者听起来很美好,独立使用又发挥不出它的全部价值来。
- 这些网关普遍对Java开发人员并不友好。比如,Nginx和Openresty体系,很多时候借助Nginx模块(C代码)和Lua脚本来实现扩展的,这对使用者来说是有一定门槛的。Envoy体系是基于C++来实现的。当然,为了解决这些痛点问题,最新的这些云原生网关厂商也在积极拥抱WASM生态,试图降低开发者扩展的门槛,不过WASM目前对Java的支持并不友好。所以,无论是想开发插件扩展,还是想进行深度的二次开发定制,门槛都不低,这也会让你十分难受。
- 太新的技术,生态可能还不够完善,各方面成熟度还有待验证,不推荐轻易在生产直接使用
- 取代微服务网关,这有点言之过早。目前我更推荐搭配使用,各司其职。10多年前Nginx流行的时候很多人绝对LVS要完了,但到现在IPVS也还在内核中。Spring Cloud刚开源的时候业内很多人也在唱衰Dubbo,Service Mesh出现的时候也被认为是颠覆性的二代微服务架构。
总结
本文先从微服务网关的诞生背景出发,带读者重新温习了一下近些年互联网公司中普遍的架构演进的过程。然后重点介绍了传统的微服务网关,传统的流量网关,以及面向云原生的Ingress控制器和API网关。
最后,重点介绍了一下Apache shenyu的特性,以及为什么我不推荐你单独使用那些云原生网关。当然,水平有限,也纯属一家之言,也欢迎读者在留言区交流和留言讨论。