-->

左耳听风_057_56_管理设计篇之网关模式

你好,我是陈浩网名做尔多house.那今天呢我们要讲的内容是网关模式。

前面呢我们讲到side car和service mesh这两种设计模式,它们呢都是在不侵入业务逻辑的情况下,把控制面和数据面的处理结耦分离。

但是呢这两种模式都让我们的运维成本变得特别大。

因为每个服务都需要一个塞子,卡那这个呢就让本来就很复杂的分布式系统架构变得更为复杂和难以管理了。

在谈service match的时候呢,我们提到了get鬼。

我个人觉得并不需要给每个服务的实力都配置上一个sid car.其实呢一个服务集群啊配上一个gateway就可以了,或者是一组类似的服务配置上一个get腿。

那这样一来呢,gateway方式下的架构啊可以细到为每一个服务的实力配置一个自己的gateway,也可以做到为每一组服务配置一个甚至呢可以粗糙,为整个架构配置一个接入的gateway.于是呢整个系统架构的复杂度就会变得简单可控起来。

文中呢我用了一张图展示了一个多层的gateway架构。

那其中呢有一个总的dteway接入了所有的流量,并分发给不同的子系统,还有第二级gateway啊,用于做各个子系统的接入gateway.我们可以看到网关所管理的服务力度呢可粗可细。

通过网关呢,我们可以把分布式架构啊组织成一个星形架构,由网络对服务的请求进行路由和分发,也可以架构成像service match那样的网格架构,或者呢只是为了适配某些服务的set car.但是呢我们也可以看到,这样一来啊,塞的儿就不再那么清亮了,而且呢还有可能会变得比较重了。

那总的来说呢,gateway就是一个服务器,也可以说是进入系统的唯一节点。

那这个呢跟面向对象设计模式中的for set模式很像gateway封装内部系统的架构,并且呢给各个客户端提供了api那它呢还可能有其他的功能,比如授权监控、负载均衡、缓存、熔断降级、限流请求、分片和管理,还有静态响应处理啊等等。

那下面呢我们来谈一谈一个好的网关应该具有哪些设计功能。

一个网关呢需要有这么几个功能。

那第一呢就是请求路由,因为不再是塞的卡了,所以网关呢一定要有请求路由的功能。

那这样一来呢,对于调用端来说也是一件非常方便的事情。

因为调用端不需要知道自己需要用到的其他服务的地址,全部统一起来,交给gateway来处理。

那第二呢就是服务注册,为了能够代理后面的服务,立马请求啊路由到正确的位置上。

网关呢应该有服务注册功能,也就是后端的服务实例呢可以把它提供服务的地址注册取消注册。

嗯,一般来说呢注册啊也就是注册一些API接口。

比如说呢HTTP的reststful请求,就可以注册相应API的URI方法HTTP请求头。

那这样呢gateway啊就可以根据接收到的请求中的信息啊,来决定路由到哪一个后端的服务上。

呃,第三呢就是负载均衡。

因为一个网关呢可以接收多个服务的实地,所以网关呢还需要在各个对等的服务实力上做负载均衡策略。

简单点呢就是直接run robbin轮选,而复杂一点呢可以设置上权重进行分发。

那再复杂一点还可以做到session年连。

那第四呢就是弹力设计,网关呢还可以把弹力设计中的那些异物啊、重饰啊、密档啊、流控啊、熔断、还有监视等都可以实践进去。

那这样呢同样可以像service matsh那样,让应用服务,只关心自己的业务逻辑,而不是控制逻辑。

那最后呢是在安全方面的功能SSL加密和证书管理、筛审、验证、授权数据效应,还有对请求源进行恶意攻击的防范。

那错误处理越靠前的位置啊就越好。

所以网关呢就可以做到一个全栈的接入组件,来对后端的服务啊进行保护。

那当然呢网关啊还可以做更多更有趣的事情。

首先是灰度发布网关呢完全可以做到对相同服务的不同版本的实例进行导流,还可以收集相关的数据。

那这样呢对于软件质量的提升,甚至产品的试错呢都有非常积极的意义。

呃,其次呢就是APR的聚合。

使用网关呢可以将多个单独的请求聚合成一个请求。

在微服务体系的架构中呢,因为服务变小了,所以啊就有一个明显的问题,就是客户端呢可能需要多次请求才能得到所有的数据。

那这样一来啊,客户端与后端之间的频繁通信会对应用程序的性能和规模产生非常不利的影响。

于是呢我们就可以让网关来帮客户端请求多个后端的服务,然后呢把后端的服务的响应结果拼装起来,回传给客户端。

那当然呢这个过程也可以做成义务的,但这个呢需要客户端来配合。

那另外呢还有一个有趣的事情,就是API的编排。

同样在微服务的架构下,要走完一个完整的业务流程呢,我们需要调用一系列的API啊,就像一种工作流一样。

那这个事儿呢完全可以通过网页来编排这个业务流程。

我们可能通过一个DRCR来定义和编排不同的API,也可以通过像AWS拉姆纳夫那样方式来串联不同的API.那通过刚才的描述呢,我们可以看到网关、编车还有service mesh是非常像的,三种设计模式很容易混淆。

因此呢我想在这里啊明确一下这三种设计模式的特点、场景和区别。

首先呢set card的方式啊主要是用来改造已有的服务。

我们知道要在一个架构中实施一些架构变更的时候呢,需要服务方啊一起过来进行一些改造。

然而业务方的事情比较多,像架构上的变更啊会低优先级处理。

那这个呢就导致架构变更时的政治复杂度太高。

而通过set car的方式呢,我们就可以适配应用服务,成为应用服务进出请求的代理。

那这样呢我们就可以干很多对于业务方完全透明的事情。

那当side car在架构中越来越多的时候呢,就需要我们啊对side car进行统一的管理。

于是呢我们就为side car增加了一个全局的中心控制器啊,就出现了我们的service match.在中心控制器出现以后呢,我们发现可以把非业务功能的东西呢全部实现在sid card和controller中,于是呢就成为了一个网格。

那业务方呢只需要把这个服务啊往网格中一放就好了,与其他服务的通讯啊,服务的弹力档就都不用管了,像一个服务的pass平台。

然而呢service match的架构和部署都太过于复杂了,会让我们在运维层面上的复杂度啊变大。

那为了简化这个架构的复杂度呢,我认为sidecard的力度啊应该是可粗可细的那这样呢更为方便。

但是我认为啊用gateway更为适合,而且呢gateway只负责进入了请求,也像sid car还需要负责对外的请求。

In gateway呢可以把一组服务给聚合起来,所以服务对外的请求呢可以交给对方服务的gateway.于是呢我们就只需要用一个负责进入请求的gateway来简化掉,需要同时负责进出请求的side card的复杂度。

那总而言之呢,我觉得gateway的方式啊比sidecar和service match更好。

那当然呢具体问题啊还要具体分析。

那最后呢我们来谈一谈网关的设计重点。

那第一点呢就是高性能在技术设计上广关啊,不应该也不能成为性能的瓶颈。

那对于高性能呢最好使用高性能的编程语言来实现,如c啊CI加go,还有java广关对后端的请求和对前端的请求的服务啊,一定要使用异步非阻塞的IO来确保后端延迟,不会导致应用程序中出现性能问题。

那c和c加加呢,可以参看linux的eppo和windows的IO. Completion port里面的一步IO模型java下的如netty root x spring reactor的NIO框架。

那当然了,我还是更喜欢go语言的go routine加channel的玩法。

那第二点呢是高可用,因为所有的流量或调用啊都要经过网关,所以网关呢必须成为一个高科用的技术组件。

那它的稳定啊直接关系到了所有服务的稳定。

网关如果没有设计呢,就会变成一个单点故障。

因此啊一个好的网关至少要做到以下三点。

那第一呢就是集群化网关要成为一个集群,它最好可以自己组成一个集群,并可以自己同步集群数据,而不需要依赖于一个第三方系统来同步数据。

那第二呢就是服务化网关呢还需要做到在不间断的情况下修改配置。

那一种呢就是像index reload配置那样可以做到不停服务。

那另一种呢就是最好做到服务化,也就是说呢得要有自己的文命,API在运行时啊修改自己的配置。

那第三呢就是持续化。

比如重启呢就是像n这x那样优雅的重启,有一个主管请求分发的主进程。

当我们需要重启的时候呢,新的请求就被分配到新的进程中。

而老的进程处理完正在处理的请求之后呢,就退出。

那网关的设计重点除了高性能和高可用以外呢,第三点啊就是高扩展。

因为网关呢需要承接所有的业务流量和请求,所以一定会有或多或少的业务逻辑。

而我们都知道业务逻辑是多变和不确定,比如呢我需要在网关上加入一些和业务相关的东西,因此啊一个好的根位还是需要可以扩展的,并且能进行二次开发的。

当然呢像n jxson那样,通过model进行二次开发了,固然可以,但我还是觉得啊应该做成像AWS朗达那样的方式,也就是所谓的serveryless或者fast那样的方式。

另外呢在运维方面,广关啊应该有几个设计原则。

呃,第一呢就是业务松耦合,协议紧耦合。

在业务设计上呢,网关不应该与后面的服务之间形成服务耦合,也不应该有业务逻辑。

网关呢应该是在网络应用层上面的组件,不应该处理通讯协议体,只应该解析和处理通讯协议头。

另外呢除了服务发现之外呢,网关也不应该有第三方服务的依赖。

那第二呢就是应用监视,提供分析,数据网关上,需要考虑应用性能的监控。

那除了有相应后端服务的高可用的统计之外呢,还需要使用trace ID实施分布式链路跟踪,并统计好一定时间内每个API的吞吐量响应时间和返回码,以便启动弹力设计中的相应策略。

那第三个原则呢就是用弹力设计保护后端的服务网关上,一定要实现熔断、限流、重试和超时等弹力设计。

如果一个或者多个服务调用花费的时间过长了,那么就要接受超时并返回一部分数据,或者呢返回一个网关里缓存的上一次成功请求的数据。

你可以考虑一下这样的设计。

那第四呢就需要devps,因为网关这个组件太关键了,所以呢就需要带vous这样的东西将它发生故障的概率降到最低。

那这个软件呢需要经过精良的测试,包括功能和性能的测试,还有啊信号测试,还需要有一系列的自动化运维的管控工具。

那在整体的架构方面呢,也有一些需要注意的事项。

那第一呢就是不要在网关中的代码里啊,内置聚合后端服务的功能,而应该考虑将聚合服务放在网关核心代码之外。

那可以使用plugin的方式也可以放在网关后面,形成一个services服务。

呃,第二呢,网关应该靠近后端服务并和后端服务啊使用同一个内网。

那这样呢就可以保证网关和后端服务调用的第一延迟,就可以减少很多网络上的问题。

那这里呢我多说一句,网关处理的静态内容呢应该靠近用户,而网关和此时的动态服务呢应该靠近后端服务。

那第三呢广关啊也需要做容量扩展,所以呢就需要成为一个集群来分担前端带来的流量。

那这一点呢要么通过DNS轮询的方式来实现。

要么呢通过CDN来做流量调度,或者呢通过更为底层的性能更高的负载均衡设备。

那第四呢,对于服务发现可以做一个时间不长的缓存,那这样呢就不需要每次请求啊都去查一下相关的服务所在的地方。

那当然呢如果你的服务不复杂,可以考虑把服务发现的功能啊直接集成进网关之中。

那第五点呢就是为网关啊,考虑包含了设计方式,用不同的网关服务,不同的后端服务,或者用不同的网吧服务前端不同的客户。

那另外呢,因为网关是用户请求和后端服务的桥接装置,所以呢就需要考虑一些安全方面的事宜啊,具体呢有这几点。

那第一呢就是要加密数据,可以把SSL相关的证书啊放到网关上,由网关啊做统一的SSL传输管理。

那第二呢就是校验用户的请求,一些基本的用户验证可以放到网关上来做。

比如用户是否已登录,用户请求中的token是否合法等等。

但是呢我们需要权衡一下网关是否要校验用户的输入。

因为这样一来呢,网关啊就要从只关心协议头变成了要关心协议体。

而协议体中的东西呢,一方面不像协议头是标准的那另一方面呢解析协体啊还需要耗费大量的运行时间,从而降低网关的性能。

那对此呢我想说的是要看具体需求。

一方面如果协议体是标准的,那么可以干。

那另一方面呢,对于解析协议所带来的性能问题,需要做相应的隔离。

那第三呢就是要检测异常访问。

网关呢需要检测一些异常访问,比如在一段比较短的时间内,请求次数超过一定数值。

再比如呢统一客户端的四叉叉请求出错率太高等等。

那对于这样的一些请求访问呢,网官一方面要把这样的请求给屏蔽掉。

另一方面呢需要发出警告,因为这有可能会是一些比较重大的安全问题,比如被黑客攻击了。

好了,我们来总结一下今天分享的主要内容。

首先呢网关模式能代替编车模式,呃,区别呢就是他把分布在各服边上的编车换成了集中式的网关。

网关呢不必管理所有的服务节点,而是可以根据需要为指定的服务集群配上网关,也可以在网关前面加上更高层的网关,从而构造出一个新型的结构。

那接着呢我列举了网关模式的功能特性。

嗯,然后呢我又介绍了网关模式的设计重点,由于网关的功能比较多啊,因此在设计上需要考虑的点也比较多,需要我们仔细的思考和斟酌。

那下一节课呢我们会讲述部署升级策略,希望能对你有帮助。

也欢迎你分享一下你接触到的分布式系统有没有用到网关呢?网关的功能如何呢?有没有把服务的弹力设计做在里面呢?文末呢我给出了分布式系统设计模式系列文章的目录,希望能在这个列表里啊找到自己感兴趣的内容。