微保API网关的探索与实践
Posted 微保技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微保API网关的探索与实践相关的知识,希望对你有一定的参考价值。
简介
随着微服务架构的日渐推广和普及,以API网关作为微服务统一入口的模式逐渐为人熟知。处在网络边界上的API网关,一方面,可以承担外网服务所需要的通用、非业务类功能,如:鉴权,监控,服务发现/注册,负载均衡等等;另一方面,可以自然地形成对服务和API的运营管理,实现发布,监控,管理,运营的自动化。
如今,微保API网关经过三个阶段的架构演进,已支撑服务于小程序、html5页面、第三合作方等终端,并逐渐成为C端后台服务的统一入口。下文将详细介绍微保API网关三阶段演进的探索和实践。
01
第一阶段:HAProxy
成立伊始,团队面临比较大的业务开发压力,选择了常见的成熟接入方案,通过原生的HAProxy的运营方案,为后端服务提供简单的负载均衡和路由转发,简单稳定。
(图1 第一阶段拓扑)
02
第二阶段:自研API网关
经过一段时间的发展,越来越多的基础功能需要被抽象,集中到一个统一的入口上,网关是天然的选择。但是,基于功能较为单一的开源方案,一方面,不方便进行自研功能的扩展,导致业务以库的形式各自实现,重复建设,版本碎片化严重,更新升级困难;另一方面,随着业务的壮大和发展,新老业务服务更迭,频繁的接口发布和服务上下线,日渐成为常态,开源组件羸弱的运营能力日渐无法支持。
(图 2自研网关逻辑架构)
针对这样的情况,经过调研和设计,我们决定使用Go语言启动自研API网关。在这一阶段主要解决的问题集中在三个重点:
1)剥离鉴权、跨域、用户权限等功能,下沉到API网关
2)结合团队当前技术方案,实现基于服务发现的路由转发和负载均衡
3)实现gRPC与JSON协议之间的协议转换
实现1和2是为了使当前的通用技术方案下沉到通用基础组件,以便剥离业务系统中的非业务功能,解决基础功能重复建设、版本破碎化、变更升级困难的问题。
第3点的协议转换需求,是因为后台服务的通信协议都是基于gRPC,而前端直接通过HTTPS+JSON来访问服务。在这里需要一种对前后端都尽可能透明的协议转换机制,使前后端能够跨协议完成通信。
(图 3 自研API网关架构)
自研API网关的基本特点是:
异步,集群化 以Go实现的API网关,在网络请求时,会基于协程进行异步处理和转发,不会阻塞新请求的接入,以此保证高并发和高性能。此外,API网关的数据面转发模块是无状态的,这样网关集群可以轻易的进行水平扩展。
支持服务发现 微保内部的服务发现基于Etcd实现,各业务服务基于自研框架实现后,都会自然地包含服务注册的功能。API网关在业务服务注册后,会直接从Etcd监视服务节点的变化,作为节点更新的依据。数据进入时,根据节点信息和负载均衡策略将数据转发至对应服务。
支持多协议的协议转换,如:HTTP转HTTP,HTTP转gRPC等等。 一般常见的方案,也是我们第一阶段的主要方案,是业务自己实现一个与proto文件耦合的业务网关,进行协议转换。对这一问题,开源界也有各式各样的实现方案,各有利弊。我们没有使用当前常见的方案,而是基于gRPC反射协议实现了不停机动态感知服务端协议变化的协议转换方案,具体方案的原理,以及和各种已知开源方案的对比,限于篇幅不在此展开,会在后续的文章中详细描述。
整体而言,在这一阶段的自研网关上线后,逐渐接管了小程序首页、车主服务等等已有服务的前端接入,而新项目如:全民保、驾乘险活动等等直接选择从API网关接入,对业务来说在很大程度上提高了开发效率,降低了研发成本。经过半年左右的线上运行,网关功能稳定性和可靠性得到了验证。
03
第三阶段:架构升级的自研API网关
上一阶段的功能实现后,网关有两个问题变得日益显著:
API网关的弹性功能、安全特性、监控、告警等等功能的扩展要持续进行,这对网关架构的可扩展性提出了较高的要求。
API网关的接入服务日渐增多,配置策略越来越复杂,运营功能急需补齐。
针对上述问题,第三阶段的设计目标是:一方面,增加网关的控制面,对网关及网关元数据进行控制和管理;另一方面,重构网关转发层的策略处理逻辑,针对可扩展性进行架构优化。
(图 4第三阶段物理架构)
如图3,首先,第三阶段与第二阶段相比最大的区别是增加了Controller模块,API Proxy转发模块也有与之相应的改造。Controller模块和对API Proxy的改造,使得策略执行的条件、参数配置化,对于配置参数,网关集群本地缓存,并支持差量热更新。为了实现基于Url Path路由的动态更新,我们自研了基于radix-tree的路由框架,能够实现不停机的动态更新。
其次,Controller模块对应着一个运营前端,网关运维人员可以登录前端进行网关机器和网关集群的管理查看,业务开发人员可以登录前端进行业务服务的管理和查看。
最后,API Proxy核心转发模块,基于责任链模式实现了策略链。业务人员可以自由地选择,并实时修改其管理的服务,要经过哪些策略处理和操作。策略链上的策略根据Controller下发后,缓存在本地的配置信息,决定如何处理当前请求。由于策略链在实现时是无状态的,使得网关的扩展变得简单,网关开发人员对于新的弹性功能,监控,统计等需求可以快速实现并编写测试用例,极大提高网关开发的效率和稳定性。
下面,我们对上面提到的一些技术细节,做较为详细的描述。
3.1 策略链
API网关除了基本的转发功能,更大的价值还有大量的非业务类基础功能,这些功能包括:日志、监控、鉴权、安全策略、弹性功能等等。随着这类功能越来越多,越来越复杂,新功能的开发维护和单元测试日益艰难。故而,我们基于责任链模式重构了网关策略处理的主逻辑,将其构成一条策略链。
(图 5 策略链)
图4所示的网关策略处理主流程,就是策略链,策略链上的每一个环节称为一个策略,依次有接入日志、跨域处理、安全策略、鉴权功能、参数变形等等功能。每一个策略相对用户请求而言都是无状态的。这保证了策略链上任意一环不会依赖于上一环的处理,使得新功能开发和单元测试更加方便。
每一个策略称为一个Middleware。当某个Middleware有超过一种实现方式时,基于模板方法模式对该Middleware的各种实现进行封装,以便扩展。
当用户请求进入时,会依次经历策略链上的每一个策略,各个策略会根据配置参数产生行为,由此实现API网关的控制类功能。
3.2 路由优化
Go中默认的路由框架,一方面,效率较低,另一方面,不支持动态的更新路由节点。对于我们的需求而言,我们希望网关可以彻底的动态更新配置,基于这一想法我们自研了基于radix-tree的支持动态更新节点的高性能路由方案。
(图 6 radix-tree)
在我们的方案中,我们选择先建策略链,后建路由的方式,使得路由的构建更新与策略链耦合较小,仅利用路由来识别服务,并通过服务查找出对应的策略配置和节点信息,使得路由节点变更的开销降到最低,从而可以利用CAS无锁的更新路由树。该路由方案能够支持热更新路由节点,相较于一般常见的路由更新后reload网关,要优雅许多。
3.3 GRPC协议转换
一直以来,对于后台基于GRPC开发的开发人员,与前端匹配都是一件繁琐的事情。在多终端场景下,前端代码的实际运行环境往往存在诸多限制,这决定了前端通常要选用最通用最常规的通信方案,所以直接使用GRPC与后台通信几乎不可能。
那么,如何完成常见的HTTP/HTTPS+JSON与GRPC的协议转换,在开源界产生了众多处理方案,下面我会先简单回顾下开源界的主流方案,并讲解我们的解决方案。
3.3.1 现有开源方案总结
1)插件方案
插件方案本身又细分为集成插件方案和多进程插件,但是本质是一样的。就是在转发时,基于服务端的IDL信息,实现相应的客户端,然后进行协议转换和转发,区别在于客户端处在网关中(集成插件)还是独立在外面以独立进程运行(多进程插件)。
这一方案较为常见,虽然有各种各样的实现方式,但内涵趋同。该方案常见于业务自行实现的业务网关,在比较著名的开源项目如Tyk,Traefik中也有使用。
优点:
实现简单,无技术难点
对前后端无侵入
缺点:
协议转换组件高度耦合业务proto,难以维护
2)gRPC-bridge方案
该名称出自envoy,但是代表了一类方案,我们这里把他们统称为GRPC-bridge方案。这类方案的原理是:把序列化的任务交还给客户端,然后用普通的HTTP/HTTPS请求将数据送到网关,然后由API网关取出该序列化结果,升级成HTTP2跟后台相应的GRPC服务交互。类似的实现还有grpc-web等。
优点:
对后端无侵入
网关可以实现通用功能
缺点:
对前端侵入大,前端必须感知协议变化,并完成序列化
3)Grpc-gateway方案
这个方案的基本原理是通过代码生成来自动生成每个配置了的GRPC接口的对应的HTTP接口。使用时,后台开发需要在proto文件中添加大量配置,之后,后台服务可以作为一个HTTP服务对网关暴露。本质上类似于多进程方案,主要亮点是基于代码生成。
优点:
对前端和网关无侵入
缺点:
网关与后端之间降级为HTTP1.1,性能不如HTTP2
proto引入额外的外部依赖,google.api.http包
对后台开发人员侵入较大,接口规模大时,难以维护
综上所述,在目前主流的GRPC的协议转换方案一定程度上都需要入侵前端或者后端,带来了额外的维护成本。伴随着接口越来越多,服务越来越细分,这些维护成本会逐渐大到无法承受。
3.3.2 基于反射协议的GRPC协议转换
(图 7反射协议原理)
GRPC协议转换之所以困难,是因为序列化的过程强依赖于IDL文件的描述。必须依赖响应服务的proto文件,才能正常的完成序列化。所以,问题的关键在于:
1)服务的IDL信息能否在运行时获得
2)根据运行时获得的IDL信息能否在运行时构造请求参数和解析返回参数
带着这两个问题,我们在调研中发现了GRPC的反射协议。GRPC反射协议本身也是一种RPC服务,客户端可以通过访问该服务,获得服务端对外暴露的接口详情,包括服务名,函数列表,出入参数等等信息。
这样依赖反射协议,我们就能够获取服务端的IDL信息,接下来只要找到根据相应的IDL信息进行序列化和反序列化的方法,就可以实现GRPC的泛化调用。GRPC反射协议原理和具体实现方法较为复杂,限于篇幅我们这里不详细描述,后续会在其他文章中详细解析实现过程。
此外,因为服务的协议信息相对稳定,我们在实现时通过异步拉取,缓存协议信息的方式,优化了泛化调用的性能。该方法有如下优点:
官方原生支持反射协议,且支持多语言,跨语言,跨平台
后端改造极小,前端无需感知,API网关一次性实现无后续维护成本
协议更新自动化,无需配置,业务无感知,无后续维护成本
该方案自18年3月上线运行至今,状态稳定,逐步取代了内部业务自行实现的业务网关,为实现统一接入入口扫清了障碍。
3.4 多集群运营及管理
API网关应该支持多集群运营的方式,可以做到:
1)对不同端,不同内部服务可能有截然不同的安全策略和资源需求,分集群运营,满足各自需求,精细化运营。
2)实现业务和服务间强隔离,分离业务风险。
(图 8 多集群运营)
3.5 服务配置管理
在日常业务开发结束,需要上线时,或者业务预研阶段需要配置网关的需求,随着业务量增加会不断增多,所以对于业务人员来说有两个核心需求:
1)管理自己服务和API
2)自助发布服务和API
为此我们开发了,业务的服务管理页面,并在其中集成了业务的自助发布,配置管理和修改功能
04
总结
经过3个阶段的架构演进和升级,结合微保实际需求场景,我们研发实现了很多实用的定制化功能,满足了业务需求,优化了系统架构。同时,通过工具链和运营支持功能的完善,API网关的可运维性和易用性有了很大提高,并为后续进一步演进,准备了必要的基础。至今,API网关已逐渐成为微保各个业务系统的统一外网入口,后续也会继续演进优化,为业务开发提供更加便捷,强健的基础设施功能。
or
长按扫码可关注
以上是关于微保API网关的探索与实践的主要内容,如果未能解决你的问题,请参考以下文章