技术

一个API网关性能优化实践之路

2019-07-02  本文已影响2707人  linking12

前言

最近换了一份工作,而新工作是调研下目前业界Api网关的一些性能情况,而在最近过去一年的时间里,我也主要开发了一个Api网关来支持协议适配的需求,但是由于前东家的话整个流量都不大,而相应的性能优化也没有很好的去做,借着让原来在唯品会的同事把网关推到了OYO在做性能压测及我刚入职新单位接手的第一项任务,把网关的性能进行了一下优化,也踩了一些坑,把这些作为总结写下来;本文是https://juejin.im/post/5d19dd5c6fb9a07ec27bbb6e?from=timeline&isappinstalled=0
的补充,主要是介绍整个优化步骤;

网关简介

Tesla的整个网络框架是基于littleproxy[https://github.com/adamfisk/LittleProxy],littleproxy是著名的软件的后端代理,按照常规性能应该不错,在此基础上我们加了些功能,具体代码在:[https://github.com/spring-avengers/tesla]

  1. HttpFiltersAdapter的clientToProxyRequest方法,负责调用方到代理方的拦截处理
public HttpResponse clientToProxyRequest(HttpObject httpObject) {
     logStart();
     HttpResponse httpResponse = null;
     try {
         httpResponse = HttpRequestFilterChain.doFilter(serveletRequest, httpObject, ctx);
         if (httpResponse != null) {
             return httpResponse;
         }
     } catch (Throwable e) {
         httpResponse = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_GATEWAY);
         HttpUtil.setKeepAlive(httpResponse, false);
         logger.error("Client connectTo proxy request failed", e);
         return httpResponse;
     }
     ...
 }
  1. HttpFiltersAdapter的proxyToClientResponse方法,负责从后端服务拿到请求返回给调用方的拦截处理
public HttpObject proxyToClientResponse(HttpObject httpObject) {
      if (httpObject instanceof HttpResponse) {
          HttpResponse serverResponse = (HttpResponse)httpObject;
          HttpResponse response = HttpResponseFilterChain.doFilter(serveletRequest, serverResponse, ctx);
          logEnd(serverResponse);
          return response;
      } else {
          return httpObject;
      }
  }

优化步骤

这个线程模型的话,整个处理请求及转发请求都复用同一个线程,而这种做法的话线程的切换基本没有;
而相应的代码如下:

  /**
     * Opens the socket connection.
     */
    private ConnectionFlowStep connectChannel = new ConnectionFlowStep(this, CONNECTING) {
        @Override
        public boolean shouldExecuteOnEventLoop() {
            return false;
        }

        @Override
        public Future<?> execute() {
            //复用整个ClientToProxy的处理IO的线程
            Bootstrap cb = new Bootstrap().group(ProxyToServerConnection.this.clientConnection.channel.eventLoop())
                .channel(NioSocketChannel.class)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, proxyServer.getConnectTimeout())
                .handler(new ChannelInitializer<Channel>() {
                    public void initChannel(Channel ch) throws Exception {
                        Object tracingContext =
                            ProxyToServerConnection.this.clientConnection.channel.attr(KEY_CONTEXT).get();
                        ch.attr(KEY_CONTEXT).set(tracingContext);
                        initChannelPipeline(ch.pipeline(), initialRequest);
                    }

                ;
                });
            if (localAddress != null) {
                return cb.connect(remoteAddress, localAddress);
            } else {
                return cb.connect(remoteAddress);
            }
        }
    };

这种做法zuul2也是如此做,文章可以看看这篇介绍比较详细:https://www.jianshu.com/p/cb413fec1632

image.png

总结

上一篇 下一篇

猜你喜欢

热点阅读