您的位置  > 互联网

微服务中的“网关”与“服务节点”的区别

在单体架构中,我们一般不会强调“网关”的概念,因为将流量分发到各个单体系统副本的负载均衡器本质上起到了内部服务和外部调用之间网关的作用。

然而在微服务环境中,网关的存在感大大增强,甚至成为微服务集群中必不可少的设施之一。

原因并不难理解。 大家可以想一想,在微服务架构下,每个服务节点负责不同的团队,他们有各自独立的、不同的能力。 因此,如果服务集群没有统一的代理角色进行外部交互,那么外部服务消费者必须知道集群中所有微服务的精确坐标(我在上一讲中介绍过“坐标”的概念)。

这样,消费者不仅会受到服务集群的网络限制(无法保证集群中的每个节点都有外部网络连接),还会受到安全限制(不仅是服务节点的安全,还受到安全限制)。外部本身会受到浏览器【同源策略】约束等限制)和依赖限制(服务坐标等信息不属于外部接口承诺的一部分,可能随时发生变化,因此您不应该依赖它) )。 就连我们自己也不太可能愿意记住每个服务的坐标来编写代码。

因此,微服务中网关的首要职责就是为外部服务提供统一的地址,并将访问该地址的外部流量按照适当的规则路由到集群内部正确的服务节点。 也正是因为如此,微服务中的网关常常被称为“服务网关”或者“API网关”。

可见,微服务的网关首先应该是路由器。 在满足这个前提的基础上,网关还可以根据需要作为流量过滤器,提供一些额外的可选功能。 如安全、认证、授权、限流、监控、缓存等。

简而言之:

网关=路由器(基本功能)+过滤器(可选功能)

在“路由”的基础功能中,服务网关主要考虑“网络层和协议”以及能否支持路由的“性能和可用性”两个因素。 接下来我们就围绕这两个因素来讲解路由的原理和知识点。

小吉特地为大家整理了关于《微服务网关》比较完整的内容。 点击下方卡片即可免费学习:

网络层和协议

在【第20讲“负载均衡器”】中,我向大家介绍了四层流量转发和七层流量代理。 这里所说的“层”是指OSI第7层协议中的各层。 更具体一点,其实就是“四楼”和“七楼”的意思。

从技术实现的角度来看,负载均衡器和服务网关路由流量的实现没有什么区别。 很多服务网关本身都是基于老的负载均衡器实现的,比如Nginx以及相应的等; 从路由目的来看,负载均衡器和服务网关的区别在于,前者是根据均衡算法对流量进行均匀路由,而后者是根据流量中的某些特征来正确路由流量。 路由。

也就是说,网关必须能够识别流量中的特征,这意味着网关能够支持的网络层数和通信协议的多少将直接限制后端服务节点可以选择的服务通信方式:

我们直接看一个例子。

这里是【Fenix的基于实现】中使用的Zuul网关配置的一段内容。 Zuul 是一个 HTTP 网关。 “`///**`”和“`//pay/**`”是HTTP中URL的特征,配置中的“”是路由的目标服务。

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

最后提醒大家:现在,围绕微服务的各种技术正处于快速发展时期。 我其实并不提倡你去记住每个框架本身的配置细节,也就是说,你不需要担心上面给出的配置的具体写法以及每条指令的含义。 因为如果你从根本上了解了网关的原理,那么你可以很容易地参考技术手册将上面给出的信息重写为Istio或其他服务网关所需的配置形式。

好,我们来看看服务网关支持路由的另一个重要因素:性能和可用性。

性能和可用性

性能和可用性是网关的主要关注点。 由于网关是所有业务的总出口,是流量必须经过的地方,因此网关的路由性能是全局性的、系统性的。 如果一个服务通过网关路由,就会有10毫秒的性能损失,这意味着整个系统所有服务的性能都会降低10毫秒。

网关的性能与其工作模式和自身实现有关,但毫无疑问工作模式是最重要的。 如果网关能够采用三角传输模式(DSR,数据链路层负载均衡模式),原则上性能会比代理模式更好(DSR,代理等都是【负载均衡】的基础知识,你可以回去复习一下)。

但由于如今对外提供的服务中,基于REST、JSON-RPC等基于HTTP协议的接口形式占据了绝对主流,所以我们这里讨论的服务网关必须默认支持七层路由,所以通常默认为无法转发,只能使用代理模式。

在此前提下,网关的性能主要取决于其代理网络请求的方式,即其网络I/O模型。 既然如此,我们就来学习一下网络I/O的基础知识,分析一下网络I/O模型的工作原理,从而了解不同网关的特点和性能差异。

网络I/O基础知识

在接口的抽象下,网络I/O的本质其实就是读,在操作系统接口中将其抽象为数据流,网络I/O可以理解为对流操作。

对于每次网络访问,从远程主机返回的数据都会首先存储在操作系统内核的缓冲区中,然后从内核缓冲区复制到应用程序的地址空间。 因此,当网络请求发生时,它会依次经历“在缓冲区中等待来自远程主机的数据到达”和“将数据从缓冲区复制到应用程序地址空间”两个阶段。

然后,根据完成这两个阶段的不同方法,我们可以将网络I/O模型概括为两大类、五种模型。 这两类指的是同步I/O和异步I/O; 这五类是指同步I/O,分为阻塞I/O、非阻塞I/O、复用I/O和信号驱动I/O。 /O四种细分模型。

同步是指调用者发送请求后,必须等待才能得到结果。 相反的是异步。 调用请求发送后会立即返回,不会立即获取处理结果。 该结果将通过状态更改和回调通知。 给来电者。 阻塞和非阻塞I/O的请求处理过程是指在接收调用请求并返回结果之前是否会挂起当前处理线程。

当然,这种概念性的解释对于你来说可能不太容易理解,那么我就用“你怎么得到饭盒”的场景来类比地给你解释一下:

异步 I/O (I/O)

这就像从某组外卖中订购午餐盒一样。 付完钱后,你就可以去做你该做的事了。 骑手自然会在门口打电话给您,让您知道餐点何时准备好。 因此,在异步I/O中,数据到达缓冲区后,调用进程不需要主动从缓冲区复制数据。 相反,复制完成后,操作系统向线程发送信号,因此必须是* *非阻塞**。

同步输入/输出(I/O)

这就像自己去食堂买饭一样。 此时,可能会出现以下几种情况:

阻塞 I/O (I/O)

你去食堂,发现饭菜还没准备好。 你不能做任何其他事情,只能小睡(线程睡眠)直到饭菜准备好。 阻塞 I/O 是最直观的 I/O 模型。 逻辑清晰,节省CPU资源。 但缺点是线程睡眠引起的上下文切换。 这是一个很重的负载,需要切换到内核态。 操作不宜频繁进行。

非阻塞 I/O(非 I/O)

你去食堂发现饭还没做好,就回去,然后每隔三分钟就来食堂看看饭有没有做好,直到饭做好了。 非阻塞 I/O 可以避免线程休眠。 对于一些能够快速返回结果的请求,非阻塞I/O可以节省上下文切换的消耗。 然而,对于需要很长时间才能返回的请求,非阻塞I/O是徒劳的。 浪费CPU资源,目前不常用。

多路复用 I/O (I/O)

多路复用I/O本质上是阻塞I/O的一种,但它最大的优点是可以处理同一个阻塞线程上多个不同端口的监控。 可以类比这样的情况:你是一个活雷锋,代表整个宿舍去食堂取饭。 到了食堂,发现饭菜还没有准备好,于是继续打瞌睡。 然而,如果你室友的食物准备好了,你会立即拿走。 那顿饭被送了回去,然后他继续打瞌睡,哼着歌,等待其他饭菜准备好。 复用I/O是目前高并发网络应用的主流。 还可以细分,epoll等不同的实现。

信号驱动 I/O (-I/O)

你去食堂,发现饭菜还没有准备好,但是你和厨师很熟悉,告诉他等饭菜做好了他会打电话给你,然后回去做你应该做的事。 接到厨师的通知后,你将饭菜带出食堂。 带着它回宿舍。 这里厨师的通知就是“信号”。 信号驱动 I/O 和异步 I/O 之间的区别在于“从缓冲区获取数据”步骤的处理。 前者收到通知后即可开始复制操作。 ,就是要从食堂把饭菜带回宿舍。 线程在复制完成之前被阻塞,因此仍然是同步I/O操作; 后者收到复制操作已完成的通知,即外卖店哥已经送餐了。

显然,异步I/O模型是最方便的。 毕竟,如果能叫外卖,谁愿意去食堂,但前提是你们学校必须允许美团送外卖。 因此,异步I/O受到操作系统的限制。 NT内核早在3.5及更高版本就通过[IOCP](/wiki/IOCP)实现了真正的异步I/O模型。 Linux系统下,在Linux 2.6中首次引入,目前尚不完善。 因此,在Linux下实现高并发网络编程时,复用I/O模型仍然是主要模式。

网关性能注意事项

好吧,回到服务网关的话题。 现在我们已经掌握了网络I/O模型的知识,理论上我们可以定性分析不同网关的性能差异。

服务网关处理请求代理时,包括两套网络操作,即“作为服务器对外部请求的响应”和“作为客户端对内部服务的调用”。 理论上,这两套网络操作可以使用不同的网络I/O模型来完成,但一般来说这是没有必要的。

为什么? 让我给你举一个使用 Zuul 网关的例子。

在Zuul 1.0中,它以最经典的“一个线程对应一个连接”(-per-)的方式使用阻塞I/O模型来代理流量,而使用阻塞I/O意味着它会有一个线程休眠时,上下文切换是有代价的。

因此,如果后端业务一般是计算密集型的(CPU Bound,一般可以理解为业务耗时较长,主要消耗在CPU上),这种模式可以节省网关的CPU资源。 但如果后端服务一般都是I/O密集型(I/O Bound,可以理解为服务返回快,主要消耗在I/O上),就会因为频繁的上下文切换而降低性能。

所以在Zuul 2.0版本中,最大的改进就是基于Netty实现了异步I/O模型来处理请求,大大减少了线程数量,实现了更高的性能和更低的延迟。 根据官方数据,Zuul 2.0 比 Zuul 1.0 快约 20%。 当然,还有一些网关。 我们也可以自己配置,或者根据环境选择不同的网络I/O模型。 典型的是Nginx,它可以支持配置文件中指定的poll、epoll等并发模型。

然而,网关的性能通常只能进行定性分析。 很难定量地说哪个网关的性能最高以及高出多少。 就像我们都一致认为它比IE快,但是快多少呢? 我们很难说清楚。

所以虽然我上面引用了官方对Zuul两个版本的定量对比,而且网上也有很多各个网关的性能对比数据,但是在没有具体的应用场景的情况下,还是很难定量比较不同网关的性能差异。 确信无疑,毕竟不同的测试环境和后端服务会直接影响结果。

网关可用性注意事项

好的,我们还需要注意的一件事是网关的可用性。 任何系统的网络调用过程中都会至少存在一个单点,这是由用户仅通过唯一地址访问系统所决定的。 即使对于淘宝、亚马逊等部署在全球多个数据中心的大型系统,为多个数据中心翻译地址的权威DNS服务器也可以被视为其单点。

对于比较常见的小型系统(小型的比较淘宝),网关,扮演着后端对外服务代理的角色,往往被视为系统的入口,很容易成为网络访问的单点。 这时,它的可用性就显得尤为重要。

另外,由于网关是唯一的,所以它不像以前服务发现中使用的注册中心。 可以直接作为集群使用,任何问题接入任何一个都可以解决。 因此,针对这种情况,我们在网关可用性方面应该考虑以下几点:

这里我提到了网关的唯一性、高可用性和可扩展性,所以我还要谈谈近年来微服务流行的“BFF”(for)概念。

这个概念目前还没有权威的中文翻译,但在我们讨论的语境中,它的含义可以理解为网关不必为所有前端提供无差别的服务,而是应该为不同的前端聚合不同的服务。结束。 提供对不同接口和网络访问协议的支持。

例如,对于运行在浏览器中的Web程序,由于浏览器一般只支持HTTP协议,所以服务网关应该提供基于REST等HTTP协议的服务,但同时,我们也可以为运行的程序部署另一组网关在桌面系统上。 ,它拥有与Web网关完全不同的技术选型,可以提供基于更高性能协议(如gRPC)的接口,以获得更好的体验。

那么这个概念想要表达的是,在网关这样的边缘节点上,针对同一个后端集群剪裁、适配、聚合不同的前端服务,有利于稳定后端,有利于前端赋能。 有能力的。

概括

这里我们讨论的主要话题是网关,但我只向大家介绍了网关的路由功能。 其他可以在网关上实现的过滤功能如限流、容错、安全、认证等在课程中都有讨论(极客时光搜索》周志明的《软件架构课程》中有专门讲解),所以我们这里不再展开。

那么在路由方面,由于我们讨论的服务网关必须默认支持七层路由,所以通常不能默认转发,只能使用代理模式。 因此,你需要掌握这个核心知识点:在必须支持七层路由的前提下,网关的性能主要取决于它如何代理网络请求。 换句话说,你需要了解他们的网络I/O模型。 现在,了解了典型的网络I/O模型是如何工作的,希望大家在后续的学习或者实践过程中看到网关的I/O模型时,能够大致了解其特点和性能。 法官。

小吉特地为大家整理了关于《微服务网关》比较完整的内容。 点击下方卡片即可免费学习: