我之前分享了Java和Go語(yǔ)言版本的gRPC接口的服務(wù)端和客戶端的開發(fā),使用的基本都是基礎(chǔ)的原聲API,舊文如下:
- Grpc服務(wù)開發(fā)和接口測(cè)試初探【Java】 2022-04-20
- gRPC服務(wù)開發(fā)和接口測(cè)試初探【Go】 2022-05-07
- gRPC三種客戶端類型實(shí)踐【Java版】 2022-05-11
經(jīng)過一段時(shí)間的摸索和嘗試,我覺得又可以了,今天給大家分享一下三種Java客戶端的性能測(cè)試實(shí)踐,其中主要是com.funtester.fungrpc.HelloServiceGrpc#newBlockingStub的性能測(cè)試實(shí)踐。因?yàn)樵趯?shí)際的業(yè)務(wù)測(cè)試中這個(gè)用的最多,還有阻塞的客戶端對(duì)于性能測(cè)試的指標(biāo)統(tǒng)計(jì)和監(jiān)控比較友好,對(duì)于多接口串聯(lián)的業(yè)務(wù)測(cè)試來(lái)說(shuō)更貼近HTTP接口的測(cè)試,這樣能讓很多用例思路直接復(fù)用。
基于以上,下面開始正題。
PS:本篇文章只做性能測(cè)試實(shí)踐,不會(huì)測(cè)試各類狀況下極限性能,所以硬件配置和軟件參數(shù)就不單獨(dú)分享了。
服務(wù)端
依舊采用了之前的fun_grpc項(xiàng)目的SDK內(nèi)容。服務(wù)端代碼如下:
package com.funtester.grpc;import com.funtester.frame.execute.ThreadPoolUtil;import io.grpc.Server;import io.grpc.ServerBuilder;import java.io.IOException;import java.util.concurrent.ThreadPoolExecutor;public class Service { public static void main(String[] args) throws IOException, InterruptedException { ThreadPoolExecutor pool = ThreadPoolUtil.createFixedPool(10, “gRPC”); Server server = ServerBuilder .forPort(12345) .executor(pool) .addService(new HelloServiceImpl()) .build(); server.start(); server.awaitTermination(); }}
實(shí)際業(yè)務(wù)處理類:
package com.funtester.grpc;import com.funtester.frame.SourceCode;import com.funtester.fungrpc.HelloRequest;import com.funtester.fungrpc.HelloResponse;import com.funtester.fungrpc.HelloServiceGrpc;import com.funtester.utils.Time;import io.grpc.stub.StreamObserver;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase { private static final Logger logger = LogManager.getLogger(HelloServiceImpl.class); @Override public void executeHi(HelloRequest request, StreamObserver responseObserver) { HelloResponse response = HelloResponse.newBuilder() .setMsg(“你好 ” + request.getName()+ Time.getDate()) .build(); SourceCode.sleep(1.0); logger.info(“用戶{}來(lái)了”,request.getName()); responseObserver.onNext(response); responseObserver.onCompleted(); }}
業(yè)務(wù)上休眠了1s,然后返回響應(yīng)內(nèi)容。
客戶端
客戶端實(shí)際使用相對(duì)簡(jiǎn)單,這里就不再分享了,有興趣的可以讀一讀文章開頭的三篇文章。
靜態(tài)模型
首先分享一下靜態(tài)模型的內(nèi)容,所謂靜態(tài)內(nèi)容指的是用例執(zhí)行之前就設(shè)定好了執(zhí)行的整個(gè)過程,用例執(zhí)行過程除了終止以外沒有其他干預(yù)措施。
線程模型
下面是基于靜態(tài)線程模型的性能測(cè)試用例:
package com.funtest.grpcimport com.funtester.base.constaint.FixedThreadimport com.funtester.frame.SourceCodeimport com.funtester.frame.execute.Concurrentimport com.funtester.fungrpc.HelloRequestimport com.funtester.fungrpc.HelloServiceGrpcimport io.grpc.ManagedChannelimport io.grpc.ManagedChannelBuilderclass FixedThreadModel extends SourceCode { static int times static HelloServiceGrpc.HelloServiceBlockingStub helloServiceBlockingStub static HelloRequest requst public static void main(String[] args) { ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(“localhost”, 12345) .usePlaintext().build() helloServiceBlockingStub = HelloServiceGrpc.newBlockingStub(managedChannel).withCompression(“gzip”) requst = HelloRequest.newBuilder() .setName(“FunTester”) .build() RUNUP_TIME = 0 times = 2000 new Concurrent(new FunTester(), 10, “靜態(tài)線程模型”).start() managedChannel.shutdown() } private static class FunTester extends FixedThread { FunTester() { super(null, times, true) } @Override protected void doing() throws Exception { helloServiceBlockingStub.executeHi(requst) } @Override FunTester clone() { return new FunTester() } }}
QPS模型
下面是基于靜態(tài)QPS模型的壓測(cè)用例。
package com.funtest.grpcimport com.funtester.base.event.FunCountimport com.funtester.frame.SourceCodeimport com.funtester.frame.execute.FunEventConcurrentimport com.funtester.fungrpc.HelloRequestimport com.funtester.fungrpc.HelloServiceGrpcimport io.grpc.ManagedChannelimport io.grpc.ManagedChannelBuilderclass FixedQpsModel extends SourceCode { static HelloServiceGrpc.HelloServiceBlockingStub helloServiceBlockingStub static HelloRequest requst public static void main(String[] args) { ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(“localhost”, 12345) .usePlaintext().build() helloServiceBlockingStub = HelloServiceGrpc.newBlockingStub(managedChannel).withCompression(“gzip”) requst = HelloRequest.newBuilder() .setName(“FunTester”) .build() def count = new FunCount(1, 1, 2, 1000, 10, “靜態(tài)QPS模型”) def test= { helloServiceBlockingStub.executeHi(requst) } new FunEventConcurrent(test,count).start() managedChannel.shutdown() }}
以上是兩個(gè)常用的靜態(tài)模型的演示,還有其他的動(dòng)態(tài)模型這里就不演示了。
動(dòng)態(tài)模型
下面到了喜聞樂見的動(dòng)態(tài)模型的part,動(dòng)態(tài)模型值得是用例執(zhí)行時(shí)都是以固定的最小壓力值(通常為1個(gè)QPS或者1個(gè)線程)啟動(dòng),然后再用例執(zhí)行過程中不斷調(diào)整(調(diào)整步長(zhǎng)、增減)用例的壓力。
動(dòng)態(tài)線程模型
由于動(dòng)態(tài)模型是不限制用例運(yùn)行時(shí)間,所以取消了關(guān)閉channel的方法。
package com.funtest.grpcimport com.funtester.base.constaint.FunThreadimport com.funtester.frame.SourceCodeimport com.funtester.frame.execute.FunConcurrentimport com.funtester.fungrpc.HelloRequestimport com.funtester.fungrpc.HelloServiceGrpcimport io.grpc.ManagedChannelimport io.grpc.ManagedChannelBuilderimport java.util.concurrent.atomic.AtomicIntegerclass FunThreadModel extends SourceCode { static int times static HelloServiceGrpc.HelloServiceBlockingStub helloServiceBlockingStub static HelloRequest requst static AtomicInteger index = new AtomicInteger(0) static def desc = “動(dòng)態(tài)線程模型” public static void main(String[] args) { ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(“localhost”, 12345) .usePlaintext().build() helloServiceBlockingStub = HelloServiceGrpc.newBlockingStub(managedChannel).withCompression(“gzip”) requst = HelloRequest.newBuilder() .setName(“FunTester”) .build() new FunConcurrent(new FunTester()).start() } private static class FunTester extends FunThread { FunTester() { super(null, desc + index.getAndIncrement()) } @Override protected void doing() throws Exception { helloServiceBlockingStub.executeHi(requst) } @Override FunTester clone() { return new FunTester() } }}
動(dòng)態(tài)QPS模型
動(dòng)態(tài)QPS模型是我現(xiàn)在最常用的模型,優(yōu)勢(shì)多多,除了某些強(qiáng)用戶綁定需求外,動(dòng)態(tài)QPS模型都是第一選擇。
package com.funtest.grpcimport com.funtester.frame.SourceCodeimport com.funtester.frame.execute.FunQpsConcurrentimport com.funtester.fungrpc.HelloRequestimport com.funtester.fungrpc.HelloServiceGrpcimport io.grpc.ManagedChannelimport io.grpc.ManagedChannelBuilderclass FunQpsModel extends SourceCode { static HelloServiceGrpc.HelloServiceBlockingStub helloServiceBlockingStub static HelloRequest requst public static void main(String[] args) { ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(“localhost”, 12345) .usePlaintext().build() helloServiceBlockingStub = HelloServiceGrpc.newBlockingStub(managedChannel).withCompression(“gzip”) requst = HelloRequest.newBuilder() .setName(“FunTester”) .build() def test= { helloServiceBlockingStub.executeHi(requst) } new FunQpsConcurrent(test).start() }}
以上就是常用的gRPC阻塞客戶端四種模型的性能測(cè)試全部?jī)?nèi)容了,歡迎繼續(xù)關(guān)注FunTester。
「BUG挖掘機(jī)·性能征服者·頭頂鍋蓋」