高并发系统设计:API网关,系统的门面

引入

  • 系统迎来了一些“不速之客”,在凌晨的时候,系统中搜索商品和和用户接口的调用量会急剧上升,持续一段时间之后又回归正常。这些搜索请求的一个共同特性是来自固定的几台设备。当你在搜索服务上加一个针对设备ID的限流功能之后,凌晨的高峰搜索请求不见了。
  • 但是不久之后,用户服务也出现了大量爬取用户信息的请求,商品接口出现了大量爬取商品信息的请求。你不得不在这两个服务上面也增加一样的限流策略

但是这样有一个问题:不同的三个服务使用同一种策略,在代码上会有冗余,无法做到重用。如果其他服务上也出现类似的问题,还要通过拷贝代码来实现,肯定是不行的。

虽然我们可以将限流的功能独立成一个单独的jar包,给其他服务引用。但是有一种情况是,这个包只能给java使用,不能给golang等其他语言使用。

那怎么办呢? 可以通过引入API网关

API网关的作用

API网关(API Gateway)不是一个开源组件,而是一种架构模式,它是将一些服务共有的功能整合在一起,独立部署为单独的一层,用来解决一些服务治理的问题。你可以把它看做系统的边界,它可以对出入系统的流量做统一的管理。

API网关可以分为两类:一类是入口网关,一类叫做出口网关。

入口网关部署在负载均衡服务器和应用服务器之间,主要有如下几个方面的作用:

  • 它提供客户端一个统一的接入地址,API网关可以将用户的请求动态路由到不同的业务服务上,并且做一些必要的协议转换工作。
    • 因为每个微服务对外暴露的协议可能不同:可能是HTTP服务、RPC服务、WebService服务等
    • API网关可以对客户端屏蔽这些服务的部署地址,以及协议的细节,给客户端的调用带来了很大的便捷
  • 另一方面,在API网关中,我们可以植入一些服务治理的策略,比如服务的熔断、降级、流量控制以及分流等等
  • 再有,客户端的认证和授权的实现,也可以放在API网关中。
    • 因为不同的客户端使用的认证方式可能不同,比如可能是token认证、cookie认证、oauth认证等
    • 这些认证方式放在API网关上,可以得到统一的处理,应用服务不需要了解认证的细节
  • API网关还可以做一些黑白名单相关的事情,比如针对设备 ID、用户 IP、用户ID 等维度的黑白名单。
  • API网关中也可以做一些日志记录的事情,比如记录HTTP请求的访问日志,生成标记一次请求的requestId等
    在这里插入图片描述
    出口网关使用场景:我们在系统开发中,会依赖很多外部的第三方系统,比如第三方账户登录、第三方工具支付等。我们可以在应用服务器和第三方系统之间,部署出口网关,在出口网关中,对调用外部的API做统一的认证、授权、审计以及访问控制。

在这里插入图片描述

API网关要如何实现

  • 在思想一个API网关时,实现要考虑的是它的性能。这很好理解,API入口网关承担从客户端的所有流量。假如业务服务处理时间是ms,而API网关的耗时在ms,那么相当于每个接口的响应时间都要增加10%,这对于性能的影响无疑是巨大的。而提升API网关性能的关键在IO模型上。

  • 除此之外,API网关中执行的动作有些是可以预先定义好的,比如黑白名单的设置,接口动态路由;有些则是需要业务根据自身业务来定义。所以,API网关的设计要注意扩展性,也就是你可以随时在网关的执行链路上,增加一些逻辑,也可以随时下调一些逻辑(也就是所谓的热插拔)

    • 一般来说,我们可以把每一个操作定义为一个fliter(过滤器),然后使用“责任链模式”将这些filter串起来。责任链可以动态的组织这些filter,解耦filter之间的关系,无论是增加还是减少filter,都不会对其他filter有任何的影响。
    • Zuul就是采用责任链模式,Zuul将filter定义为三类:pre routing filter(路由前过滤器)、routing filter(路由过滤器)、after routing filter(路由后过滤器)。每一个filter定义了执行的顺序,在filter注册时,会按照顺序插入到filter chain(过滤器链)中。这样zuul在接收到请求时,就会依次按照执行插入到filter chain中的filter了。
      在这里插入图片描述
  • 另外,还需要注意的是,为了提高网关对请求的并行处理能力,我们一般会使用线程池来并行的执行请求。

    • 不过,这会带来一个问题:如果某个服务出现问题,造成响应缓慢,那么调用商品服务的线程就会被阻塞无法释放,久而久之,线程池中的线程就会被这个服务所占据,从而影响到其他服务。因此,我们需要针对不同的服务做线程隔离。主要有两种思路:
      • 如果你后端的服务拆分的不多,那么针对不同的服务,采用不同的线程池
      • 在线程池内部可以针对不同的服务,甚至不同的接口做线程的保护。比如说,线程池的最大线程数是1000,那么可以给每个服务设置一个最多可以使用的配额。
    • 一般来说,服务的执行时间应该在毫秒级,线程被使用后会很快被归还给线程池以供后继请求使用,同时出于执行中的线程数量不会很多,对服务或者接口设置线程的配额,不会影响到正常的执行。即使因为故障,某个接口或者服务的响应时间变长,造成线程数暴涨,但是因为有配额的限制,也不会影响到其他的接口或者服务了
    • 在实际应用中也可以将这两种方式结合。比如针对不同的服务使用不同的线程池,在线程池内部针对不同的接口设置配额

如何在系统中引入API网关呢?

目前系统的架构如下:
在这里插入图片描述
可以看到,服务端和客户端之间有一层薄薄的web层,这个web层做的事情主要有两方面:

  • 一方面是对服务层接口数据的聚合。比如,商品详情页的接口,可能会聚合在服务层中,获取商品信息、用户信息、店铺信息以及用户评论等多个服务接口的数据。
  • 一方面Web层还需要将HTTP请求转换为RPC请求,并且对前端的流量做一些限制,对于某些请求添加设备ID的黑名单等等。

因此,我们做改造的时候,可以先将API网关从Web层独立出来,将协议转换、限流、黑白名单等事情,挪到API网关中处理,形成独立的入口网关层。

而针对服务接口数据聚合的操作,一般有两种解决思路:

  • 再独立出一组网关转换用服务聚合、超时控制方面的事情,我们一般把前一种网关叫做流量网关,后一种可以叫做业务网关
  • 抽取独立的服务层,专门用接口聚合的操作。这样服务层就大概分为原子服务层和聚合服务层

因为接口数据服务是业务操作,于其放在通用的网关层来实现,不如放在更贴近业务的服务层来实现。所以,建议第二种方案。

在这里插入图片描述
同时,我们可以在系统和第三方支付服务,以及登录服务之间部署出口网关服务。以及将对数据的加密、签名的操作放在出口网关。

最后,其系统架构如下:
在这里插入图片描述

总结

  • API网关分为入口网关和出口网关两类,入口网关作用很多,可以隔离客户端和微服务,从中提供协议转换、安全策略、认证、限流、熔断等功能。出口网关主要是为调用第三方服务提供统一的接口,在其中可以对调用外部的API做统一的认证、授权、审计以及控制访问
  • API网关的实现重点在于扩展性和性能,可以使用多路IO复用和线程池并发处理来提升网关的性能,可以使用责任链模式来提升网关的扩展性
  • API网关中的线程池,可以针对不同的接口或者服务做隔离和保护,这样可以提升网关的可用性
  • API网关可以代替原本系统中的web层,将web层中的协议转换、认证、限流等功能挪入到API网关中,将服务聚合的逻辑下沉到服务层

API网关可以为API的调用提供便捷,也可以将一些服务治理的功能独立出来,达到复用的目的。虽然在性能上可能有一些损耗,但是一般来说,使用成熟的API网关组件,这些损耗是可以接受的。所以,当你的微服务系统越来越复杂时,可以考虑使用API网关作为整体系统的门面

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值