Which one is better and which one is worse? gRPC and Rest performance competition

This article compares REST and gRPC performance with examples.

Search on WeChat and follow “Java Learning and Research Base Camp”

We use Spring Boot and REST controllers in our project. In this article, we will compare REST and gRPC to explore whether you can use gRPC for performance optimization.

Picture

gRPC is an RPC (Remote Procedure Call) method that provides communication between applications by using Google Protobuf serialization infrastructure.

  • gRPC relies on the HTTP/2 protocol, while REST uses the HTTP/1 protocol.

  • In HTTP/1, each request needs to establish a TCP connection, while in HTTP/2 the same TCP connection can be reused.

  • In HTTP/1, headers are sent as plain text, while in HTTP/2, both headers and data are converted to binary data.

  • In HTTP/2, the server can send multiple response messages to client requests.

  • Since communication is via binary data, messages take up less space, providing efficient serialization and deserialization processes.

Client and server applications can be implemented in different languages and communicate through .proto files.

This is an example proto definition used when implementing a gRPC server-client application.

syntax = "proto3";

package order.core;

// Generated source code options
option java_package = "com.example.grpc.order";
option java_multiple_files = true;

message OrderRequest {
  int64 timestamp = 1;
  int32 count = 2;
  double amount = 3;
  string name = 4;
  bool active = 5;
  Type type = 6;
  InnerObject innerObject = 7;
  repeated string items = 8;
  reserved 9;
}
enum Type {
  UNKNOWN = 0;
  WEB = 1;
  LOCAL = 2;
}
message InnerObject {//Level 1
  Inner inner = 1;
}

message Inner {//Level 2
  int64 value = 1;
  bool active = 2;
}

message OrderResponse {
  int64 timestamp = 1;
  string message = 2;
}

service OrderService {
  rpc order (OrderRequest) returns (OrderResponse);
}

1 Supported data types

The following table shows the supported data types and their corresponding Java types:

Picture

2 Reserved fields

Backward compatibility is an important concept when working with proto definitions. If you delete a field but do not specify a number that was previously used, other users can use the same number to represent a different field, which can cause serious problems. To solve this problem, you can specify the field number of the deleted field as a retained field. If any user attempts to use these field identifiers, the protocol buffer compiler will issue an error.

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

For Java gRPC implementation, the compiler generates the necessary class files and builders for each message type.

3 Implementation

Picture

For comparison, I have implemented a REST server-client and a gRPC server-client here.

4 REST server implementation

Create a Spring Boot starter project and write the following REST controller class. Use the default Tomcat configuration.

@RestController
@RequestMapping
@RequiredArgsConstructor
public class OrderController {

    private final OrderService orderService;

    @PostMapping(path = "/order")
    public OrderResponse order(@RequestBody OrderRequest request) {
        OrderDto orderDto = convertOrderDto(request);
        //Business logic, create order
        return orderService.createOrder(orderDto);
    }
}

5 REST client implementation

Use “Feign Client” to implement the REST client, the code is as follows:

@FeignClient(name = "orderService", url = "${integration.rest.url}")
public interface OrderFeignClient {

    @PostMapping(value = "/order")
    OrderResponse order(@RequestBody OrderRequest request);
}
@Service
@RequiredArgsConstructor
public class OrderRestClient {
    private final OrderFeignClient orderFeignClient;

    public OrderResponse createOrder(OrderRequest orderRequest) {
        OrderResponse response = orderFeignClient.order(orderRequest);
        return response;
    }
}

6 gRPC server implementation

In the server implementation, grpc-server-spring-boot-starter is used here along with grpc-protobuf and grpc-stub dependencies. gRPC supports unary, client stream, server stream and bidirectional stream API types. I implemented a unary API which sends a request from a server and gets a response.

<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-server-spring-boot-starter</artifactId>
    <version>2.14.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.51.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.51.0</version>
</dependency>
<dependency> <!-- necessary for Java 9 + -->
    <groupId>org.apache.tomcat</groupId>
    <artifactId>annotations-api</artifactId>
    <version>6.0.53</version>
    <scope>provided</scope>
</dependency>

Add the following build steps in the pom file:

<build>
  <extensions>
      <extension>
          <groupId>kr.motd.maven</groupId>
          <artifactId>os-maven-plugin</artifactId>
          <version>1.6.2</version>
      </extension>
  </extensions>
  <plugins>
      <plugin>
          <groupId>org.xolstice.maven.plugins</groupId>
          <artifactId>protobuf-maven-plugin</artifactId>
          <version>0.6.1</version>
          <configuration>
              <protocArtifact>com.google.protobuf:protoc:3.19.2:exe:${os.detected.classifier}</protocArtifact>
              <pluginId>grpc-java</pluginId>
              <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.51.0:exe:${os.detected.classifier}</pluginArtifact>
          </configuration>
          <executions>
              <execution>
                  <goals>
                      <goal>compile</goal>
                      <goal>compile-custom</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
  </plugins>
</build>

The compiler will generate a .java file and a corresponding class for each message type in the proto file. The plugin will be triggered during the compile step of the project.

Picture

The @GrpcService annotation is used for server implementation. By default, the gRPC server will listen on port 9090. The port setting can be changed to other values via the grpc.server.port property in the application.yaml file.

In the business layer, both the gRPC server and the REST server are designed to call the same orderService.

@GrpcService
@RequiredArgsConstructor
public class OrderGrpcController extends OrderServiceGrpc.OrderServiceImplBase {
    private final OrderService orderService;

    @Override
    public void order(OrderRequest request, StreamObserver<OrderResponse> responseObserver) {
        OrderDto orderDto = convertOrderDto(request);
        //Business logic, create order
        com.example.grpcserverapi.response.OrderResponse orderServiceResponse = orderService.createOrder(orderDto);
        
        OrderResponse response = OrderResponse.newBuilder()
                .setTimestamp(orderServiceResponse.getTimestamp())
                .setMessage(orderServiceResponse.getMessage())
                .build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

7 gRPC client implementation

In the client implementation, grpc-client-spring-boot-starter and grpc-protobuf and grpc-stub dependencies are used.

<dependency>
  <groupId>net.devh</groupId>
  <artifactId>grpc-client-spring-boot-starter</artifactId>
  <version>2.14.0.RELEASE</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-protobuf</artifactId>
  <version>1.51.0</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-stub</artifactId>
  <version>1.51.0</version>
</dependency>
<dependency> <!-- necessary for Java 9 + -->
  <groupId>org.apache.tomcat</groupId>
  <artifactId>annotations-api</artifactId>
  <version>6.0.53</version>
  <scope>provided</scope>
</dependency>

Add the URL of the gRPC server in the application .yaml file as follows:

grpc:
  client:
    orderService:
      address: static://localhost:9090
      negotiation-type: plaintext

The @GrpcClient(serverName) field annotation is used in the gRPC client stub implementation. Do not use the @Autowired annotation for client-side implementation.

@Service
@RequiredArgsConstructor
public class OrderGrpcClient {

    @GrpcClient("orderService")
    private OrderServiceGrpc.OrderServiceBlockingStub blockingStub;

    public OrderResponse createOrder(OrderRequest request) {
        return blockingStub.order(request);
    }
}

When sending 10,000 requests to the REST client and gRPC client respectively for performance testing, the following results can be obtained:

gRPC average time per request: 0.3503 milliseconds

REST average time per request: 2.3109 milliseconds

Please note that this was performance tested on a local machine.

Picture

8 Conclusion

According to performance results, using the gRPC implementation can reduce latency by 85%.

If you want faster communication between services, you can use gRPC instead of REST. Since communication is based on binary data, maintaining compatibility can be difficult if the service changes frequently. In this case, REST may be preferable.

Recommended book list

Autumn Reading Projecticon-default.png?t=N7T8https://pro.m.jd .com/mall/active/3yzSCnrymNQEzLmwtZ868xFeytT7/index.html

“Java Web from Beginner to Master (3rd Edition)”

“Java Web from Beginner to Master (3rd Edition)” starts from the perspective of beginners, uses easy-to-understand language and colorful examples, and introduces in detail various technologies that need to be mastered for Java Web application development.

This book is divided into 21 chapters, including an overview of JavaWeb application development, basics of HTML and CSS web development, JavaScript scripting language, building a development environment, basic JSP syntax, JSP built-in objects, JavaBean technology, Servlet technology, filters and listeners, and JavaWeb Database operations, EL (expression language), JSTL tags, Ajax technology, Struts2 basics, Struts2 advanced technology, Hibemate technology, Hibemate advanced applications, Spring core IoC, Spring core AOP, SSM framework integrated development, Jiugongge memory network, etc. .

All the knowledge in this book is introduced with specific examples, and the involved program codes are given detailed annotations, which allows readers to easily understand the essence of JavaWeb application development and quickly improve development skills. In addition, in addition to paper content, a massive development resource library is also provided in the supporting resources. The main contents are as follows:

  • Audio and video explanation: 19 hours in total, 94 paragraphs in total

  • Module resource library: 15 classic module development processes are fully displayed

  • Test question bank system: 596 ability test questions

  • PPT electronic lesson plan

  • Instance resource library: 1010 examples and detailed analysis of source code

  • Project case resource library: 15 corporate project development processes are fully displayed

  • Interview resource library: 369 real company interview questions

“Java Web from Beginner to Master (3rd Edition)” can be used as a self-study book for beginners in software development, and can also be used as a teaching reference book for related majors in colleges and universities. It can also be consulted and referenced by developers.

Java Web from Beginner to Master (3rd Edition) icon-default.png?t=N7T8https://item.jd.com/13446953.html

Picture

Highlights

Understand the encapsulation mechanism in Java object-oriented programming in one article

Understand the inheritance mechanism in Java object-oriented programming in one article

4 steps to implement Websocket in Android

Make good use of these 4 design patterns to complete most tasks in Java

5 programming libraries that Java developers must know

Search on WeChat and follow “Java Learning and Research Base Camp”

Visit [IT Today’s Hot List] to discover daily technology hot spots