为什么微服务一定要有API网关,微服务api网关的作用
本文讲述了为什么微服务一定要有API网关,微服务api网关的作用。
微服务不能没有网关,就如同 Java 程序员不能没有IDEA、Eclipse。为什么呢?
之所以网关对微服务这么重要,主要有以下几点原因:
1. 解决 API 放哪里的问题
要知道,采用微服务架构的系统本身是由很多的独立服务单元组合起来的。而客户端要调用系统,则必须通过系统提供的各种对外开放的功能 API 来实现。
问题来了,这些 API 要放在哪里呢?直接放在组成系统的服务单元上行不行?
比如,在一套电商系统上,关于订单相关的 API ,放在组成订单服务的服务单元上;风控服务的 API ,放在组成风控服务的服务单元上。
好,咱们假设有这么一个场景,有一位用户想在这套电商系统上查看下商品详情。那么,这个查看商品详情的操作,就可能:
调用商品服务的 API 获取商品描述
调用评价服务的 API 获取相关评价
调用商家服务的 API 获取商家信息
调用礼券服务的 API 获取相关礼券
……
可以看到,就这么一个商品查看操作,就可能会调用许多服务的 API。
那这些 API 如果全部分散到各个服务单元上,供客户端调用,像查看商品这么简单的一次操作,客户端就可能需要远程访问好几次甚至十几次服务器。
微服务员自己有讲究把 API 的粒度划分得很细,也就是说,可能从商品服务上调用商品信息,不止是调用一次商品服务就够了,很可能需要多次对商品服务的不同 API 进行调用,才能获取到足够的数据。
这样一来,客户端需要访问服务器的次数就更多了,可能十几次都不够,得几十次。
这种多次访问服务器的行为,会极大延迟客户端的界面响应时间,很不现实。
所以,把 API 放到各个业务相关的服务单元上,看上去问题很大。
那为什么引入网关就能解决这个问题呢?
因为引入网关,就相当于在客户端和微服务之间加了一层隔离。通常,网关本身会和各个服务单元处于同一个机房,这样,客户端做业务操作的时候,只需要访问一次网关。然后剩下的事情,再由网关分别访问同在一个机房的不同的服务,再把拿到的数据统一在网关封装好,返回给客户端就好。
2. 解决边缘功能集成的问题
在一套微服务组成的系统里,除了必须的业务功能以外,还有为了系统自身的健壮与安全,以及微服务本身的管理,而必须引入的一些非业务功能。对于这些非业务又很重要的功能,我们统称为边缘功能。
还是拿电商系统为例,我们来看一些重要的边缘功能。
假设因为我们做了一次非常大的促销活动,导致流量过大,系统承载不了了。此时,为了保证系统本身的稳定,我们就需要把一些承载不了的流量给通过各种手段消化掉,一般的做法有三种:
限流:通过令牌桶等算法,把一些额外的流量挡在系统外面,不让其访问。
降级:由于系统可能已经过载了,此时,我们就放弃处理一些服务和页面的请求或者进行简单处理,比如直接返回一个报错。
熔断:有些时候,系统过载过度或者上线出了问题 bug,降级都解决不了问题。比如,缓存失效了,导致大量请求频繁访问了数据库,而这种频繁访问数据库可能造成了大量的 IO 操作,结果又影响了数据库所在的操作系统,同时,这个操作系统上又有着别的重要服务,直接也被影响了。对于这种连锁反应,我们称之为雪崩。而为了防止雪崩,我们就会坚决把缓存失效导致数据库被频繁访问的服务给停掉,这就是熔断。
可以看到,像限流、降级、熔断这些系统保障策略,最合适的地方应该是有一个集中的请求入口点,就像古时候,老百姓进城需要过城门那样。
当系统出现问题的时候,直接就在这个入口点做相应的操作即可。
限流,就直接在这个入口点限制后续请求。
降级,就直接在这个入口点判断请求想要访问的服务或者页面,直接报错返回。
熔断,就直接在这个入口点,断开所有访问特定服务的请求连接,然后再把后继对特定服务的访问,也统统拦在门外。
在电商系统里,有很多特殊场景的接口,需要受到严格的限制。
比如,支付接口,访问它就需要认证和权限控制。又比如,对于系统的访问,有时候不能让国外的人去访问国内的网站,这就需要限制客户端的访问 IP,所以系统还需要认证和授权功能。
那这种认证和授权也是最合适放在请求的一个集中入口点,统一实现。
还记得上面咱们说过的网关的 API 统一存放吗?我们只需要对这些 API 做对应的权限设置,当请求访问特殊场景接口的时候,必定会通过 API 访问。所以,限制接口的访问,本质上就是对特定 API 的限制,那么,放在网关再合适不过了。
现实里,我们有时候需要把线上的流量镜像出来,转发到灰度环境,利用这些镜像出来的流量既可以用于小范围测试,又可以更好的评估系统所能承载的最大吞吐量,也因此,系统需要有一个统一入口做分流。
可以看到,无论是系统需要的保障策略,认证授权,还是流量分流等功能,都应该放到一个统一的请求入口处才能得到最好的实现。网关恰好就承担了这么个统一请求入口的角色。
所以,对于微服务中,林林总总的边缘功能,往往会通过插件的形式,集成在 API 网关中。
3. 解耦了客户端和后端微服务
一套项目,在使用微服务模式的初期,往往后端变化是十分频繁的。
频繁变化的原因有很多,像业务领域划分不合适啊,像某个业务模块急速膨胀啊,都可能导致后端微服务的剧烈变化。
在这种情况下,如果没有网关,很可能就会出现客户端需要被迫随着后端的变化而变化的情况。
比如,在电商系统里,初期我们很可能会把风控服务做得非常小。随着业务的发展,风控服务越来越庞大,此时,风控服务就可能被分解为决策引擎和分析中心等更多更细的服务。
在电商里,风控往往是下单、支付等操作的必要前置操作。如果没有网关去分隔开客户端和微服务,客户端直接和风控服务打交道,那么风控服务拆分,API 必然不会稳定,API 的变化,自然会引发调用 API 客户端代码的变化。
有了网关之后,情况就好了很多了。当风控服务本身频繁变化的时候,我们只需要改动网关的代码就好。而服务器代码的升级可是远远要比客户端代码的升级容易太多了。
今天准备再谈下API网关,发现很多人对去中心化的微服务架构下为何还要用API网关本身存在诸多的疑惑,因此准备在对一些关键的问题点进行说明。
微服务架构下API网关的位置
上图是一个标准的基于SpringCLoud的微服务架构体系图,在图中可以明确的看到API网关或微服务网关所处的位置,即前面谈到过的API网关的定义。
即API网关是内部微服务的统一对外出口,所有需要外部的应用或APP访问的接口都通过API网关暴露一个统一的地址给外部使用。
因此API网关最基本的作用首先是要实现一次接口服务的代理,实现内部的微服务对外界透明。否则所有的内部微服务将全部暴露给外部应用,这个风险是相当大的。
如果仅仅是实现接口转发,那么Ngnix反向代理也可以完全实现,因此当前架构也可以看到很多的微服务架构体系并没有采用API网关。
微服务注册和微服务API接口注册
在微服务架构里面的注册一定要将微服务注册和微服务API接口注册两个概念分开。
微服务注册中心只到微服务模块级注册,而API网关可以到API接口级别注册。
比如我们常说的Eureka服务注册中心,实际是整个微服务模块注册,而不是该微服务提供的具体多个API接口服务的注册。因此后续的心跳监控,负载均衡等也全部是在微服务这个颗粒度上面。
而微服务API接口注册,即微服务提供出来的Http Rest API接口的具体注册动作,比如一个微服务本身提供了100个接口,但是只有10个API接口需要外部APP访问,那么这个时候实际上只需要将这10个接口注册和接入到API网关即可。
去中心化和中心化的思路区别
对于微服务架构下的服务管控治理,要首先考虑中心化和去中心化的区别。
对于中心化架构,简单来说就是所有的API接口服务全部都要注册和接入到API网关中,等于是API网关基于原始的业务服务API接口做了一层封装,然后发布代理服务。
那么对于所有API接口服务的调用,涉及到的调用请求,消息的输入和输出,都可以在API网关中进行拦截。
因此API网关要实现安全,日志,限流熔断,服务路由等能力,全部都都以这个拦截为基础。同时各个能力的实现又可以配置为拦截过程中的各个独立插件。这个是当前主流的API网关产品的实现和API管控治理思路。
而在非中心化架构下,实际服务调用请求和数据流并不会通过类似服务注册中心或管控中心,而注册中心仅仅起到服务注册发现作用。
在这种情况下要实现负载均衡,路由,限流熔断等各种服务治理管控能力,那么就必须在微服务的消费端植入代理来完成,类似下图。
也就是说在去中心化架构下,实际上管控流和数据流已经分离,为了实现最终的管控要求,那么就必须在服务请求端对相关请求进行拦截和处理。类似可以看到Ribbon,Hystrix,Sentinel等基本也都是上述的处理思路和逻辑。
而上图去中心化的思路也正是当前ServiceMesh实现微服务治理的一个核心思路,即通过去中心化架构下,下放Sidecar来实现拦截和控制处理。
有了类似Sentinel和Hystrix为何还用网关限流?
在前面我已经画过一个同时存在API网关和注册中心的混合架构,如下:
从这个图实际可以很明显的看到,对于外部APP实际上是无法通过内部的Hystrix进行限流的。外部APP本身可能并没有通过标准的SpingCloud框架实现,也无法下放各种JAR包和代理。那么外部APP访问请求的限流就必须在API网关上面来做。
因此在存在内外访问的场景下,两处的限流都是必须的。
API网关是否需要具备ESB总线的协议转换能力
简单来说在一个遗留系统的微服务架构改造过程中,如果整体的IT应用集成已经有了ESB总线平台,那么API网关只做Rest API接口服务接入即可。
但是如果原来并没有这类平台,那么API网关需要承担部分轻量的ESB总线能力。
轻量的能力主要包括两个方面:
一个是协议转换,对于协议转换并不需要支持很复杂,但是可以将传统遗留系统的SOAP接口,JMS接口转换发布为Rest API接口。
其次是数据映射,不需要复杂的数据映射,但是存在提供方和消费方需要的数据格式存在差异的时候,能够通过间的映射模板来完成数据删减或丰富的动作。
对于当前主流的API网关往往都会提供简单的数据映射能力,但是对于协议转换能力不提供。而对于协议转换能力也可以方便的通过插件定义来实现。
服务运行监控和日志分析
前面谈到,对于API网关的中心化,既有形成新得集中化单点影响可靠性和性能得劣势,同时也存在关键请求输入和输出拦截的优势。
由于可以拦截服务运行请求报文数据,因此一方面可以应用到具体的接口调用日志审计需求,也可以详细的记录到接口服务运行的性能数据信息,包括前面一篇文章谈到的服务运行时长,数据量,调用IP等。
对每一次的服务运行实例日志信息都进行详细记录,是后续进行服务运行监控,统计分析,监控预警,限流熔断等的基础。
从这个点来说,去中心化架构没有完全ServiceMesh化的时候实际上很难做到这点。
因此也看到在采用SpingCLoud微服务架构又没有启用ServiceMesh的时候,实际上是没有一个统一的地方可以查询到服务运行实例日志信息,进行统一的服务运行分析统计的。
异构微服务框架的兼容性
要看到对于API网关实际是独立在微服务框架外的一个组件。虽然在类似SpingCLoud框架体系里面也提供了Zuul和SpringCloud Gateway的微服务网关。
但是也有各种独立在微服务框架体系之外的API网关产品。
我们可以想一个最简单的场景,比如我现在有一个采用传统的Java SpringMVC+CXF框架来开发实现的Rest API接口服务。那么这个接口服务在标准的微服务架构体系里面是无法纳入到注册中心,限流熔断,负载均衡等进行统一的管控。
包括不同的微服务开发框架,本身也存在各自的微服务治理管控策略上的差异。
其次,在当前去中心化的架构下,往往是多个组件协同来完成整体的服务注册发现,服务配置,服务限流熔断,服务安全等多个管控能力。同时在这些管控能力的实现过程中,实际对微服务模块本身是存在侵入性的,即要么需要将管控的Jar包下放到具体的微服务模块里面并添加依赖,要么需要在接口实现方法上增加注解等。
即标准微服务体系下的微服务治理能力实际依赖微服务框架,同时对代码实现存在一定的侵入性。那么在这种情况下管控规则变更,或者更改微服务框架等,都会导致对应的微服务治理管控部分的配置文件或代码修改。
而对于中心化的API网关来说,希望达到的效果是,前面谈到的服务安全,日志,限流熔断等各自API接口的管控能力全部能够通过配置的方式来完成。在API接口注册到API网关后,所有的管控规则都可以通过配置方式动态变化,并实时生效。
即使你微服务实现替换了框架,对API网关已有的能力和规则实现并没有任何影响。API网关只关心接入的是Rest API接口,但是如何实现的接口,采用哪种框架实现的接口并不关心,也不会去限制使用。
也正是这个原因可以看到,在遗留系统朝微服务迁移的时候,API网关往往更加适合。
为何需要在Ngnix后面再加一层API网关
在前面已经谈到,Ngnix本身也可以起到接口服务代理和路由的作用。在简单的一些场景往往使用Ngnix就可以了。但是在更加严格要求安全和控制粒度的场景仍然需要API网关。
对于Ngnix重点是来做负载均衡,也可以做接口代理路由,但是一般只做URL大的路径级别,而不会做到具体的API接口服务级别。比如一个微服务需要暴露30个API接口服务给前端APP端使用,这个时候一般只配置到一个统一的路径,通过路径进行代理路由,而不是配置到具体的一个个接口服务地址。那么在这种场景下这个路径如果本身提供了100个API接口服务,就会导致其他70个服务也同时暴露到外网。
而API网关则可以管控到每一个细粒度的API接口服务。
其次,内部微服务暴露给外部使用的API接口,一种场景是只暴露给自己的APP端使用,还有一种场景就是需要暴露给外部第三方的应用系统使用。
在第二种场景下,就需要进一步对API接口的安全进行细粒度管控,即需要管控到每一个API接口的安全控制。比如我们常说的,虽然API网关上暴露了100个服务,但是只有A01-A10这10个服务开放给第三方物流系统使用,A01-A10和B01-B10的20个服务开放给招投标平台使用。在这种情况下,就必须实现到具体的业务系统消费方+API接口服务粒度的访问控制能力。
这种到API接口级别细粒度安全控制Ngnix无法做,简单的使用Auth2.0也无法满足,因此就需要一个统一的地方对这种安全进行管理。
API网关的开源实现
对于API网关的开源实现,当前主要有两类,一类是基于Ngnix+Lua语言的Openresty来实现,一类是基于Go语言来实现。
当前Kong网关也是大家采用比较多的一个开源API网关产品,底层基于Ngnix和OpenRestry,语言是Lua语言,最重要的是整个架构设计中的可插拔的插件机制,这种插件机制很方便我们自定义插件扩展。比如我们现在对于安全,日志,运行监控等功能都能够很方便的通过插件扩展来实现。
在上次也谈到另外一个国人研发,进入到NCNF开源基金会的API网关,APISIX,这个网关底层架构实际和Kong很类似,但是从作者公布的性能数据来看比Kong网关好了很多,具体可以参考作者发布的一篇文章如下:
https://zhuanlan.zhihu.com/p/103236688
对于Go语言开发的API网关,如国内的GoKu API Gateway,中文名:悟空API网关,该网关是eoLinker旗下、国内首个企业级开源的go语言API网关,帮助企业进行API服务治理与API性能安全维护,为企业数字化赋能。GoKu支持OpenAPI与微服务管理,支持私有云部署,实现API转发、请求参数转换、数据校验等功能,提供图形化界面管理,能够快速管理多个API网关,提高API业务安全性。
而个人理解Go语言开发的API网关应该具备更好的并发性能,这个需要后续做了压测后再给出具体的测试数据说明。当然Kong网关本身的性能也不弱,已经能够满足大部分的业务需求和场景,也是我个人推荐采用的API网关选型参考。
跨团队协同必须使用API网关
一个企业有两个独立的开发部门,分别开发企业两个独立的应用,而两个应用本身都基于微服务架构进行开发。这个时候两个应用之间存在接口集成。
而这个接口集成个人建议是不能走微服务注册中心,即使类似Nacos这种独立的注册中心也不建议。其核心的一个原因就是对于两个独立团队和独立应用来说,两者的边界不再应该是微服务这个粒度,而应该是微服务API接口这个粒度。
如果完全将微服务全部开放,那么等于是内部应用很多API接口能力也会暴露给其他的应用,这个从安全管控上显然是不合适的。
这也是我们常说的场景,即即使都是内部环境,内部应用,也不需要提供统一的API接入地址给对外的APP应用使用和访问。但是由于内部是独立的开放团队,独立的应用,考虑到各自的边界,还是应该启用API网关来管理两个应用的API接口服务。
API网关和微服务网关
对于API网关和微服务网关实际实现的核心功能基本一致,但是要注意到微服务网关一般是在微服务架构体系里面的内容。而API网关一般是可以独立在微服务架构体系之外的内容。
也就是说API网关和微服务整体框架体系更加的松耦合。
API网关一般具备独立的服务注册接入,负载均衡和路由能力,而微服务网关一般则是通过和服务注册中心的集成来实现服务注册发现,负载均衡和路由。
简单来说如果当前微服务A模块有100个接口服务。
在有服务注册发现中心的情况下,微服务A模块部署后会被注册中心自动发现,并加入到可用集群列表中。因此在微服务网关和注册中心集成后,所有的接口服务也自动的注册和接入到了微服务网关中。
当用户访问网关提供的服务地址时候整体过程如下图:
调用网关暴露地址:http://ip/gateway/api网关将请求转发到注册中心注册中心返回可用的服务注册地址列表网关基于负载均衡算法选择一个最终地址并路由在这种场景下可以看到实际并不用一个个的API接口在网关上面注册。但是也无法控制一个微服务哪些具体的接口要接入网关,哪些不接入。同时这里的微服务网关实际上本身也是整体微服务架构体系里面的一个微服务模块,充当了服务消费方的角色。
也就是说APP应用无法受整体微服务框架管辖,那么对应的依赖包,代理SDK等无法下放到外部应用中,那么这部分内容实际是转移到微服务网关上来帮助外部APP应用完成。
而对于相对独立的API网关来说,整体的注册和接入过程是在API网关上面独立完成的,而是是控制到API接口服务粒度进行。
那么这个时候如果微服务模块出现了动态扩展,在API网关上是否需要手工添加新节点?
这里实际两种方法:
其一是微服务模块节点变化的时候,应该能够调用API网关提供的接口,对节点地址集群进行动态更新。其二是微服务上层构建一个集群IP地址,API网关只对接这个集群IP地址出口,比如在微服务和容器云融合后,实际可以暴露Kurbernetes集群IP地址给API网关接入。
上文是小编为大家整理的为什么微服务一定要有API网关,微服务api网关的作用。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~