一个超简洁API网关的设计思路
Posted chen陈序猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个超简洁API网关的设计思路相关的知识,希望对你有一定的参考价值。
API网关对于互联网应用,实在是太重要了,有了API网关,对于微服务来说,将服务治理和安全授权的功能统一放置在API网关处,会减少不少的重复功能的开发量。这不仅提高了整体后台架构的简洁和清晰度,也能让后台更关注业务逻辑,提升代码质量。
无网关架构下的服务调用模式
现在来看一下,如果没有API网关,一些微服务常用功能如何在后台实现:
限流和熔断:
请求签名:
上面的图片表示了整体业务请求签名的全过程,我们可以发现上面的架构存在以下问题:
1,每个接口都需要执行一次与业务无关的合法请求鉴定,多了一次rpc调用。
2,签名逻辑需要每一个业务方参与,不仅繁琐,且及其容易出错。
3,消息扩散风暴:签名认证服务的并发量是其他业务的总和。
黑白名单:
很多时候,我们有以下需求:鉴定到某ip发生的请求为恶意请求,比如利用系统漏洞薅羊毛,我们想针对此服务将其ip封禁,如果每一个服务都有这样的需求,我们就需要重复开发类似的黑名单功能,造成代码互相拷贝。
实际上,重复的功能在每一个服务重复开发,最大的问题是不可控,会造成整个后台系统架构的加速腐败:你不能保证每一个使用者都能正确的使用了SDK从而不发生差错。
网关架构下的服务调用模式
网关架构下的服务调用模式:
API网关专为重复逻辑而生,只在入口统一解决限流,熔断,认证,请求签名验签,黑白名单等功能。http负载均衡,http请求转dubbo请求等请求协议转换功能。
一个争议:
网关只在请求入口处做对外约束还是内部服务调用也通过API网关转发?比如内部服务每一个服务仍然都保留熔断功能。
笔者认为,网关只限制入口处请求就可以了,如果内部服务调用也通过API网关,因为多个rpc调用连起来一起成功才能保证数据的完整性,在没有可靠的分布式事务解决方案出现之前,如果熔断了多个写请求的某一个步骤,会导致错误的数据产生。(两个系统的数据对不上)另外一个问题就是增加了系统的复杂性,网关系统反而变的臃肿,所以不建议对内部调用做网关层转发。
好了,说明了搭建API网关系统的好处,下面简述一下如何设计一个比较简洁的API网关。
API网关需要保证哪些要求
一,无状态,可以平滑扩容。
二,高性能,可以承载海量并发。
三,易扩展,可以轻松实现组件的扩展。
四,动态化,各项配置皆可动态配置,免重启实时生效。
下面就以笔者自研API网关 easy-gateway说一下整个网关中间件的设计思路。(下附架构图)
--geteway-core:网关的控制逻辑实现。
--geteway-service:网关的启动配置和业务逻辑实现。(组件逻辑)
--gateway-common:网关的公共依赖。
--gateway-admin:网关可配置管理控制台。(未实现)
--zip: 配置中心模版zip,网关建库脚本,war.zip为网关熔断所使用组件hystrix的面板web程序。
网关采用Netty框架的NIO通讯模型来保证Http请求的高性能处理,但是也保证了你可以随时更新其他的HTTP实现。
httpService接口作为了web容器的可扩展接口,内置了基于Netty的高性能实现。
wapper包封装了与具体http容器无关的request和response模型。它本身是一个抽象类,每一个http容器负责继承requestwapper将自己的实现映射到通用模型上,例如,Netty有Netty的requestWapper,servlet容器则有servlet的wapper。这使得程序更加面向对象。
getWayExecutor作为网关执行器,用于执行一系列的前置后置运行时处理器。
HandlerContext则为网关一次执行的上下文,用于在各种组件中通过Handler获取通用请求模型对象和API,以及在调用成功后的后置组件获取响应对象。
PostHandler和PreHandler以及RuntimeHandler则是开发的对网关插件扩展的接口,用于处理对请求的拦截。
RouteInvocation则为最终的路由组件,用于将请求发送到对端的http服务或者dubbo服务。
exception包为网关异常,以及网关异常执行组件ExceptionHander,在网关程序处理发生异常时,会调用ExceptionHandler做请求返回。
invocation包则封装了rest和rest转dubbo调用的逻辑:
以上则为网关核心组件抽象层的基本叙述。下图是完成一次调用的整个流程,即为GateWayExecutor的控制逻辑:
不妨看一下NettyHandler的逻辑:
让我们看一下gateway-service中的业务逻辑,实际上就是实现了一系列的Handler,例如,黑名单组件:
easyGateWay如何实现网关的各项要求
一,无状态,可以平滑扩容
实际上网关是有状态的,内存cache里存储了网关的各项组件配置。但是zookeeper可以同步多节点之间的状态,而且网关的配置本身就可以允许最终一致性。因此,前台架设一台nginx即可轻松实现平滑扩容。
二,高性能,可以承载海量并发。
高性能是靠以下能力保证:
1,可以随时扩容
2,采用高性能网络编程框架Netty实现NIO非阻塞请求通讯。
3,网关弱依赖db,配置更新机制如下:mysql更新以后,zookeeper通知各节点去数据库重新获取最新的网关组件配置。
4,使用Hystrix对异常请求进行熔断,使用信号量隔离机制和自建线程池实现超时控制。相关代码逻辑如下:
实际上,为了避免Handler组件代码异常本身耗时造成整个网关系统的不可用。我们可以不直接使用Netty本身的工作线程池,而且像Dubbo一样维护一个专门的业务线程池,业务线程池阻塞不影响Netty本身处理请求的性能。
三,易扩展,可以轻松实现组件的扩展。
网关面向扩展开放的原则,你可以随便编写PreHandler,RuntimeHandler和PostHandler的实现类来在请求调用前/调用时/调用中完成自己的个性化网关逻辑。
四,动态化,各项配置皆可动态配置,免重启实时生效。
基于zookeeper的配置中心机制和内存池监听机制来实时同步配置,一切的东西都是动态的。
总结
以上,就是easy-gateway的API网关能力相关介绍
未来可能会实现基于SPI机制的扩展行为自动发现功能。
github: https://github.com/chenhaiyangs/easy-gateway
另外安利笔者的TCC分布式事务实现框架:
github: https://github.com/chenhaiyangs/rpc-tcc-transaction
(完)
chen陈序猿|一起学技术吧
以上是关于一个超简洁API网关的设计思路的主要内容,如果未能解决你的问题,请参考以下文章