【问题标题】:Netty worker threads and throughputNetty 工作线程和吞吐量
【发布时间】:2018-05-09 03:27:47
【问题描述】:

我创建了一个具有多个工作线程的 netty 服务器,以检查线程数量的增加如何改变吞吐量。 这是我使用的代码。它是Writing and echo server 的略微修改版本,可以在 Netty 网站上找到。

回声服务器计算

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class EchoServerCompute {

    private int port;

    public EchoServerCompute(int port) {
        this.port = port;
    }

    public void run(int threadCount) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup(threadCount);
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new EchoServerComputeHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          
             .childOption(ChannelOption.SO_KEEPALIVE, true); 

            ChannelFuture f = b.bind(port).sync(); 

            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 8080;
        new EchoServerCompute(port).run(Integer.parseInt(args[0]));
    }
}

EchoServerComputeHandler

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.lang.Math;
import java.math.BigInteger;


public class EchoServerComputeHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) { 
        BigInteger result = BigInteger.ONE;
        for (int i=0; i<2000; i++)
            result = result.multiply(BigInteger.valueOf(i));
        ctx.write(msg);
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

我使用 5 个工作线程和 50 个工作线程运行此服务器,并使用 JMeter 和 1000 个用户对其进行测试。但我在这两种情况下收到的吞吐量几乎相同。

我希望在使用更多工作线程时看到吞吐量增加。如果我在这里做错了什么,有人可以告诉我吗?

编辑
我运行它的测试环境有 2 个节点,分别指定为服务器和客户端。 Server 节点运行 netty 程序,Client 节点运行 JMeter。该服务器具有 Intel Xeon 5160 CPU 和 16GB RAM。客户端有一个 Intel Xeon E5506 CPU 和 8GB RAM。它们之间的链路是 1Gbps。

【问题讨论】:

  • 你弄清楚发生这种情况的原因了吗?

标签: java multithreading netty


【解决方案1】:

您在这里面临几个问题:

Java 太聪明了

for (int i=0; i<2000; i++)
        result = result.multiply(BigInteger.valueOf(i));

JIT 会将其检测为死代码并简单地将其完全删除。这意味着您的代码将在几分之一毫秒内完成。要解决此问题,请将 result 添加到响应中,使其无法消除。

您的硬件有限

更多的工作线程并不一定意味着更高的吞吐量,因为您的机器实际上需要能够处理工作负载。如果您还在同一台机器上运行 JMeter,您将不会看到吞吐量有任何增加 threads &gt;= amount_of_cpus / 2 请记住,如果您使用英特尔 CPU 具有注册为“真实”CPU 的超核心,但不会做任何工作。因此,如果您在 Intel 四核上运行此程序,则不要期望在第二个工作线程之后吞吐量会增加。

线程需要时间

实际上管理线程并在它们之间切换需要时间。因此,在系统中有一定数量的线程之后,您的吞吐量将明显下降。您从 5 步到 50 步太多,无法检测到这一点,请尝试以 2 个线程的步长前进。

线程混乱

线程的执行顺序未定义。因此,如果您运行足够多的线程,它们将开始相互窃取执行时间。有些可能会立即完成,而另一些则会排队等待几秒钟。在 50 个线程时,您会看到完成时间大大增加,这仅仅是因为有很多线程一直处于暂停状态。您可以通过比较最小和最大执行时间来看到这一点,随着线程数量的增加,执行时间应该会开始发散。

【讨论】:

    【解决方案2】:

    Netty 旨在支持非阻塞 I/O,这意味着线程不会被阻塞。从一个线程切换到另一个线程是有成本的,因此固定数量的线程更有效。这个号码通常是number_of_core × 2。 Java 的Executor 是在可用线程之间分配任务的正确抽象。

    试想一下,一旦每个内核都满负荷运行,创建更多线程将无济于事。将线程池大小增加到超过可用物理线程数仅有助于在阻塞 I/O 的情况下处理更多同时连接。

    如果您的任务不需要太长时间,您可以在与EventLoopGroup 相同的线程池中运行它们。不要试图调整线程数。相反,调整 I/O 和任务之间分配的线程总数。您可以使用两个单独的ExecutorsEventLoopGroup 为一个),也可以调整EventLoopGroup#setIoRatio 的值。

    【讨论】:

      【解决方案3】:

      因为大多数http服务器有两个工作线程限制。

      一个是'endpoint'的最大工作线程数。另一个是服务器的最大工作线程数。

      基于 ip adderss(或会话)的端点,一个端点的默认最大线程数为 5。因此,虽然您创建了 1000 个用户进行测试,但您的 1000 个用户属于一个端点,因此最大吞吐量始终为 5。

      这个限制是为了过度使用一个端点请求服务器,这将导致没有工作处理其他端点,这将是严重和危险的。

      【讨论】:

        【解决方案4】:

        我的想法:

        1. 删除执行乘法和重新测试的循环
        2. 检查您的 JMeter 配置。你能发布你的线程配置吗?
        3. 当前每秒请求数/吞吐量是多少?你的系统配置是什么?您可能会达到系统限制。

        【讨论】:

        • 1.您建议删除循环的任何理由?是因为@TwoThe 提到的原因吗? 2.你说的JMeter config,是.properties文件还是测试的.jmx文件? 3. 我在这两种情况下获得的吞吐量约为 17,000/秒。测试设置由指定为服务器和客户端的 2 个节点组成。服务器具有 Intel Xeon 5160 CPU 和 16GB RAM。客户端有一个 Intel Xeon E5506 CPU 和 8GB RAM。它们之间的链路是1Gbps
        猜你喜欢
        • 1970-01-01
        • 2018-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多