暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

架构修炼之道-API网关的管道

看点有用的 2021-09-05
1801

在日常工作中经常会听到网关这个词汇,一般情况下网关特指API网关,即API Gateway,其作用是将所有的API调用统一接入API网关层,由网关层负责接入和输出。今天就简单聊一下API网关在面对各种流量和错误冲击时如何保证其健壮性。

一.API网关简介

     API网关主要解决微服务下客户端调用和统一接入的问题。使用了API网关之后,各个API服务提供方可以专注于自己的业务逻辑处理,而API网关更专注于安全、流量和路由等问题。

     与代理不同,网关在数据透传的背景下还会涉及到协议的转换,例如将用户请求的HTTP协议转换为RPC协议,而代理只是纯粹的进行数据透传。网关的工作原理如下图所示:


     一个API网关的核心能力包括统一接入、协议适配、流量管控与容错,以及安全防护。网关的首要功能是负责统一接入,然后将请求的协议转换为内部的接口协议,在调用的过程中还有限流、降级和熔断等容错方式来保护网关的整体稳定,同时网关还要做到基本的安全防护措施,例如IP地址白名单。

二.管道技术实现原理

     网关应对流量管控与容错主要有降级、限流、熔断和管道技术等方案,本节将主要介绍管道技术是如何实现网关的流量管控。

2.1 管道的实现

     对于API网关而言几乎没有任何业务逻辑,可以将其理解为一条直达服务提供者的笔直的马路,要以最快捷的方式调用提供者的API,而管道技术就是在这条马路上的各种检查站,例如参数校验,通过一定的顺序将这些管道组织起来就实现了管道技术,如下图所示:


     想要实现上图中的管道技术,首先要定义各个功能Pipe类,然后将Pipe类包装成一个实现了Runnable的Task(PipeTask),再将Task交给实现定义好的ThreadPool线程池来处理,如下图所示:


     管道的具体实现步骤及代码示例如下:

     第一步,定义一个Pipe,代表一个功能,例如参数校验,代码如下:

public class HttpPipeInput{
public HttpServletRequest request;
public HttpServletResponse response;

public HttpPipeInput(HttpServletRequest request,HttpServletResponseresponse,
HttpPipeManagerpipeManager){
this.request = request;
this.response = response;
}

// 具体业务逻辑
}
复制


     PipeInput中封装了HttpServletRequest和HttpServletResponse,当使用Servlet3的异步特性时会将I/O线程和业务线程分开,在最终业务处理时就会使用这两个对象,代码如下:

public class APipe extends Pipe{
public void doPipe(PipeInput pipeInput,PipeResult pipeResult){
// 具体业务逻辑
}
}
复制


     第二步,实现一个PipeTask,获取管道池,代码如下:

public class PipeTask implements Runnable{

public void run(){
// 获取管道池
Pipe[] pipes = pipeManager.getPipes();
if(pipes != null){
// 遍历管道
for(Pipe pipe : pipes){
Pipe pipeHandle = pipe;
if(pipeHandle != null){
// 执行处理
pipeHandle.doPipe(pipeInput,pipeResult);
}
}
}
}
}
复制

第三步,将一个Pipe包装成一个Task,代码如下:

new PipeTask(pipe);
复制

第四步,将Task交给线程池去处理,遍历执行管道内的任务,然后执行对应的功能,代码如下:

   PipeTask[] pipeTasks = event.getPipeTasks();
for(PipeTask pipeTask : pipeTasks){
if(pipeTask != null) {
threadPool.excute(pipeTask);
       }
}
复制

2.2 管道的获取

     从2.1节中可知,可以通过pipeManager来获取管道池,进而获取管道,因此首先需要将管道装入池中,交由pipeManager来管理,接着再通过管道名称来获取,代码如下:

   public PipeManager getHttpPipeManager(String methodName){
if(StringUtils.isBlank(methodName)){
throw new PipeException("接口入参为空");
}

if(!httpPipeManagerPool.containsKey(methodName)){
addMethod(methodName);
       }
// 从管道池获取管道管理类
return httpPipeManagerPool.get(methodName);
}

    public void addMethod(String methodName){
// 添加管道管理类到管道池
httpPipeManagerPool.put(methodName,pipeManager);
}
复制

2.3 管道的传输

     管道的信息传递是单向的,传递的顺序是按照管道池里管道的排列顺序来传递的。

     管道之间通过封装好的PipeInput来进行传递,在传递过程中如果不再更新PipeInput的属性那么就会跑完整个管道;如果中途有变化需要更新,例如参数校验管道需要更新PipeInput对象的属性,那么参数校验管道的下一管道中就会使用最新的PipeInput对象。

三.管道技术与责任链模式

     责任链模式是一种行为模式,在这种模式下能够让多个对象都有机会去处理请求,这些对象被连成一条链路,请求沿着链路传递,直到有对象处理该请求,而管道技术则是责任链模式的一种思维演化。

     责任链模式由一个抽象处理类和具体处理类组成,其中在抽象处理类中有一个成员变量和一个处理请求的方法,如果此时满足被处理的条件则由本对象的请求处理方法去处理,否则就会向下传递,而具体处理类主要处理具体的逻辑和实现具体的适用条件场景。

     管道技术与责任链模式的区别在于管道技术更加灵活,他是由开发者自定义的一种方式,相比于责任链模式的成员变量和处理方法,管道技术没有这些具体的限制,因此使用起来更加灵活。

四.小结

     本文主要阐述了管道技术的实现原理以及与责任链模式的区别,在日常工作中难免遇到大流量和错误冲击场景,通过管道技术可以很好的应对这样的场景,同时了解管道技术与责任链模式的区别可以更好的开拓我们的抽象思维,并且将思维实际转换落地。

文章转载自看点有用的,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论