tokuhirom's blog

armeria で grpc するサンプルコードをかいた

https://github.com/tokuhirom/armeria-sample line が出している rpc フレームワークであるところの armeria が最新版で grpc をサポートしたとのことで、実際どんなもんか試してみた。

試すのは簡単。build.gradle に protobuf プラグインを追加。

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
    }
}

apply plugin: 'com.google.protobuf'

protobuf {
    protoc {
        // The version of protoc must match protobuf-java. If you don't depend on
        // protobuf-java directly, you will be transitively depending on the
        // protobuf-java version that grpc depends on.
        artifact = "com.google.protobuf:protoc:3.0.0"
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0'
        }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
    }
}

idea {
    module {
        sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java");
        // If you have additional sourceSets and/or codegen plugins, add all of them
        sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/grpc");
    }
}

dependencies {
    ["grpc-core", "grpc-stub", "grpc-protobuf"].each { module ->
        compile "io.grpc:$module:1.0.0"
    }
}

src/main/proto/hi.proto とかに以下のように protobuf の定義を置く。

syntax = "proto3";

package hi;

option java_multiple_files = true;
option java_package = "com.example.grpc";
option java_outer_classname = "HiProto";
option objc_class_prefix = "HI";

message MyStringValue {
    string value = 1;
}

service Hi {
    rpc Hello (MyStringValue) returns (MyStringValue) {
    }
}

で、./gradlew generateprotoで java コードが生成されるのでそれを継承したクラスを実装する。src/main/java/com/example/grpc/HiService.java 使い勝手は thrift と大差ない。

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class HiService extends HiGrpc.HiImplBase {
    @Override
    public void hello(MyStringValue request, StreamObserver<MyStringValue> responseObserver) {
        responseObserver.onNext(MyStringValue.newBuilder()
                .setValue("Hi, " + request.getValue() + "!")
                .build());
        responseObserver.onCompleted();
    }
}

最後に armeria サーバーの起動部分だけ実装すれば完成。簡単。

public class MyApp {
    public static void main(String[] args) {
        ServerBuilder sb = new ServerBuilder();
        sb.port(8080, SessionProtocol.HTTP);
        GrpcService grpcService = new GrpcServiceBuilder()
                .addService(new HiService())
                .build();
        sb.serviceUnder(
                "/",
                grpcService.decorate(LoggingService::new));
        Server server = sb.build();
        server.start();
    }
}

gRPC 採用した場合のメリット

もともと armeria は thrift 用のサーバーなわけだけど、gRPC を採用した場合には以下のような恩恵を得られます。

  • Full support for request/response streaming
  • Protocol buffer generated code can be a nice change
  • Efficient clients on a variety of platforms (Android, iOS, Go, etc)

一方で、grpc 使うと DocService 使えないとか JSON で利用できないとかそういうデメリットも現状あるようだ

armeria の上で gRPC 動かした場合のメリット

一方、gRPC 使ってるユーザーが armeria の上で gRPC を動かすメリットとしては以下のようなことがあるとのこと

  • Support for HTTP1 (not verified, will probably require some followup work). HTTP1 should open GRPC to the browser and work better with Cloud load balancers that generally translate HTTP2 -> HTTP1
  • Once implemented, DocService and Grpc on the same server
  • And any other servers they feel like having on the same server since armeria's flexible that way :)

とはいえ、現状だと grpc のクライアントって直接 HTTP で話せるわけでもないし HTTP1 サポートしたいというモチベーションも薄いかなあ。protobuf の方がネックになるし。あと DocService も grpc に対応してない様子。

DocService に対応して、さらに JSON エンドポイントが自動で生えるぐらいまでなったらぜひ使いたい。 https://github.com/grpc-ecosystem/grpc-gateway 的な感じで、GrpcJsonServiceBuilder.service(myService).build() とかで JSON API 提供できる、とかだと嬉しい。

まとめ

今後に期待。

Created: 2016-08-30 23:38:46 +0000
Updated: 2016-08-30 23:38:46 +0000