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 提供できる、とかだと嬉しい。
# まとめ
今後に期待。