Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Scala でgRPC ScalaMatsuri 2018 1 / 36
Slide 2
Slide 2 text
twitter @xuwei_k github @xuwei-k blog https://xuwei-k.hatenablog.com 2 / 36
Slide 3
Slide 3 text
Scala 忍者 未来から送られてきた関数型プログラミングロボット 3 / 36
Slide 4
Slide 4 text
2017 年のOSS 活動 出したpull request 825 merge されたpull request 750 4520 contributions 4 / 36
Slide 5
Slide 5 text
gRPC 公式サイト grpc.io 5 / 36
Slide 6
Slide 6 text
2015 年2 月にGoogle が 発表したhttp2 を使った RPC フレームワーク 6 / 36
Slide 7
Slide 7 text
google 内部ではstubby という名前で ずっと内部で使われているらしい stubby をOSS として作り直したのがgRPC 7 / 36
Slide 8
Slide 8 text
gRPC デフォルトでは protocol buffers が使われる 他のシリアライズ方式に差し替えることも可能 だがそれほど使われていない? 8 / 36
Slide 9
Slide 9 text
公式対応言語 C++, Java, Python, Go, Ruby, C#, Node.js, Android, Objective-C, PHP PHP はクライアントのみ 9 / 36
Slide 10
Slide 10 text
gRPC とは 公式では Scala は対応していない protocol buffers 自体に plugin があるの で、それでコード生成をして対応できる 内部的には grpc-java を使っている grpc-java の実装はnetty 4.1 を使っている 10 / 36
Slide 11
Slide 11 text
protocol buffers の plugin protoc プラグインの書き方 by @yugui さん yugui さんは元google でgrpc-gateway なども作っておりとても詳しい 11 / 36
Slide 12
Slide 12 text
Protocol Buffers は遅いのか 同僚 遅いかどうかの話じゃなく protocol buffers の特徴をうまく説明している? のでオススメ 12 / 36
Slide 13
Slide 13 text
https://xuwei-k.github.io/scala- protobuf-docs/grpc https://github.com/xuwei-k/grpc-scala- sample 13 / 36
Slide 14
Slide 14 text
Scala での使い方 14 / 36
Slide 15
Slide 15 text
https://github.com/scalapb/ScalaPB Scala での protocol buffers のライブラリ gRPC にも対応している @xuwei-k が対応させました 15 / 36
Slide 16
Slide 16 text
たぶん3 年連続くらいで2 位 16 / 36
Slide 17
Slide 17 text
project/plugins.sbt addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.18") libraryDependencies += "com.thesamet.scalapb" %% "compilerplugin" % "0.7.1" 17 / 36
Slide 18
Slide 18 text
build.sbt import scalapb.compiler.Version.{ scalapbVersion, grpcJavaVersion } PB.targets in Compile ++= Seq( scalapb.gen() -> (sourceManaged in Compile).value ) libraryDependencies ++= Seq( "io.grpc" % "grpc-netty" % grpcJavaVersion, "com.thesamet.scalapb" %% "scalapb-runtime-grpc" % scalapbVersion ) 18 / 36
Slide 19
Slide 19 text
service の定義 https://github.com/grpc/grpc- java/blob/v1.10.0/examples/src/main/proto/helloworld.proto message HelloRequest { string name = 1; } message HelloReply { string message = 1; } service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } 19 / 36
Slide 20
Slide 20 text
Server の実装 https://github.com/xuwei-k/grpc-scala-sample/blob/a5d4fb9a952/grpc- scala/src/main/scala/io/grpc/examples/helloworld/HelloWorldServer.scala#L80- L81 class GreeterImpl extends GreeterGrpc.Greeter { override def sayHello(req: HelloRequest): Future[HelloReply] val reply = HelloReply(message = "Hello " + req.name) Future.successful(reply) } } 20 / 36
Slide 21
Slide 21 text
protobuf でリクエスト、レスポンス、サービスを 定義 リクエストを引数にとって、Future[ レスポンス] を返すメソッドを実装 21 / 36
Slide 22
Slide 22 text
Client リクエストやレスポンスのパーサー的なものは実装の 必要ない https://github.com/xuwei-k/grpc-scala- sample/blob/a5d4fb9a95/grpc- scala/src/main/scala/io/grpc/examples/helloworld/HelloWorldClient. 22 / 36
Slide 23
Slide 23 text
client のインスタンスの生成 val channel = ManagedChannelBuilder .forAddress(host, port) .build() val blockingStub = GreeterGrpc.blockingStub(channel) https://github.com/xuwei-k/grpc-scala- sample/blob/a5d4fb9a952c3e895e791b13786f8eb1681b6f65/grpc- scala/src/main/scala/io/grpc/examples/helloworld/HelloWorldClient.scala#L75-L77 23 / 36
Slide 24
Slide 24 text
リクエストを作成して渡す val request = HelloRequest(name) val response = blockingStub.sayHello(request) 24 / 36
Slide 25
Slide 25 text
Java との違い unary の場合は、StreamObserver は使用せずに、 scala のFuture を返すという規約にした その他の場合はJava と似たような感じで StreamObserver を使用 つまり必要以上に関数型な感じにはあえてしなかった 25 / 36
Slide 26
Slide 26 text
リクエストとレスポンスがそれぞれstream か否か? で4 種類ある Unary Server Streaming Client Streaming Bidirectional Streaming 26 / 36
Slide 27
Slide 27 text
/* unary */ rpc hello(Req) returns (Res){} /* server streaming */ rpc hello(Req) returns (stream Res){} /* client streaming */ rpc hello(stream Req) returns (Res){} /* bidirectional streaming */ rpc hello(stream Req) returns (stream Res){} 27 / 36
Slide 28
Slide 28 text
4 種類の実装のサンプル 28 / 36
Slide 29
Slide 29 text
Unary リクエストを1 つ送るとレスポンス1 つ返る def hello(req: Req): Future[Res] = { // req: Req を使って Future[Res] を返す処理 } 29 / 36
Slide 30
Slide 30 text
Server Streaming リクエストを1 つ送るとレスポンスがゼロ個以上の複数 返る def hello(request: Req, observer: StreamObserver[Res]): Unit = { // observer.onNext を0 回以上複数回呼ぶ } 30 / 36
Slide 31
Slide 31 text
Client Streaming リクエストを複数送ると、レスポンスが返る def hello(observer: StreamObserver[Res]) = new StreamObserver[Req] { // onNext などを実装 } 31 / 36
Slide 32
Slide 32 text
Bidirectional Streaming リクエストを複数送ると、レスポンスが複数返る(?) def hello(observer: StreamObserver[Res]) = new StreamObserver[Req] { // onNext などを実装 } 32 / 36
Slide 33
Slide 33 text
無理してstream 使わずに、どうしても必要でない限り unary だけで良い気がする ( 個人の感想) 33 / 36
Slide 34
Slide 34 text
server streaming 使うと、たしかにサーバーからの push が簡単にかけそう・・・? 34 / 36
Slide 35
Slide 35 text
bidirectional はエラー処理や状態を考えると、 かえって色々自由すぎて面倒・・・? 誰か良いユースケースがあったら逆に教えて欲しい 35 / 36
Slide 36
Slide 36 text
質問コーナーや、ライブコーディング 36 / 36