关于spring cloud gateway中 netty线程池的一点小优化

关于spring cloud gateway中 netty线程池的一点小优化

最近测试同学对系统进行压测。报出一个问题:几乎所有接口的成绩都不太好。甚至一些仅仅是主键查询,并且数据量不大的接口也是如此。

更新:看到评论说linux的epoll不配置ioSelectorCount效率更高。我这里也没太了解实际情况,具体是否要配置各位还是看自己实际的测试效果吧

排查过程中:跳过gateway网关,直接通过目标服务器ip进行压测发现成绩提升明显。初步判断是网关问题。
网上翻阅资料发现一个优化点,就是netty本身的线程池配置。
先看一下源码


package reactor.netty.resources;

import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import java.time.Duration;
import java.util.Objects;
import reactor.core.Disposable;
import reactor.core.publisher.Mono;

@FunctionalInterface
public interface LoopResources extends Disposable {
	// 这里是worker线程数,未配置的话。从cpu核心数和4直接取一个
    int DEFAULT_IO_WORKER_COUNT = Integer.parseInt(System.getProperty("reactor.netty.ioWorkerCount", "" + Math.max(Runtime.getRuntime().availableProcessors(), 4)));
    // 这里是select线程数 默认是-1
    int DEFAULT_IO_SELECT_COUNT = Integer.parseInt(System.getProperty("reactor.netty.ioSelectCount", "-1"));
    ....
    
    // 创建一个默认的资源,把两个线程数的参数传递过去
	static LoopResources create(String prefix) {
		if (Objects.requireNonNull(prefix, "prefix").isEmpty()) {
			throw new IllegalArgumentException("Cannot use empty prefix");
		}
		return new DefaultLoopResources(prefix, DEFAULT_IO_SELECT_COUNT, DEFAULT_IO_WORKER_COUNT, true);
	}
    ....

接下来看一下 DefaultLoopResources做了什么

DefaultLoopResources(String prefix, int selectCount, int workerCount, boolean daemon) {
		this.running = new AtomicBoolean(true);
		this.daemon = daemon;
		this.workerCount = workerCount;
		this.prefix = prefix;

		this.serverLoops = new AtomicReference<>();
		this.clientLoops = new AtomicReference<>();

		this.cacheNativeClientLoops = new AtomicReference<>();
		this.cacheNativeServerLoops = new AtomicReference<>();
		// 因为默认没有配置 所以selectCode必然是-1
		if (selectCount == -1) {
			this.selectCount = workerCount;
			// serverSelectLoops没有创建,而是直接使用的serverLoops
			this.serverSelectLoops = this.serverLoops;
			this.cacheNativeSelectLoops = this.cacheNativeServerLoops;
		}
		else {
			this.selectCount = selectCount;
			this.serverSelectLoops = new AtomicReference<>();
			this.cacheNativeSelectLoops = new AtomicReference<>();
		}
	}
	
	@SuppressWarnings("FutureReturnValueIgnored")
	EventLoopGroup cacheNioSelectLoops() {
		// 两个相等的话 使用 cacheNioServerLoops 返回工作组
		if (serverSelectLoops == serverLoops) {
			return cacheNioServerLoops();
		}
		
		EventLoopGroup eventLoopGroup = serverSelectLoops.get();
		if (null == eventLoopGroup) {
			EventLoopGroup newEventLoopGroup = new NioEventLoopGroup(selectCount,
					threadFactory(this, "select-nio"));
			if (!serverSelectLoops.compareAndSet(null, newEventLoopGroup)) {
				//"FutureReturnValueIgnored" this is deliberate
				newEventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
			}
			eventLoopGroup = cacheNioSelectLoops();
		}
		return eventLoopGroup;
	}

	// 这里相当于返回了工作组
	@SuppressWarnings("FutureReturnValueIgnored")
	EventLoopGroup cacheNioServerLoops() {
		EventLoopGroup eventLoopGroup = serverLoops.get();
		if (null == eventLoopGroup) {
			EventLoopGroup newEventLoopGroup = new NioEventLoopGroup(workerCount,
					threadFactory(this, "nio"));
			if (!serverLoops.compareAndSet(null, newEventLoopGroup)) {
				//"FutureReturnValueIgnored" this is deliberate
				newEventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
			}
			eventLoopGroup = cacheNioServerLoops();
		}
		return eventLoopGroup;
	}

可以看出来,如果未配置。netty是没有select线程组的。结合分析reactor模型可以发现,这种情况对处理效率是有影响的。而且最大只和cpu核心数量相同的配置也明显无法重复利硬件用资源。

目前解决是注入一下参数,当然也可以启动jvm时指定。两种都差不多

System.setProperty("reactor.netty.ioSelectCount","1");
// 这里工作线程数为1-4倍都可以。看具体情况
System.setProperty("reactor.netty.ioWorkerCount",String.valueOf(Math.max(Runtime.getRuntime().availableProcessors(), 4)));

我这里版本是reactor-netty-core-1.0.3,版本不一样的话 可能参数key不太一样。可以看一下LoopResources 中写的key

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值