记一次spring cloud gateway Netty线程性能优化(附带压测)
作者:mmseoamin日期:2024-01-19

这里是weihubeats,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党

Spring cloud gateway version

  • 3.1.4

    背景

    线上的api-gateway网关在请求量过大的时候会偶尔出现如下报错

    io.netty.channel.ConnectTimeoutException: connection timed out:
    

    这说明网关存在一定的性能瓶颈,需要对网关进行性能优化或者扩容pod

    Spring cloud gateway IO模型

    我们通过查看Spring cloud gateway源码发现Spring cloud gateway使用的IO通信sdk主要是使用的reactor.netty

    初始化会去构建一个DefaultLoopResources

    记一次spring cloud gateway Netty线程性能优化(附带压测),第1张

    在创建DefaultLoopResources的时候我们看看他的一些构造参数

    记一次spring cloud gateway Netty线程性能优化(附带压测),第2张

    熟悉Netty的IO模型我们就能知道上面最核心的两个线程配置

    • IO_WORKER_COUNT
    • IO_SELECT_COUNT

      记一次spring cloud gateway Netty线程性能优化(附带压测),第3张

      一个是select线程数,一个是work线程数

      其中可以看到IO_WORKER_COUNT即work线程数,默认是cpu核数,最大值为4

      IO_SELECT_COUNT的线程数默认是-1,即不设置与IO_WORKER_COUNT共享一个线程池

      记一次spring cloud gateway Netty线程性能优化(附带压测),第4张

      一般我们传统的Netty通信配置都是会设置一个Boss线程池和一个Work线程池

      如果Boss和Work线程池公用一个会影响性能。也就是说Spring cloud gateway 默认是非主从Reactor多线程模式

      大概是这样

      EventLoopGroup eventGroup = new NioEventLoopGroup();
      ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(eventGroup);
      

      我们在开发Netty应用的时候一般都会使用主从Reactor多线程模式。

      也就是如下方式

      EventLoopGroup bossGroup = new NioEventLoopGroup();
      EventLoopGroup workGroup = new NioEventLoopGroup();
      ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup,workGroup);
      

      所以可以我们最好设置- IO_SELECT_COUNT线程数。

      这个参数spring cloud gateway没有提供配置的方式。只能通过系统参数去设置

      如何设置IO_SELECT_COUNT

      System.setProperty(ReactorNetty.IO_SELECT_COUNT,"1");
      

      压测

      实践是检验真理的唯一标准。这里我们通过压测添加IO_SELECT_COUNT和不添加IO_SELECT_COUNT配置进行压测看看spring cloud gateway的性能表现如何

      压测环境

      • 机器配置:Apple M1 hw.physicalcpu: 8
      • os版本: 13.4 (22F66)

        jmeter设置

        记一次spring cloud gateway Netty线程性能优化(附带压测),第5张

        3000个线程,循环两次。1秒执行

        这里如果不会Jmeter可以参考我之前的使用教程:

        https://blog.csdn.net/qq_42651904/article/details/118860462

        注意新版本的Jmeter默认返回的请求结果只有200个,如果需要观察全部可以修改配置jmeter.properties

        #view.results.tree.max_results=0
        

        把这个注释的#去掉

        记一次spring cloud gateway Netty线程性能优化(附带压测),第6张

        测试路由服务接口

        @GetMapping("/test")
        public  List test(String name) throws Exception{
            TimeUnit.MILLISECONDS.sleep(500);
            return mockSelectSql();
        }
        

        请求的接口故意休眠500毫秒,模拟存在一定耗时

        压测结果

        • 无任何配置
          序号averageMaxerror%
          1533077760.35%
          2443693018.03%
          33629897718.55%
          43164807426.02%
          5515678151.37%
          63907900213.63%
          73871975915%
          83557852719.97%
          • 新增IO_SELECT_COUNT = 1
            序号averageMaxerror%
            1515180515.45%
            2526080812.88%
            3537177320.33%
            4578580780.00%
            5561381902.48%
            6539780360.37%
            7127527730.00%
            8566482410.12%
            9574685890.00%

            总结

            可以看到增加IO_SELECT_COUNT线程数配置 可以明显减少error错误,即减少connection timed。目前是在mac测试数据,预计至少有20%左右的QPS提升

            其次还有一个可配置参数DEFAULT_IO_WORKER_COUNT,默认为cpu核数,最大为4

            如果cpu核数够多也可以增加该线程数,由于本机线程数有限,增加该线程数性能提升不明显