模拟高并发测试tomcat吞吐量

     这两天无事,正好学习下。出发点是, 怎样模拟高并发访问restful api。步骤如下:

1、客户端

    客户端模拟多线程访问,有两种方式:

   1.1、利用synchronized、object的wait和notifyAll方法,代码如下:

package com.mxsoft.web;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 模拟高并发
 *
 * @author zhangyingxuan
 */
public class SimulateHighConcurrency1 {
    static volatile int successNum = 0;
    static volatile int failNum = 0;

    public static void main(String[] args) throws InterruptedException {


        final Object obj = new Object();


        synchronized (obj) {


            List<Thread> threadList = new ArrayList<>();

            for (int i = 0; i < 1000; i++) {
                Thread th = new Thread(() -> {
                    try {
                        obj.wait();
                        TimeUnit.SECONDS.sleep(3);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    String doneWork = TestDemo.doneWork();
                    if ((doneWork.contains("success"))) {
                        successNum++;
                    } else {
                        failNum++;
                    }
                });
                threadList.add(th);
            }

            for (Thread thread : threadList) {
                thread.start();
            }

            obj.notifyAll();

            for (Thread thread : threadList) {
                thread.join();
            }

            System.out.println("run done: success -> " + successNum + "; fail -> " + failNum);
        }
    }
}

   1.2、利用jdk concurrent包下的api,代码如下:

package com.mxsoft.web;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 模拟高并发
 *
 * @author zhangyingxuan
 */
public class SimulateHighConcurrency2 {
    //请求总数
    public static int clientTotal = 100000;

    //同时并发执行的线程数
    public static int threadTotal = 100;

    private static AtomicInteger num = new AtomicInteger();

    public static volatile int successNum = 0;
    public static volatile int failNum = 0;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(1000);
        //信号量, 此处用于控制并发的线程数
        final Semaphore semaphore = new Semaphore(threadTotal);

        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for(int i = 0; i < clientTotal; i ++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    String doneWork = TestDemo.doneWork();
                    if (doneWork.contains("success")) {
                        successNum++;
                    } else {
                        System.out.println(doneWork);
                        failNum++;
                    }
                    semaphore.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
                System.out.println(num.incrementAndGet());
            });
        }

        countDownLatch.await();

        executorService.shutdown();

        System.out.println("successNum: " + successNum + " failNum: " + failNum);
    }
}

说明:

Executors.newCachedThreadPool() 这个方法,如果线程数太多,会造成机器之前重启。我的是mac电脑,5000个线程直接导致重启了。

2、服务器端

package com.mxsoft.web;

import com.mxsoft.util.ThreadPoolExecutorUtils;
import com.mxsoft.util.UserThreadState;
import com.mxsoft.util.UserUtils;
import com.mxsoft.web.bean.UserObj;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HellowordServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        UserObj currentUser = UserUtils.getCurrentUser();
        System.out.println(currentUser.getName() + "->" + currentUser.hashCode());

//        new Thread(new Runnable() {
//            @Override
//            public void run() {
//                UserObj user = UserUtils.getCurrentUser();
//                System.out.println("自线程: " + (user == null ? "user为null" : user.getName() + "->" + user.hashCode()));
//            }
//        }).start();


        ThreadPoolExecutorUtils.execute(new UserRunnable(new UserThreadState(currentUser)));

//        super.doGet(req, resp);

        resp.getWriter().write("success");
        resp.getWriter().flush();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

class UserRunnable implements Runnable {

    UserThreadState userThreadState;

    public UserRunnable( UserThreadState userThreadState) {
        this.userThreadState = userThreadState;
    }

    @Override
    public void run() {
        userThreadState.bind();
        UserObj user = UserUtils.getCurrentUser();

        //输出子线程的user信息
        System.out.println("自线程: " + (user == null ? "user为null" : user.getName() + "->" + user.hashCode()));
        userThreadState.restore();

        //输出富显成的user信息
        UserObj currentUser = UserUtils.getCurrentUser();
        System.out.println("original: " + currentUser.getName()+"->" + currentUser.hashCode());
    }
}

说明:服务器端其实就是一个servlet,没有其他的东西。

2.1、tomcat配置:

catalina.sh如下:

JAVA_OPTS="-Xmx1024m -Xms1024m -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=172.16.125.140 -Dcom.sun.management.jmxremote.port=8180 -Dcom.sun.management.jmxremote.authenticate=false"

server.xml如下:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
       maxThreads="400" maxQueueSize="80" minSpareThreads="30" maxIdleTime="60000"/>

   <Connector executor="tomcatThreadPool" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
       URIEncoding="UTF-8" compression="off" enableLookups="false" maxKeepAliveRequests="20" bufferSize="8192"
       connectionTimeout="5000" redirectPort="8443" maxPostSize="20971520"/>

两台tomcat,配置如上,除了端口差别,其他都是一样的。

2.2、用nginx做了负载均衡,nginx配置如下:

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
        upstream tomcats {
           server 127.0.0.1:8080;
           server 127.0.0.1:7080;
        }

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            #root   html;
            proxy_pass http://tomcats;
            index  index.html index.htm;
        }
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }
}

2.3、操作系统内核参数优化:

文件:/etc/sysctl.conf

vm.overcommit_memory = 1
#net.ipv4.ip_local_port_range = 1024 65536
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_abort_on_overflow = 0
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
#net.ipv4.netfilter.ip_conntrack_max = 2097152
net.nf_conntrack_max = 655360
net.netfilter.nf_conntrack_tcp_timeout_established = 1200

文件:/etc/security/limits.conf

*       soft    nofile  655350
*       hard    nofile  655350
ulimit -n 65535

ulimit -n

3、结论

    按照以上配置,并发1万个线程,100、80、60、50、30、20等等的并发量,有小于10%的失败率,并发量越小,失败率越低。

tomcat监控截图:

不知道,怎么保证100%的正常,请大家帮助我。

完整代码地址:代码

转载于:https://my.oschina.net/u/1170450/blog/1833010

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值