“Can you have your cake and eat it?” Still struggling with HTTP and gRPC? Try gRPC – Gateway

Microservices: Independent, decentralized architectural patterns

Independent, decentralized, organizes services and manages data around the business, and uses lightweight communication mechanisms

Services are organized according to business domains and Restful interfaces are provided. Data is exchanged and invoked between services through lightweight communication (Restful). Lightweight gateways are used externally to simplify client access. Based on service discovery and registry, mutual discovery between services and horizontal extension of service itself can be realized.

GRPC: General-purpose, high-performance RPC framework

Google developed a generic, high-performance RPC framework designed based on the HTTP/2 standard

  • Better application performance (bandwidth saving and TCP connection reduction) based on HTTP/2 protocol
  • Based on ProtoBuf definition of services, interface – oriented service top-level design

    syntax = "proto3";
    package example;
    message StringMessage {
    string value = 1;
    }
    
    service YourService {
    rpc Echo(StringMessage) returns (StringMessage) {}
    }
    Copy the code
  • Support the mainstream programming language, c + +, Java, Python, Go, Ruby, Node. Js, PHP, etc., based on the ProtoBuf generated the corresponding server and client code.

GRPC provides better performance, lower latency, and is inherently suited to distributed systems, compared to Restful access between services. While generating server-side and client-side code based on standardized IDL (ProtoBuf), ProtoBuf service definitions can be used as service contracts, thus better supporting team to team interface design, development, testing, collaboration, etc.

Therefore, in many cases with high requirements on application performance, Restful apis are used to support different client channels (Web and Mobile), and RPC is used for interaction between services.

Expand your gRPC definition

Using gRPC based on Protobuf allows for standardized definitions between services and provides better application performance, but in some cases we still want our service interfaces to support Restful apis, such as in the first figure, where we need to support different channels externally. Therefore, we can add more extensions to the existing Protobuf service definition file to say that Protobuf defines the service and the corresponding Restful interface:

syntax = "proto3"; package example; + +import "google/api/annotations.proto"; + message StringMessage { string value = 1; } service YourService { - rpc Echo(StringMessage) returns (StringMessage) {} + rpc Echo(StringMessage) returns (StringMessage) { + option (google.api.http) = { + post: "/v1/example/echo" + body: "*" + }; +}}Copy the code

The Google/API/annotations. Proto from github.com/googleapis/…

Grpc-gateway: from gRPC to HTTP

Through Google provides a standard interface to Google/API/annotations. The proto we can describe its corresponding effective for Protobuf service form of HTTP interface. Grpc-gateway provides the ability to generate Http reverse proxies based on the service interface definition in the. Proto file. Because for the same standard Grpc service definition, in addition to the basic Grpc client can also generate the corresponding HTTP+JSON interface implementation.

Example: Create support gRPC

1. Define the service echo_service.proto

Define the service EchoService and Echo method, which receives data from a StringMessage structure and returns StringMessage. /v1/example/echo/{value}

syntax = "proto3"; package echo; import "google/api/annotations.proto"; message StringMessage { string value = 1; } service EchoService { rpc Echo(StringMessage) returns (StringMessage) { option (google.api.http) = { post: "/v1/example/echo/{value}" body: "*" }; }}Copy the code

2. Generate server-side code

Gradle is used to build build.gradle is invoked to generate server-side code based on the proto file

|- ProjectRoot
   |- build.gradle
   |- src
      |- main
         |- proto
            |- api
              |- annotations.proto
              |- http.proto
            |- echo_service.proto
Copy the code

build.gradle

apply plugin: 'java' apply plugin: 'maven' apply plugin: Protobuf 'buildscript {repositories {mavenCentral()} dependencies {// assuming GRADLE 2.12 OR higher.use The plugin version 0.7.5 with earlier / / gradle versions classpath 'com. Google. Protobuf: protobuf - gradle - plugin: 0.8.1'}} Repositories {mavenCentral() mavenLocal()} Group = 'com.demo.grpc' version = '1.0-snapshot' Description = """ "echo-service""" sourceCompatibility = 1.5 targetCompatibility = 1.5 def grpcVersion = '1.6.1' // CURRENT_GRPC_VERSION Dependencies {the compile "com. Google. API. GRPC: proto - Google - common - protos: 0.1.9" the compile "io.grpc:grpc-netty:${grpcVersion}" compile "io.grpc:grpc-protobuf:${grpcVersion}" compile IO. GRPC: grPC-stub :${grpcVersion}" testCompile "IO. GRPC :grpc-testing:${grpcVersion}" testCompile "junit:junit:4.11" TestCompile "org. Mockito: mockito - core: 1.9.5"} protobuf {protoc {an artifact = 'com. Google. Protobuf: protoc: 3.3.0'} plugins { grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" } } generateProtoTasks { all()*.plugins { grpc  { // To generate deprecated interfaces and static bindService method, // turn the enable_deprecated option to true below: option 'enable_deprecated=false' } } } generatedFilesBaseDir = new File("$projectDir", "src") } // Inform IntelliJ projects about the generated code. apply plugin: 'maven' // Provide convenience executables for trying out the examples. apply plugin: 'application' startScripts.enabled = false task echoServer(type: CreateStartScripts) { mainClassName = 'com.wise2c.grpc.App' applicationName = 'echo-server' outputDir = new File(project.buildDir, 'tmp') classpath = jar.outputs.files + project.configurations.runtime } applicationDistribution.into('bin') { from(echoServer) fileMode = 0755 }Copy the code
./gradlew build
Copy the code

3. Implement the Echo interface and start the service

The interface gets the requested content and generates the corresponding content

public class EchoImpl extends EchoServiceImplBase { @Override public void echo(StringMessage request, StreamObserver<StringMessage> responseObserver) { StringMessage reply = StringMessage.newBuilder().setValue("Hello " + request.getValue()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); }}Copy the code

Creating a startup class

public class EchoServer
{
    private static final Logger logger = Logger.getLogger(EchoServer.class.getName());

    private Server server;

    private void start() throws IOException {
        int port = 9090;
        server = ServerBuilder.forPort(port)
                .addService(new EchoImpl())
                .build()
                .start();
        logger.info("Server started, listening on " + port);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                // Use stderr here since the logger may have been reset by its JVM shutdown hook.
                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                EchoServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        final EchoServer server = new EchoServer();
        server.start();
        server.blockUntilShutdown();
    }

}
Copy the code

Run the gRPC Server instance

Oct 24, 2017 4:05:00 PM com. Wise2c. GRPC. EchoServer start information: the Server started, listening on 9090Copy the code

4. Generate Restful reverse proxy (Go) code

Currently, grPC-Gateway supports only the Go Restful reverse proxy

protoc -I/usr/local/include -I. -I$GOPATH/src -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis --grpc-gateway_out=logtostderr=true:. echo/echo_service.proto
Copy the code

5. Create Restful proxy startup classes

package main import ( "flag" "net/http" gw "git.wise2c.com/grpc-gateway-example/echo" "github.com/golang/glog" "github.com/grpc-ecosystem/grpc-gateway/runtime" "golang.org/x/net/context" "google.golang.org/grpc" ) var ( echoEndpoint = flag.String("echo_endpoint", "localhost:9090", "endpoint of YourService") ) func run() error { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() mux := runtime.NewServeMux() opts := []grpc.DialOption{grpc.WithInsecure()} err := gw.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts) if err ! = nil { return err } return http.ListenAndServe(":8080", mux) } func main() { flag.Parse() defer glog.Flush() if err := run(); err ! = nil { glog.Fatal(err) } }Copy the code

Start Restful Interface

bee run
Copy the code

summary

So far, take Kubernetes deployment as an example:

  • Each microservice creation Deployment contains two containers, the gRPC Server implementation of the service and its corresponding reverse proxy. In addition, the storage resources in the same Pod can be accessed by using 127.0.0.1.
  • Create the Service and proxy the Http port for Deployment as well as the RPC port (internally exposing both Http and RPC services).
  • For stateless services, Service is used as DNS between services in the system to implement remote RPC calls.
  • For stateful services, additional service discovery and registries such as Consul or Eureka need to be added. Implement point-to-point invocation.
  • Externally the API Gateway provides Rest apis to external clients (browsers, H5).

In microservice frameworks such as Spring Cloud, each service provides Restful API externally based on HTTP protocol by default, so as to provide service capability externally and internally. In some scenarios, we need to keep Restful simplicity, but also want to fully improve the internal performance and reliability of the application, using gRPC can help us achieve this goal, and using tools like GRPC-Gateway we can quickly based on the PROTO interface definition, In the use of RPC at the same time to provide external Restful, to achieve small software architecture optimization and application performance improvement.