模拟高并发测试tomcat吞吐量

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

一、客户端java

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

   1.一、利用synchronized、object的wait和notifyAll方法,代码以下:git

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.二、利用jdk concurrent包下的api,代码以下:web

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);
    }
}

说明:apache

Executors.newCachedThreadPool() 这个方法,若是线程数太多,会形成机器以前重启。个人是mac电脑,5000个线程直接致使重启了。

二、服务器端api

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,没有其余的东西。tomcat

2.一、tomcat配置:bash

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.二、用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.三、操做系统内核参数优化:

文件:/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

三、结论

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

tomcat监控截图:

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

完整代码地址:代码

相关文章
相关标签/搜索