模擬高併發測試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%的正常,請你們幫助我。

完整代碼地址:代碼

相關文章
相關標籤/搜索