RPC

Modern RPC

When compared with REST (using gRPC as example)

Comparison table

REST

gRPC

Definition

REST is an architecture style. It exposes data as resources and CRUD operations could be used to access resources. HTTP is an implement conforming to REST styles

Make the process of executing code on a remote machine as simple and straight-forward as calling a local functions. There are many types of RPC. RPC usually exposes action-based API methods. gRPC is a multi

Use case

Cross-language platform, public and private facing scenarios

Cross-language platform, public scenarios

Serilization protocol

readablee text(XML, JSon)

Use ProtoBuf by default

Transmission protocol

Typically on HTTP1.1

HTTP 2.0 which supports streaming communication and bidirectional support.

API contract

Loose, Optional (Open API)

Strict, required (.proto)

Delivery semantics

Idempotent

At most/least/exactly once

User friendly

Easy to debug because request/response are readable

Hard to debug because request/response are not readable

Browser support

Universal browser support.

Limited browser support. gRPC requires gRPC-web and a proxy layer to perform conversions between HTTP 1.1 and HTTP 2.

Code generation support

Developers must use a third-party tool like Swagger or Postman to produce code for API requests.

gRPC has native code generation features.

HTTP verbs

REST will use HTTP methods such as GET, POST, PUT, DELETE, OPTIONS and, hopefully, PATCH to provide semantic meaning for the intention of the action being taken.

RPC uses only GET and POST, with GET being used to fetch information and POST being used for everything else.

Examples

SpringMVC/Boot, Jax-rs, drop wizard

Dubbo, Motan, Tars, gRPC, Thrift

Semantics of RPC

At least once

  • Def: For every request message that the client sends, at least one copy of that message is delivered to the server. The client stub keeps retrying until it gets an ack. This is applicable for idempotent operations.

Exactly once

  • Def: For every request message that the client sends, exactly one copy of that message is delivered to the server.

  • But this goal is extremely hard to build. For example, in case of a server crash, the server stub call and server business logic could happen not in an atomic manner.

At most once

  • Def: For every request message that the client sends, at most one copy of that message is delivered to the server.

Designs

  1. How to detect a duplicate request?

    • Client includes unique transaction ID with each one of its RPC requests

    • Client uses the same xid for retransmitted requests

  2. How to avoid false detection?

    • One of the recurrent challenges in RPC is dealing with unexpected responses, and we see this with message IDs. For example, consider the following pathological (but realistic) situation. A client machine sends a request message with a message ID of 0, then crashes and reboots, and then sends an unrelated request message, also with a message ID of 0. The server may not have been aware that the client crashed and rebooted and, upon seeing a request message with a message ID of 0, acknowledges it and discards it as a duplicate. The client never gets a response to the request.

    • One way to eliminate this problem is to use a boot ID. A machine’s boot ID is a number that is incremented each time the machine reboots; this number is read from nonvolatile storage (e.g., a disk or flash drive), incremented, and written back to the storage device during the machine’s start-up procedure. This number is then put in every message sent by that host. If a message is received with an old message ID but a new boot ID, it is recognized as a new message. In effect, the message ID and boot ID combine to form a unique ID for each transaction.

  3. How to ensure that the xid is unique?

    • Combine a unique client ID (e.g. IP address) with the current time of the day

    • Combine a unique client ID with a sequence number

    • Combine a unique client ID with a boot ID

    • Big random number

  4. seen and old arrays will grow without bound

    • Client could tell server "I'm done with xid x - delete it".

    • Client includes "seen all replies <= X" with every RPC

  5. Server may crash and restart

    • If old[], seen[] tables are only in meory, then the user needs to retry

Last of many

  • Last of many : This a version of 'At least once', where the client stub uses a different transaction identifier in each retransmission. Now the result returned is guaranteed to be the result of the final operation, not the earlier ones. So it will be possible for the client stub to tell which reply belongs to which request and thus filter out all but the last one.

Sample Dubbo RPC implementation

Skeleton RPC design

RPC framework (wrapping Registry center, client, server.)

Serialization

Factors to consider

  • Support data types: Some serialization framework such as Hessian 2.0 even support complicated data structures such as Map and List.

  • Cross-language support

  • Performance: The compression rate and the speed for serialization.

  • General RPC protocol vs specialized RPC protocol:

  • Prefer general RPC protocol because the parameters / methods / marshall / etc could be any type.

Protobuf

Compatibility

  • Each field will be decorated with optional, required or repeated. optional keyword helps with compatibility. For example, when a new optional field is added, client and server could upgrade the scheme independently.

Efficiency

  • Protobuf is based on varied length serialization.

  • Tag, Length, Value

    • Tag = (field_num << 3) | wire_type

      • field_num is the unique identification number in protobuf schema.

Hessian2

Sample design

Transport

Netty basics

  • Implementation based on Netty. Netty listens to the following types of events:

    • Connection event: void connected(Channel channel)

    • Readable event: void sent(Channel channel, Object message)

    • Writable event: void received(Channel channel, Object message)

    • Exception event: void caught(Channel channel, Throwable exception)

Http 1.1 vs Http 2

  • REST APIs follow a request-response model of communication that is typically built on HTTP 1.1. Unfortunately, this implies that if a microservice receives multiple requests from multiple clients, the model has to handle each request at a time, which consequently slows the entire system. However, REST APIs can also be built on HTTP 2, but the request-response model of communication remains the same, which forbids REST APIs to make the most out of the HTTP 2 advantages, such as streaming communication and bidirectional support.

  • gRPC does not face a similar obstacle. It is built on HTTP 2 and instead follows a client-response communication model. These conditions support bidirectional communication and streaming communication due to gRPC's ability to receive multiple requests from several clients and handle those requests simultaneously by constantly streaming information. Plus, gRPC can also handle "unary" interactions like the ones built on HTTP 1.1.

  • gRPC is able to handle unary interactions and different types of streaming. The following are sampleSample gRPC interface definition

Sample design

Command

  • Response Header:

  • Payload:

InFlightRequests

  • Used to capture all requests going on.

  • Within the InflightRequests there is a semaphore implementation because:

    • In synchronous programming, client will only send another requests when it receives the current one.

    • In asynchronous programming, server will immediately return a response so there must be some concurrency control in place.

Netty channel

  • Used to send request.

Generate the stub

Static compiling

  • During compiling interface definition files

    • For example in gRPC, gRPC will compile IDL files into gRPC.java stub files.

Example code for generating stub according to static resource

  • There is only one interface method to implement.

  • StubFactory:

    • Implementation with DynamicStubFactory.

    • createStub():

  • AbstractStub:

    • InvokeRemote() is a method.

    • RpcRequest is the parameter to the above method.

  • SPI mechanism: Dynamically create concrete impl of an interface.

    • A more lightweight version of dependency injection.

    • NettyAccessPoint does not create an instance of DynamicStubFactory directly.

Dynamical bytecode instrument

Example code for generating stub dynamically

  • The generated class file sun.misc.ProxyGenerator.saveGeneratedFiles

Server

Server processing model

  • BIO: Server creates a new thread to handle to handle each new coming request.

    • Applicable for scenarios where there are not too many concurrent connections

  • NIO: The server uses IO multiplexing to process new coming request.

    • Applicable for scenarios where there are many concurrent connections and the request processing is lightweight.

  • AIO: The client initiates an IO operation and immediately returns. The server will notify the client when the processing is done.

    • Applicable for scenarios where there are many concurrent connections and the request processing is heavyweight.

  • Reactor model: A main thread is responsible for all request connection operation. Then working threads will process further jobs.

Service discovery

Choose RPC framework

Cross language RPC: gRPC vs Thrift

Comparison criteria

gRPC

Thrift

Integrated frameworks

Lose -_-

Borned earlier. Integrate with big data processing frameworks such as Hadoop/HBase/Cassandra.

Supported num of languages

Lose -_-

Support 25+ languages, more than gRPC

Performance

Used more often in mobile scenarios due to Protobuf and Http2 utilization. Generated code smaller than thrift.

Lose -_-

Same language RPC: Dubbo (Motan/Tars) vs Spring Cloud

Comparison criteria

Dubbo (Motan/Tars)

Spring Cloud

Supported languages

Java (Java/C++)

Java

Supported functionalities

Dubbo(Motan/Tars) is only RPC protocol

Spring cloud provides many other functionalities such as service registration, load balancing, circuit breaker.

gRPC

Interface definition language

  • The steps are as follows:

    1. Programmer writes an interface description in the IDL (Mechanism to pass procedure parameters and return values in a machine-independent way)

    2. Programmer then runs an IDL compiler which generates

      • Code to marshal native data types into machien independent byte streams

      • Client/server stub: Forwards local procedure call as request to server / Dispatches RPC to its implementation

HTTP 1.1 vs HTTP 2

  • Transport over HTTP/2 + TLS

  • First, gRPC runs on top of TCP instead of UDP, which means it outsources the problems of connection management and reliably transmitting request and reply messages of arbitrary size.

  • Second, gRPC actually runs on top of a secured version of TCP called Transport Layer Security (TLS)—a thin layer that sits above TCP in the protocol stack—which means it outsources responsibility for securing the communication channel so adversaries can’t eavesdrop or hijack the message exchange.

  • Third, gRPC actually, actually runs on top of HTTP/2 (which is itself layered on top of TCP and TLS), meaning gRPC outsources yet two other problems:

    • Binary framing and compression: Efficiently encoding/compressing binary data into a message.

    • Multiplexing: Requests by introducing concept of streams.

      • HTTP: The client could send a single request message and the server responds with a single reply message.

      • HTTP 1.1: The client could send multiple requests without waiting for the response. However, the server is still required to send the responses in the order of incoming requests. So Http 1.1 remained a FIFO queue and suffered from requests getting blocked on high latency requests in the front Head-of-line blocking

      • HTTP2 introduces fully asynchronous, multiplexing of requests by introducing concept of streams. lient and servers can both initiate multiple streams on a single underlying TCP connection. Yes, even the server can initiate a stream for transferring data which it anticipates will be required by the client. For e.g. when client request a web page, in addition to sending theHTML content the server can initiate a separate stream to transfer images or videos, that it knows will be required to render the full page.

gRPC use cases

  • As mentioned, despite the many advantages gRPC offers, it has one major obstacle: low browser compatibility. Consequently, gRPC is a bit limited to internal/private systems.

  • Contrarily, REST APIs may have their disadvantages, as we have discussed, but they remain the most known APIs for connecting microservices-based systems. Plus, REST follows the HTTP protocol standardization and offers universal support, making this API architectural style a top option for web services development as well as app and microservices integrations. However, this does not mean we should neglect gRPC's applications.

  • gRPC architectural style has promising features that can (and should) be explored. It is an excellent option for working with multi-language systems, real-time streaming, and for instance, when operating an IoT system that requires light-weight message transmission such as the serialized Protobuf messages allow. Moreover, gRPC should also be considered for mobile applications since they do not need a browser and can benefit from smaller messages, preserving mobiles' processors' speed.

History

  • The biggest differences between gRPC and SunRPC/DCE-RPC/RMI is that gRPC is designed for cloud services rather than the simpler client/server paradigm. In the client/server world, one server process is presumed to be enough to serve calls from all the client processes that might call it. With cloud services, the client invokes a method on a service, which in order to support calls from arbitrarily many clients at the same time, is implemented by a scalable number of server processes, each potentially running on a different server machine.

  • The caller identifies the service it wants to invoke, and a load balancer directs that invocation to one of the many available server processes (containers) that implement that service

gRPC history

Multi-language, multi-platform framework

  • Native implementations in C, Java, and Go

  • Platforms supported: Linux, Android, iOS, MacOS, Windows

  • C/C++ implementation goals

    • High throughput and scalability, low latency

    • Minimal external dependencies

gRPC components

Last updated

Was this helpful?