我之前分享了JAVA和Go語言版本的gRPC接口的服務端和客戶端的開發,使用的基本都是基礎的原聲API,舊文如下:
- Grpc服務開發和接口測試初探【Java】 2022-04-20
- gRPC服務開發和接口測試初探【Go】 2022-05-07
- gRPC三種客戶端類型實踐【Java版】 2022-05-11
經過一段時間的摸索和嘗試,我覺得又可以了,今天給大家分享一下三種Java客戶端的性能測試實踐,其中主要是com.funtester.fungrpc.HelloServiceGrpc#newBlockingStub的性能測試實踐。因為在實際的業務測試中這個用的最多,還有阻塞的客戶端對于性能測試的指標統計和監控比較友好,對于多接口串聯的業務測試來說更貼近HTTP接口的測試,這樣能讓很多用例思路直接復用。
基于以上,下面開始正題。
PS:本篇文章只做性能測試實踐,不會測試各類狀況下極限性能,所以硬件配置和軟件參數就不單獨分享了。
服務端
依舊采用了之前的fun_grpc項目的SDK內容。服務端代碼如下:
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();
}
}
實際業務處理類:
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<HelloResponse> responseobserver) {
HelloResponse response = HelloResponse.newBuilder()
.setMsg("你好 " + request.getName()+ Time.getDate())
.build();
SourceCode.sleep(1.0);
logger.info("用戶{}來了",request.getName());
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
業務上休眠了1s,然后返回響應內容。
客戶端
客戶端實際使用相對簡單,這里就不再分享了,有興趣的可以讀一讀文章開頭的三篇文章。
靜態模型
首先分享一下靜態模型的內容,所謂靜態內容指的是用例執行之前就設定好了執行的整個過程,用例執行過程除了終止以外沒有其他干預措施。
線程模型
下面是基于靜態線程模型的性能測試用例:
package com.funtest.grpc
import com.funtester.base.constaint.FixedThread
import com.funtester.frame.SourceCode
import com.funtester.frame.execute.Concurrent
import com.funtester.fungrpc.HelloRequest
import com.funtester.fungrpc.HelloServiceGrpc
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
class 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, "靜態線程模型").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模型
下面是基于靜態QPS模型的壓測用例。
package com.funtest.grpc
import com.funtester.base.event.FunCount
import com.funtester.frame.SourceCode
import com.funtester.frame.execute.FunEventConcurrent
import com.funtester.fungrpc.HelloRequest
import com.funtester.fungrpc.HelloServiceGrpc
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
class 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, "靜態QPS模型")
def test= {
helloServiceBlockingStub.executeHi(requst)
}
new FunEventConcurrent(test,count).start()
managedChannel.shutdown()
}
}
以上是兩個常用的靜態模型的演示,還有其他的動態模型這里就不演示了。
動態模型
下面到了喜聞樂見的動態模型的part,動態模型值得是用例執行時都是以固定的最小壓力值(通常為1個QPS或者1個線程)啟動,然后再用例執行過程中不斷調整(調整步長、增減)用例的壓力。
動態線程模型
由于動態模型是不限制用例運行時間,所以取消了關閉channel的方法。
package com.funtest.grpc
import com.funtester.base.constaint.FunThread
import com.funtester.frame.SourceCode
import com.funtester.frame.execute.FunConcurrent
import com.funtester.fungrpc.HelloRequest
import com.funtester.fungrpc.HelloServiceGrpc
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
import java.util.concurrent.atomic.AtomicInteger
class FunThreadModel extends SourceCode {
static int times
static HelloServiceGrpc.HelloServiceBlockingStub helloServiceBlockingStub
static HelloRequest requst
static AtomicInteger index = new AtomicInteger(0)
static def desc = "動態線程模型"
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()
}
}
}
動態QPS模型
動態QPS模型是我現在最常用的模型,優勢多多,除了某些強用戶綁定需求外,動態QPS模型都是第一選擇。
package com.funtest.grpc
import com.funtester.frame.SourceCode
import com.funtester.frame.execute.FunQpsConcurrent
import com.funtester.fungrpc.HelloRequest
import com.funtester.fungrpc.HelloServiceGrpc
import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder
class 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阻塞客戶端四種模型的性能測試全部內容了,歡迎繼續關注FunTester。
「BUG挖掘機·性能征服者·頭頂鍋蓋」