背景
朋友有这样的一个需求,在5分钟发起200万次请求 ,就尝试一下
简单计算下
- 2000000 / 300 大概每秒 7000次请求 同步请求无法
按照每个API 20字节 网络流量是 20 * 7000 140k
技术方案
Java线程池 (试试阿里开源JDK 启用协程试试)
- 异步请求 (okhttp 异步调用 http线程池)
- 操作系统调优
代码案例
服务端代码(建议使用Go)
package mainimport ("log""net/http""runtime")const (httpPort = "8088")func main() {runtime.GOMAXPROCS(runtime.NumCPU() - 1)hello := func(w http.ResponseWriter, req *http.Request) {data := "Hello, World!"w.Header().Add("Server", "golang")w.Write([]byte(data))return}http.HandleFunc("/", hello)err := http.ListenAndServe(":"+httpPort, nil)if err != nil {log.Fatal("ListenAndServe: ", err)}}
客户端代码
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency>
package ren.shuaipeng.oom.basic;import com.google.common.util.concurrent.ThreadFactoryBuilder;import okhttp3.*;import org.jetbrains.annotations.NotNull;import java.io.File;import java.io.IOException;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;public class Diaobao {public static OkHttpClient client = new OkHttpClient.Builder().cache(new Cache(new File(System.getProperty("java.io.tmpdir") , "http_cache"),50L * 1024L * 1024L)).eventListenerFactory(PrintingEventListener.FACTORY).connectTimeout(10,TimeUnit.SECONDS).readTimeout(10,TimeUnit.SECONDS).connectionPool(new ConnectionPool(50,5,TimeUnit.MINUTES)).build();public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),Runtime.getRuntime().availableProcessors() * 2,60, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1000000),new ThreadFactoryBuilder().setDaemon(true).setNameFormat("demo-pool-%d").build(),new ThreadPoolExecutor.AbortPolicy());executor.execute(new CallApiCountTask());for (int i = 0; i< 999999;i++) {executor.execute(new CallApiTask());}executor.shutdown();}static final AtomicLong secondCount = new AtomicLong(0L);static class CallApiCountTask implements Runnable {@Overridepublic void run() {while (true) {try {secondCount.set(0L);Thread.sleep(1000L);System.out.println(secondCount.get());} catch (InterruptedException e) {e.printStackTrace();}}}}static class CallApiTask implements Runnable {@Overridepublic void run() {Request washingtonPostRequest = new Request.Builder().url("http://127.0.0.1:8088").build();client.newCall(washingtonPostRequest).enqueue(new Callback() {@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {String demo = response.body().string();}@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {e.printStackTrace();}});}}static class PrintingEventListener extends EventListener {public static final Factory FACTORY = new Factory() {final AtomicLong nextCallId = new AtomicLong(1L);@Override public EventListener create(Call call) {long callId = nextCallId.getAndIncrement();return new PrintingEventListener(callId, System.nanoTime());}};final long callId;final long callStartNanos;public PrintingEventListener(long callId, long callStartNanos) {this.callId = callId;this.callStartNanos = callStartNanos;}private void printEvent(String name) {// System.out.printf("第 %d 个请求 时间是 %s \n", callId,System.nanoTime() );}@Override public void callStart(Call call) {printEvent("callStart");secondCount.incrementAndGet();}@Override public void callEnd(Call call) {printEvent("callEnd");}}}
测试结果

每秒发起请求数达到预想的一半,后面看看还能不能继续优化一波
对比Jmeter 就3个线程就搞了这么多
