+5

[gRPC] - gRPC vs REST Performance

Bài viết này chúng ta sẽ cùng so sánh về hiệu năng của gRPC và REST.

Một số bài viết về gRPC có thể mọi người quan tâm.

Sample Application

Mục tiêu chính của chúng ta ở đây là tạo ra một ứng dụng - với 2 cách triển khai khác nhau (REST và gRPC) cho cùng một chức năng. Trong các bài viết trước chúng ta đã cùng thảo luận rằng gRPC sẽ phù hợp tốt cho việc phát triển ứng dụng Client - Server hoặc giao tiếp giữa các dịch vụ Microservices, khi mà việc trao đổi thông tin cần đến nhiều các tác vụ IO. Chúng ta hãy cùng thử làm một ví dụ tăng tải các cuộc gọi giữa các dịch vụ để có thể dễ dàng so sánh sự khác biệt về hiệu suất.

Để mọi thứ đơn giản, chúng ta sẽ tạo ra 2 dịch vụ aggregator-servicesquare-service. Dịch vụ square-service sẽ tính bình phương của một số. Ví dụ nếu chúng ta gửi đến là 2, nó sẽ phản hồi với kết quả là 4.

Giả sử nghiệp vụ của chúng ta như sau, aggregator-service nhận được request với tham số là một số N và nó muốn tính bình phương tất cả các số từ 1 đến N. Để làm được điều này, aggregator-service sẽ gửi N request với tham số là các số từ 1 đến N đến máy chủ square-serviceaggregator-service sẽ nhận được kết quả như dưới đây:

[
   {
      "1":1
   },
   {
      "2":4
   },
   {
      "3":9
   },
   {
      "4":16
   },
   {
      "5":25
   }
]

Khi N là 1000, aggregator-service sẽ gửi 1000 request đến square-service. Chúng ta sẽ có 2 cách triển khai khác nhau cho logic phía máy chủ square-service như được hiển thị ở đây. Dựa trên endpoint được gọi mà aggregator-service sẽ gọi tới rest service hoặc grpc service.

Proto Service Definition

Chúng ta sẽ tạo ra 4 module maven project như sau:

  • File .proto định nghĩa model và service cho gRPC
syntax = "proto3";

package vinsmath;

option java_package = "example.model";
option java_multiple_files = true;

message Input {
  int32 number = 1;
}

message Output {
  int32 number = 1;
  int32 result = 2;
}

service SquareRpc {
  rpc findSquareUnary(Input) returns (Output) {};
  rpc findSquareBiStream(stream Input) returns (stream Output) {};
}

REST Server

Đây là spring boot project với Controller có endpoint là /rest/square/unary/{number},

@RestController
public class RestSquareController {

    @Autowired
    private RestSquareService squareService;

    @GetMapping("/rest/square/unary/{number}")
    public int getSquareUnary(@PathVariable int number){
        return number * number;
    }

}

gRPC – Server

Chúng ta định nghĩa 2 implementation, một cho Unary, một cho gRPC bi-directional stream.

@GrpcService
public class MyGrpcService extends SquareRpcGrpc.SquareRpcImplBase {

    @Override
    public void findSquareUnary(Input request, StreamObserver<Output> responseObserver) {
        int number = request.getNumber();
        responseObserver.onNext(
                Output.newBuilder().setNumber(number).setResult(number * number).build()
        );
        responseObserver.onCompleted();
    }

    @Override
    public StreamObserver<Input> findSquareBiStream(StreamObserver<Output> responseObserver) {
        return new StreamObserver<Input>() {
            @Override
            public void onNext(Input input) {
                var number = input.getNumber();
                Output output = Output.newBuilder()
                        .setNumber(number)
                        .setResult(number * number).build();
                responseObserver.onNext(output);
            }

            @Override
            public void onError(Throwable throwable) {
                responseObserver.onCompleted();
            }

            @Override
            public void onCompleted() {
                responseObserver.onCompleted();
            }
        };
    }

}

Server gRPC sẽ chạy ở port 6565.

Aggregator Service

Dịch vụ này sẽ đóng vai trò như một Client Application chứa 2 endpoint để truy cập đến 2 dịch vụ rest service hoặc grpc service đã tạo ở trên.

  • Controller chứa endpoint gọi đến grpc service
@RestController
@RequestMapping("grpc")
public class GrpcAPIController {

   @Autowired
   private GrpcService service;

   @GetMapping("/unary/{number}")
   public Object getResponseUnary(@PathVariable int number){
       return this.service.getSquareResponseUnary(number);
   }

   @GetMapping("/stream/{number}")
   public Object getResponseStream(@PathVariable int number){
       return this.service.getSquareResponseStream(number);
   }

}
  • Controller chứa endpoint gọi đến rest service
@RestController
@RequestMapping("rest")
public class RestAPIController {

   @Autowired
   private RestService service;

   @GetMapping("/unary/{number}")
   public Object getResponseUnary(@PathVariable int number){
       return this.service.getUnaryResponse(number);
   }

}
  • application.properties
server.port=8080
grpc.client.square.address=static://localhost:6565
grpc.client.square.negotiationType=plaintext
rest.square.service.endpoint=http://localhost:7575

Ví dụ kết quả:

gRPC vs REST Performance – Unary

Chúng ta sẽ thực hiện kiểm tra hiệu suất bằng cách gửi 1000 request đến aggregator-service với 100 request đồng thời tại một thời điểm (mô phỏng server chịu tải 100 request đồng thời). Chúng ta sử dụng công cụ ApacheBench để kiểm tra hiệu suất.

  • Rest request
ab -n 1000 -c 100 http://localhost:8080/rest/unary/1000

Kết quả:

  • gRPC request
ab -n 1000 -c 100 http://localhost:8080/grpc/unary/1000

Kết quả:

  • So sánh
Throughput (Requests/Second) 50th Percentile Response Time 90th Percentile Response Time
REST 29.43 3383 3576
gRPC 66.71 1266 2660

Chú ý rằng là, cả 3 service trong ví dụ này cùng chạy trên một máy chủ vật lý. Kết quả sẽ có thể khác phụ thuộc vào CPU/Memory vào máy của mọi người.

gRPC vs REST Performance – Bi-Directional Stream

Với ví dụ trên chúng ta thấy gRPC unary/blocking stub dường như đã hoạt động tốt hơn nhiều so với REST. Bây giờ chúng ta sẽ chạy thử nghiệm tương tự bằng cách sử dụng phương pháp gRPC bi-directional stream, thông lượng lên đến ~ 150.67 requests/second, quá tuyệt vời!

  • So sánh
Throughput (Requests/Second) 50th Percentile Response Time 90th Percentile Response Time
REST 29.43 3383 seconds 3576 seconds
gRPC-Unary 66.71 1266 seconds 2660 seconds
gRPC Bi-Directional Stream 150.67 462 seconds 1762 seconds

Chú ý: Throughtput càng cao càng tốt, Percentile Response Time càng thấp càng tốt.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí