8.2.2 非阻塞客户端

非阻塞客户端(异步客户端)相较于阻塞客户端,使用上稍显复杂,但其高并发性能使其在压力测试中表现优异,尤其适合模拟大量用户请求的场景。异步客户端与阻塞客户端的主要差异在于两点:一是创建服务存根的方式不同,二是响应类型及处理方式不同。以下详细讲解异步客户端的使用方法。

首先,创建异步存根(FutureStub),用于发起异步调用。代码如下:

// 创建异步存根,用于调用FunTester服务的queryUser方法
UserServiceGrpc.UserServiceFutureStub userServiceFutureStub = UserServiceGrpc.newFutureStub(managedChannel);

接着,发送请求。请求对象可复用上一节的QueryRequest,通过异步存根调用接口,返回ListenableFuture对象:

// 发送异步请求,获取Future对象
ListenableFuture<QueryResponse> queryResponseFuture = userServiceFutureStub.queryUser(queryRequest);

ListenableFuture提供了两种处理响应的方式:

在实际测试中,阻塞获取方式更为常见。例如,测试一个订单系统的查询接口时,可先发送多个异步请求,将ListenableFuture对象存入线程安全的集合(如List),待所有请求发出后再遍历调用get()获取结果:

// 示例:处理多个异步请求
List<ListenableFuture<QueryResponse>> futures = new ArrayList<>();
for (int i = 0; i < 100; i++) {
    QueryRequest request = QueryRequest.newBuilder().setId(800 + i).build();
    futures.add(userServiceFutureStub.queryUser(request)); // 批量发送请求
}
// 遍历获取响应
for (ListenableFuture<QueryResponse> future : futures) {
    try {
        QueryResponse response = future.get(); // 阻塞获取响应
        System.out.println("用户名称: " + response.getName()); // 打印FunTester相关信息
    } catch (Exception e) {
        System.err.println("请求失败: " + e.getMessage());
    }
}

这种方式兼顾了异步客户端的高并发优势和业务逻辑的正确性,适合性能测试场景。测试人员可根据需求调整请求数量,模拟不同负载下的系统表现。

8.2.3 流式客户端

流式客户端也属于异步客户端,专为实时数据传输或双向通信设计,能够并发发送和接收数据流。与阻塞客户端相比,流式客户端在创建存根、发送请求和处理响应三个方面存在差异,其实现复杂度更高,常用于视频流、聊天系统等实时场景。以下详细介绍其使用方法。

首先,创建流式存根(Stub),用于流式调用:

// 创建流式存根,用于FunTester服务的流式调用
UserServiceGrpc.UserServiceStub userServiceStub = UserServiceGrpc.newStub(managedChannel);

流式客户端的请求发送通过StreamObserver接口实现,调用方法(如queryUser)不直接返回响应,而是将响应处理交给StreamObserver对象。以下是一个简单的流式客户端示例:

// 创建请求对象
QueryRequest queryRequest = QueryRequest.newBuilder().setId(888).build();
// 创建响应观察者,用于处理服务端返回的数据流
StreamObserver<QueryResponse> streamObserver = new StreamObserver<QueryResponse>() {
    @Override
    public void onNext(QueryResponse response) {
        // 收到服务端响应时调用,打印用户信息
        System.out.println("用户名称: " + response.getName()); // 输出FunTester相关信息
    }

    @Override
    public void onError(Throwable throwable) {
        // 出错时调用,打印错误信息
        System.err.println("请求失败: " + throwable.getMessage());
    }

    @Override
    public void onCompleted() {
        // 数据流结束时调用
        System.out.println("数据流处理完成");
    }
};
// 发送流式请求
userServiceStub.queryUser(queryRequest, streamObserver);

流式客户端的核心在于StreamObserver接口的实现,其三个方法分别处理响应数据(onNext)、错误(onError)和流结束(onCompleted)。例如,在测试实时日志系统时,客户端可通过流式调用持续接收服务端推送的日志数据,并在onNext中解析日志内容。

相比异步客户端,流式客户端对开发和测试人员的能力要求更高,上手难度较大。初学者可先了解其工作流程和 API 用法,工作中若无需处理实时数据流,可将重点放在阻塞或异步客户端的测试上。在实际性能测试中,流式客户端适合验证系统在持续高频数据交互下的稳定性。例如,测试一个即时通讯系统时,可用流式客户端模拟多个用户同时发送消息,观察服务端是否能稳定处理。

通过掌握非阻塞和流式客户端的使用,测试工程师能够应对更复杂的 gRPC 测试场景,为系统的性能和稳定性提供有力保障。建议从简单场景入手,逐步深入流式调用,结合实际业务需求提升测试能力。

FunTester 原创精华
从 Java 开始性能测试
故障测试与 Web 前端
服务端功能测试
性能测试专题
Java、Groovy、Go
测试开发专题
测试理论、FunTester 风采
视频专题


↙↙↙阅读原文可查看相关链接,并与作者交流