网关路由

网关(Gateway)在计算机网络中很常见,用于表示位于内部区域边缘,与外界进行交互的某个物理或逻辑设备,譬如你家里的路由器就是属于家庭内网与互联网之间的网关。

单体架构下不太强调网关的概念,为各个单体系统的副本分发流量的负载均衡器实质上会扮演内部服务与外部请求之间的网关角色。

为什么微服务架构下需要网关?并且网管已然成为微服务架构下的一种基础设施?why?

我个人的理解是:微服务架构下,每个服务节点可能是由不同的团队负责,都有着自己独立的、不相同的接口,如果服务集群缺少一个统一对外交互的代理人角色,那外部的服务消费者就必须知道所有微服务节点在集群中的精确座标。如此一来,外部消费者就会受到服务集群的网络限制(服务集群内部一般是内网通讯)、安全限制(安全策略约束)、依赖限制等诸多不便。

总得来说,微服务中网关的首要职责就是作为统一的出口对外提供服务,将外部访问网关地址的请求,根据适当的规则路由到内部集群中正确的服务节点上。因此,微服务中的网关,也常被称作”服务网关“或者”API网关"。

微服务中的网关首先应该是个路由器,在满足此前提的基础上,可以依据需要通过过滤器来添加额外的职能,譬如安全、认证、授权、限流、监控、缓存,等等。网关公式:

网关 = 路由器(基础职能) + 过滤器(可选职能)

一、网关--路由器基础职能

服务网关主要考量的是能够支持路由的“网络协议层次”和“性能与可用性”这两个方面因素。

1.1 网络协议层次

是指负载均衡中的四层流量转发和七层流量代理。从技术实现角度来看,对于路由这项工作,负载均衡器与服务网关在实现上是没有什么差别的,很多服务网关本身就是基于老牌的负载均衡器来实现的,譬如基于Nginx、HAPproxy开发的Ingress Controller,基于Netty开发的Zuul 2.0等。从目的角度来看,负载均衡器与服务网关会有一些区别,具体在于前者是为了根据均衡算法对流量进行平均的路由,后者是为了根据请求(流量)中的某种特征进行正确的路由。

网关必须能够识别流量中的特征,这意味着网关能够支持的网络通信协议的层次将会直接限制后端服务节点能够选择的服务通信方式。如果服务集群只提供像etcd这样直接基于TCP访问的服务,那只部署四层网关便可满足,网关以IP报文中源地址、目标地址为特征进行路由;如果服务集群要提供HTTP服务,那就必须部署一个七层网关,网关以HTTP报文中的URL、Header等信息为特征进行路由;如果服务集群还要提供更上层的WebSocket、SOAP等服务,那就必须要求网关同样能够支持这些上层协议,才能从中提取到特征。

举个例子,以下是一段基于SpringCloud实例中要到的Netflix Zuul网关的配置,Zuul是HTTP网关,/restful/accounts/** 和 /restful/pay/** 是HTTP中的URL的特征,而配置中的serviceId就是路由的目标服务。

routes: 
    account: 
        path: /restful/accounts/**
        serviceId: account
        stripPrefix: false
        sensitiveHeaders: "*"

    payment:
        path: /restful/pay/**
        serviceId: payment
        stripPrefix: false
        sensitiveHeaders: "*"

1.2 性能与可用性

由于网关是所有服务对外的总出口,是流量必经之地,所以网关的路由性能将导致全局的、系统性的影响。打个比方,如果经由网关时有1ms的性能损失,那整个系统所有服务的响应延迟都会增加1ms。网关的性能与它的工作模式和自身实现算法都有关系,但毫无疑问工作模式是最关键的因素。如果能够采用DSR三角传输模式,在实现原理上就决定了性能一定会比代理模式来的强(DSR、IPTunnel、NAT、代理等这些都是网络基础知识)。不过,因为今天REST和JSON-RPC等基于HTTP协议的服务接口在对外部提供的服务中占绝对主流的地位,所以我们所讨论的服务网关默认都必须支持七层路由,通常默认无法直接进行流量转发,只能采用代理模式。在这个前提约束下,网关的性能主要取决于它们如何代理网络请求,也即它们的网络I/O模型。

1.2.1 网络I/O模型

 在套接字接口抽象下,网络I/O的出入口就是Socket的读和写,Socket在操作系统接口中被抽象为数据流,而网络I/O可以理解为对流的操作。每一次网络访问,从远程主机返回的数据会先存放到操作系统内核的缓冲区中,然后从内核的缓冲区复制到应用程序的地址空间,所以当发生一次网络请求时,将会按顺序经历“等待数据从远程主机到达缓冲区”和“将数据从缓冲区复制到应用程序地址空间”两个阶段,根据实现这两个阶段的不同方法,人们把网络I/O模型总结为两类、五种模型:

  1. 两类是指同步I/O异步I/O
    1. 异步I/O:订外卖-->之后该干嘛干嘛-->等骑手通知。异步I/O中数据到达缓冲区后,不需要调用进程主动进行缓冲区复制数据的操作,而是复制完成后由操作系统向线程发送信号,所以是非阻塞的。
    2. 同步I/O:自己亲自去饭堂打饭
  2. 五种是指在同步I/O中又划分出
    1. 阻塞I/OBlocking I/O):自己亲自去饭堂打饭,饭堂没做好,只好等待(线程休眠),直到饭做好。这就是被阻塞。阻塞I/O是最直观的I/O模型,逻辑清晰,也比较节省CPU资源,但缺点是线程休眠所带来的上下文切换,这是一种需要切换到内核态的重负载操作,不应当频繁进行
    2. 非阻塞I/O(Non-Blocking I/O):你去饭堂,发现饭还没做好,你就回去了,然后每隔3分钟来一次饭堂看饭是否做好,一直重复,直到饭做好。非阻塞I/O能够避免线程休眠,对于一些很快就能返回结果的请求,非阻塞I/O可以节省切换上下文切换的消耗,但是对于较长时间才能返回的请求,非阻塞I/O反而白白浪费了CPU资源,所以目前并不太常用。
    3. 多路复用I/O(Multiplexing I/O): 多路复用I/O本质上是阻塞I/O的一种,但是它的好处是可以在同一条阻塞线程上处理多个不同端口的监听。比如:肯德基买套餐-->帮几个同事带-->发现套餐还没做好-->继续等待-->其中某个同事的套餐好了,送回去-->然后回来继续等待。多路复用I/O是目前高并发网络应用的主流,它还可以细分为select、epoll、kqueue等不同实现,这里就不再展开了。
    4. 信号驱动I/O(Signal-Driven I/O)四种细分模型: 去饭堂,饭没好-->跟厨师很熟,打好招呼饭好了叫你,然后返回-->接到厨师通知-->饭堂取饭返回。厨师通知就是信号,信号驱动I/O与异步I/O的区别在于“从缓冲区获取数据”,这个步骤的处理,前者收到了通知事可以进行复制操作了,即,要你自己从饭堂拿回宿舍,在复制完成之前线程处于阻塞状态,本质上它仍属于同步I/O操作,而后者异步I/O收到的通知是复制操作已经完成,即,有外卖小哥把饭给你送来。
    5. 异步I/O模型 如上4对比所述

以Zuul为例:

在Zuul 1.0时,它采用的是阻塞I/O模型来进行最经典的“一条线程对应一个连接”(Thread-per-Connection)的方式来代理流量。采用阻塞I/O模型意味着它会有线程休眠,就有上下文切换的成本,所以如果后端服务普遍属于计算密集型(CPU Bound,可以通俗理解为服务耗时比较长,主要消耗在CPU上)时,这种模型能够相对节省网关的CPU资源,但如果后端服务普遍都是I/O密集型(I/O Bound,可以理解为服务都很快返回,主要消耗在I/O上),它就会由于频繁的上下文切换而降低性能。

Zuul 2.0版本最大的改进就是基于Netty Server实现了异步I/O模型来处理请求,大幅度减少了线程数,获得了更高的性能和更低的延迟。根据Netflix官方给出的数据,Zuul 2.0大约要比Zuul 1.0快上20%左右。还有一些网关甚至支持自行配置,或者根据环境选择不同的网络I/O模型,典型代表就是Nginx,它可以支持在配置文件中指定select、poll、epoll、kqueue等并发模型。

网关的性能高低一般只会定性分析,要定量地说哪一种网关性能最高、高多少是很困难的,就像我们都认可Chrome要比IE快,但脱离了具体场景,快多少就很难说的清楚。网上也有不少关于各种网关的性能对比数据,但若脱离具体应用场景去定量地比较不同网关的性能差异还是难以令人信服,不同的测试环境和后端服务都会直接影响结果。

网络上也有不少关于各种网关的性能对比数据,但若脱离具体应用场景去定量地比较不同网关的性能差异还是难以令人信服,不同的测试环境和后端服务都会直接影响结果。

在网关的性能方面,我们应该考虑到以下几点:

  • 网关尽可能的轻量。在集群的角色定位,除了安全、认证、授权、限流、监控等功能,要对网关赋能符合自己业务场景的功能时要仔细权衡,取得功能性与可用性之间的平衡,过度增加网关的功能是危险的。
  • 网关选型,尽可能选择成熟的产品。比如:Nginx Ingress Controller、KONG、Zuul这些经过长期考验的产品,而不能一味地只考虑性能选择最新的产品,性能与可用性之间的平衡也需要权衡。
  • 在需要高可用的生产环境中,应当考虑在网关之前部署负载均衡器或者等价路由器(ECMP),让那些更成熟健壮的设施(往往是硬件物理设备)去充当整个系统的入口地址,这样网关也可以进行扩展。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章