Netty 模拟百万连接

作者: 良辰美景TT | 来源:发表于2018-12-06 10:34 被阅读6次

  我们知道单机的端口最多65536,除去系统使用的端口, 留给程序使用的也就6万个端口, 在需要对单机做长连接压力测试的时候,如果要测60W的长连接并发,就得找10台机器,而一般情况下我们并没有这么多的空闲机器去做这种规模的测试,那如何用两台机器模拟百万连接呢?对于TCP的连接,系统用一个4四元组来唯一标识:{server ip, server port,client ip,client port}。这里有两个变量是固定的, server ip与clinet ip。能做文章的也就是两台服务器的端口号了。如果server port 只开启一个端口的话, 那一台client最多也就 6W个连接能连上,多了因为端口的限制无法创建新的连接。如果server端多开几个端口,根据TCP的唯一标识,我们便能够模拟超过6W的连接测试了。处面是具体的代码,项目依赖netty,版本为4.1.25.Final。

  • server端代码如下:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFutureListener;
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 final class Server {

    static final int BEGIN_PORT = 10000;
    static final int N_PORT = 100;

    public static void main(String[] args) {
        new Server().start(BEGIN_PORT, N_PORT);
    }

    public void start(int beginPort, int nPort) {
        System.out.println("server starting....");

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childOption(ChannelOption.SO_REUSEADDR, true);

        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                                //每个连接都有个ConnectionCountHandler对连接记数进行增加
                ch.pipeline().addLast(new ConnectionCountHandler());
            }
        });

        //这里开启 10000到100099这100个端口
        for (int i = 0; i < nPort; i++) {
            int port = beginPort + i;
            bootstrap.bind(port).addListener((ChannelFutureListener) future -> {
                System.out.println("bind success in port: " + port);
            });
        }
        System.out.println("server started!");
    }
}
  • 统计服务端连接数的代码
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class ConnectionCountHandler extends ChannelInboundHandlerAdapter {

    //这里用来对连接数进行记数,每两秒输出到控制台
    private static final AtomicInteger nConnection = new AtomicInteger();

    static {
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
            System.out.println("connections: " + nConnection.get());
        }, 0, 2, TimeUnit.SECONDS);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        nConnection.incrementAndGet();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        nConnection.decrementAndGet();
    }

}
  • client端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
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.NioSocketChannel;

public class Client {

    //服务端的IP
    private static final String SERVER_HOST = "10.200.10.146";

    static final int BEGIN_PORT = 10000;
    static final int N_PORT = 100;

    public static void main(String[] args) {
        new Client().start(BEGIN_PORT, N_PORT);
    }

    public void start(final int beginPort, int nPort) {
        System.out.println("client starting....");
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(eventLoopGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.SO_REUSEADDR, true);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) {
            }
        });

        int index = 0;
        int port;
        //从10000的端口开始,按端口递增的方式进行连接
        while (!Thread.interrupted()) {
            port = beginPort + index;
            try {
                ChannelFuture channelFuture = bootstrap.connect(SERVER_HOST, port);
                channelFuture.addListener((ChannelFutureListener) future -> {
                    if (!future.isSuccess()) {
                        System.out.println("connect failed, exit!");
                        System.exit(0);
                    }
                });
                channelFuture.get();
            } catch (Exception e) {
            }

            if (++index == nPort) {
                index = 0;
            }
        }
    }
}

在linux机器上测试的时候,如果报了Could not initialize class sun.nio.ch.FileDispatcherImpl,这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄。解决办法如下:

  • 修改linux系统进程打开文件数的限制,文件在/etc/security/limits.conf。需要增加的行如下:
# * 表示对于任何用户, hard表示硬件的限制 , soft表示软件限制 nofile表示打开文件数
* hard nofile 1000000
* soft nofile 1000000
  • 修改linux系统能够打开文件的最大限制,文件在: /proc/sys/fs/file-max。需要增加的行如下:
1000000

相关文章

  • Netty 模拟百万连接

      我们知道单机的端口最多65536,除去系统使用的端口, 留给程序使用的也就6万个端口, 在需要对单机做长连接压...

  • netty的性能调优和总结

    性能调优 Netty 应用程序性能调优 能不能增加线程的数量 单机百万连接调优解决思路 如何模拟百万连接 突破局部...

  • Netty统计连接数

    Netty统计连接数 思路 netty如何统计当前的连接数?当有连接接入netty server的时候,Chann...

  • 突破netty单机最大连接数

    实现单机的百万连接,瓶颈有以下几点:1、如何模拟百万连接2、突破局部文件句柄的限制3、突破全局文件句柄的限制在li...

  • IdleStateHandler、心跳

    介绍: 对于netty这种高性能的网络通信框架来说,支持的连接数还是很可观的;当同时存在数百万连接的时候,对于这些...

  • Netty简单使用教程

    Netty是基于NIO实现的Java高性能网络库,号称可以达到单机百万连接,在业界上有大量实践,例如Spark,D...

  • netty源码分析之--新连接接入过程

    netty是在哪里检测有新连接接入的 新连接是怎么注册到NioEventLoop线程中的 Netty新连接接入处理...

  • 服务端技术实战系列——Netty篇

    一、概念&原理 二、Netty Client 创建并连接到netty-server端 publicBootstra...

  • 【六】小吴开始学Netty

    1.Netty是什么? 2.Netty基本组件 NioEventLoop(Netty发动机:监听客户端连接+处理客...

  • Netty实战:如何让单机下Netty支持百万长连接?

    单机下能不能让我们的网络应用支持百万连接?可以,但是有很多的工作要做。而且要考虑到单机的系统资源消耗能否支撑百万并...

网友评论

    本文标题:Netty 模拟百万连接

    本文链接:https://www.haomeiwen.com/subject/pibwcqtx.html