Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
新卒エンジニアが0からNon-BlockingなgPRCサーバーを作った話
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
株式会社出前館
June 17, 2024
Technology
1k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
新卒エンジニアが0からNon-BlockingなgPRCサーバーを作った話
JJUGにて登壇した内容です
株式会社出前館
June 17, 2024
More Decks by 株式会社出前館
See All by 株式会社出前館
出前館のメニュー登録・更新用APIをSpring Boot+Kafkaで実現したお話
demaecan
0
230
現実的なセキュリティ体制の構築 限られたリソースの中で成果を最大化する「選択と集中」
demaecan
7
4.8k
中期計画、2回作ってみた ~業務委託と正社員、両方の視点から~
demaecan
1
1.2k
複雑にからみあう複数のシステムを要する出前館QAの実情、展望
demaecan
0
220
QA業務を変える(!?)AIを併用した不具合分析の実践
demaecan
0
260
出前館アプリの品質を支えるリリーストレインとその実践
demaecan
0
290
出前館アプリ進化論 アーキテクチャと組織のリアルな変⾰の舞台裏
demaecan
0
970
Flutterにしてよかった?出前館アプリを2年運用して気づいたことを全部話します
demaecan
1
1.4k
Boxを“使われる場”にする統制と自動化の仕組み
demaecan
1
530
Other Decks in Technology
See All in Technology
WAF 運用改善の承認サイクル/SRE_BizReach_MIXI_1
visional_engineering_and_design
2
420
omasushiというライブラリを作った
polidog
PRO
0
200
AIで開発は速くなったのに、なぜ現場は楽にならないのか 〜あなたの組織のボトルネックを突き止めるワークショップ〜
jacopen
1
320
AIオーケストレーションを活用した 開発ワークフローの設計と実践
bqnq
0
130
TinyGo 開発サイクルを高速化する:Go で作るエミュレータ入門
zozotech
PRO
1
600
【視聴者参加型!】AWSセキュリティアンチパターンクイズ
syoshie
1
490
深夜のクラウド懺悔室 1:29:300 or 1:0:0
kazzpapa3
1
230
2026-09-10 【Snowflake World Tour Tokyo 2026】dbt Core と Snowflake で実現する多層的なデータガバナンス / Multi-Layered Data Governance Powered by dbt Core and Snowflake
civitaspo
0
310
20260912_スクラムにジェネラリストは必要か
ryugen04
0
320
Gitは怖い?共有ワークスペースから始めるSnowflakeチーム開発
coco_se
0
110
20260906 「AWS運用入門」著者が教える、運用業務への生成AI活用入門
masaruogura
0
260
OpenTelemetryのメトリクスをCloudWatchに送ってPromQLで見てみた
ota1022
0
120
Featured
See All Featured
The SEO Collaboration Effect
kristinabergwall1
1
550
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
590
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
How to train your dragon (web standard)
notwaldorf
97
6.8k
Believing is Seeing
oripsolob
1
210
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
330
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Speed Design
sergeychernyshev
33
2.1k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
490
The agentic SEO stack - context over prompts
schlessera
0
920
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
42k
Transcript
新卒エンジニアが 0 から Non-Blocking な gRPC サーバーを作った話 株式会社出前館 佐藤 幸樹
⾃⼰紹介 2023年4⽉ LINE株式会社 (現LINEヤフー株式会社) 新卒⼊社 2023年7⽉ 株式会社出前館へ出向 商品管理・決済周りのバックエンド開発 学⽣の頃はRailsなどで開発していたが、LINEに⼊ってJVM系の⾔語で 開発するようになりました。
2
主な対象 • REST API は書いたことがあるが gRPC でサービスを作ったことがない⽅ • Non-Blockingな処理をするサーバーを作ったことがない⽅ •
(Spring Bootでアプリケーションを作ったことがある⽅) gRPC や Non-Blocking に興味を持ってもらい、今後開発する際の技術選定の 参考にしてもらいたい。 3 https://github.com/sato9818/jjug-sample
出前館について システム刷新 gRPC と Non-Blocking 技術選定 苦労した点 01 02 03
04 05 4 ⽬次
出前館について システム刷新 gRPC と Non-Blocking 技術選定 苦労した点 01 02 03
04 05 5 ⽬次
出前館 6 Web サイトやアプリから料理、⾷品、⽇⽤品を注⽂できる 国内最⼤級のデリバリーサービス 2000年 10⽉ 「出前館」サービス開始 2023年 •
アクティブユーザー数約650万⼈ • 年間7730万件注⽂
出前館 7 バックエンドは • Spring Boot • Java • Kotlin
をメインに構築されています 決済サービスとカートサービスを担当
出前館について システム刷新 gRPC と Non-Blocking 技術選定 苦労した点 01 02 03
04 05 8 ⽬次
システム刷新 問題 • システムのレガシー化 • オンプレ環境を管理する⼯数がかかる • フレームワークや⾔語が古く、サポートが終了している • 古い技術に対応できる⼈が少ない
Þ2020年にマイクロサービス化を進めていく過程で、ある程度解消 ✅ オンプレからAWSに移⾏ ✅ コードのリライト 9
システム刷新 しかしまだ問題が… • 技術的負債 • 1つの Oracle DB のテーブルに複数のサーバーが参照している(密結合) •
仕様的負債 • 加盟店(レストラン等)によって少しずつ違う仕様があることで、開発コスト増 10
システム刷新 再度システム刷新が必要︕ • 仕様のシンプル化: 可能な限りお店独⾃仕様の撤廃 • DB の分離: マイクロサービスごとにDBを持つ (Oracle
→ MySQL、MongoDB) • コスト削減: AWS → プライベートクラウド • etc… 11
After Before 通信⽅式 処理⽅式 REST API Blocking gRPC Non-Blocking 12
システム刷新 DB Oracle MySQL
出前館について システム刷新 gRPC と Non-Blocking 技術選定 苦労した点 01 02 03
04 05 13 ⽬次
gRPC Google によって開発された、クライアントとサーバ間の通信⼿段の1つ PRC: Remote Procedure Call (遠隔⼿続き呼び出し) `g`については諸説あり (Google?
General?) 特徴 • HTTP/2を使った⾼速な通信が可能 • ローカルにある関数を呼び出すかのように、サーバーにリクエストできる • さまざまな⾔語に対応している (Java, Kotlin, Go...) 14
gRPC 4つの通信⽅式 • Unary RPC: 1リクエスト 1レスポンス • 例: ユーザー情報の取得
• Server streaming RPC: 1リクエスト nレスポンス • 例: ビデオストリーミング、株価のリアルタイム更新 • Client streaming RPC: nリクエスト 1レスポンス • 例: ファイルアップロード、センサーデータの収集 • Bidirectional streaming RPC: nリクエスト nレスポンス • 例: リアルタイムチャットアプリケーション 15
Protocol Buffers (protobuf) Protocol Buffers という IDL (Interface Definition Language*)
を⽤いて、 APIのインターフェースを定義する ソースコードを⽣成するには…? • Protobuf のコンパイラである protoc を使う 厳密にはソースコードを⽣成する際には protoc プラグインが必要 (Javaコードを⽣成したい場合は、それ⽤のプラグインが必要) 16 *Interface Definition Language: プログラミング⾔語とは異なり、インターフェースを記述することに重きを置いた⾔語
Protocol Buffers (protobuf) 17 syntax = “proto3”; package sample; //
ユーザーの情報を取得 service UserService { // IDに基づいてユーザーの情報を取得 rpc GetUser(GetUserRequest) returns (GetUserResponse); } // ユーザー情報を取得するリクエスト message GetUserRequest { int32 id = 1; // 取得したいユーザーのID } // 取得したユーザーの情報 message GetUserResponse { int32 id = 1; // ユーザーのID string name = 2; // ユーザーの名前 string email = 3; // ユーザーのメールアドレス }
Protocol Buffers (protobuf) 18 syntax = “proto3”; package sample; //
ユーザーの情報を取得 service UserService { // IDに基づいてユーザーの情報を取得 rpc GetUser(GetUserRequest) returns (GetUserResponse); } // ユーザー情報を取得するリクエスト message GetUserRequest { int32 id = 1; // 取得したいユーザーのID } // 取得したユーザーの情報 message GetUserResponse { int32 id = 1; // ユーザーのID string name = 2; // ユーザーの名前 string email = 3; // ユーザーのメールアドレス } package sample; public final class UserServiceOuterClass { private UserServiceOuterClass() {} public static void registerAllExtensions( com.google.protobuf.ExtensionRegistryLite registry) { } public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { registerAllExtensions( (com.google.protobuf.ExtensionRegistryLite) registry); } public interface GetUserRequestOrBuilder extends // @@protoc_insertion_point(interface_extends:sample.GetUserReq uest) com.google.protobuf.MessageOrBuilder { … $ protoc --java_out=. example.proto protobuf Java クラス
REST API 共通 gRPC プロトコル HTTP/1.1が⼀般的 HTTP/2 データフォーマット JSONやXMLなどテキスト ベース
Protocol Buffers 開発の容易さ シンプルで直感的 Protocol Buffersを 覚えなきゃいけない分⼤変 Client Sever間の規約 ゆるい 厳しい 互換性 異なる⾔語間で通信可能 19 gRPC vs REST API
gRPC 個⼈的に便利だと思った点 • Protocol Buffers で型が定義できるので、リクエストする際に型を間違えて エラーにならない • クライアントとサーバーで同じスキーマを共有するので、タイポしてエラーにならない •
Streaming など拡張性が⾼い 20
Non-Blocking 処理 スレッドや関数を実⾏した際に、その実⾏したスレッドをブロックしないで結果を得る処理 óBlocking 処理 スレッドや関数を実⾏した際に、その実⾏したスレッドをブロックして結果を得る処理 21
⽐較 22 Client Server1 Server2 リクエスト1 リクエスト2 レスポンス1 レスポンス2 待ち
待ち Blocking Client Server1 Server2 リクエスト1 リクエスト2 レスポンス1 レスポンス2 待ちがない Non-Blocking スレッドをブロッキングしている スレッドをブロッキングしない ※リクエスト1とリクエスト2には依存関係がない
Blocking 23 public void getUserAndItem(String userId, String itemId) { final
User user = getUser(userId); final Item item = getItem(itemId); System.out.println("user: " + user.toString() + ", item: " + item.toString()); } public User getUser(String id) { // サーバーAにUser情報を取りに⾏く。 } public Item getItem(String id) { // サーバーBにItem情報を取りに⾏く } 1秒 2秒 1秒
Non-Blocking 24 public void getUserAndItem(String userId, String itemId) { CompletableFuture<User>
userFuture = getUser(userId); CompletableFuture<Item> itemFuture = getItem(itemId); userFuture.thenCombine(itemFuture, (user, item) -> { System.out.println("user: " + user.toString() + ", item: " + item.toString()); return null; }).join(); } public CompletableFuture<User> getUser(String id) { // サーバーAにUser情報を取りに⾏く。 } public CompletableFuture<Item> getItem(String id) { // サーバーBにItem情報を取りに⾏く } 1秒 1秒 1秒ちょい
Non-Blocking ⼿法 Javaの場合 • CompletableFuture • Reative Streams Kotlinの場合 •
Kotlin Coroutine 25
Non-Blocking IO アプリケーションの内部の処理の改善だけでもでも処理は効率化する さらなる効率化をするには・・・ アプリケーションがリクエストを受けて、レスポンスを返すまで全て Non-Blocking にする ネットワーク越しでデータのやり取りをするようなライブラリを全て Non-Blocking (Non-Blocking
IO) に 対応させる必要がある 例えば・・・ • DBからのデータの取得 • HTTP Clientを使⽤した他サーバーからのデータの取得 • アプリケーションサーバー 26
1つのリクエストにつき、1つのスレッドを割り当てる。 課題 もし⼤量のリクエストが来たら︖ → ⽣成できるスレッドの数は限られている。 → スレッドを増やしすぎるとコンテキストスイッチのコストも上がる。 Blocking IO 27
Client Blockingサーバー Client Client Thread Thread Thread Multi-Thread Blocking IO
Blocking IO 28 Client Blockingサーバー Client Client Thread Thread Thread
Multi-Thread Blocking IO 課題 別サーバーからのレスポンスが遅延したら︖ → そのスレッドはブロックされて 他のリクエストを処理するのに使えなくなる。 → 内部の処理をNon-blockingにしても スレッド⾃体は占有されてしまう。 別サーバー 遅延 Client New! 占有
Non-Blocking IO 29 Non-Blocking IO イベントループという仕組みを使うことでスレッドを ブロックしなくなり、少数のスレッドで複数のリクエストを 処理できるようになる。 暇なスレッドがリクエストを処理に⾏けるイメージ。 Client
Non-Blockingサーバー Client Client イベントループ
Non-Blocking IO 30 Multi-Thread Blocking IO 別サーバーなどからのレスポンスが 遅延したとしてもその待ち時間にスレッドは 他のリクエストの処理をすることができる。 Client
Non-Blockingサーバー Client Client イベントループ 別サーバー 遅延 Client New!
Non-Blocking IO • Javaではイベントループを実装しているNettyというネットワークライブラリが 使われることが多い。 参考*: 「JJUG CCC 2018 Spring
- I-7 (俺が)はじめての Netty」 • Non-Blocking IO ではアプリケーションの内部でスレッドをブロックしてしまうと、 致命的にパフォーマンスが落ちる。 • 少数のスレッドだけで、スレッドがブロッキングされないこと前提で動いているので、処理 できるスレッドが減ってしまう。 31 * https://www.slideshare.net/slideshow/jjug-ccc-2018-spring-i7-netty/99033170
Non-Blocking IO 32 Multi-Thread Blocking IO 別サーバーへのリクエストはNon-Blocking にする必要がある。 Non-Blockingに対応しているライブラリを使おう。 Client
Non-Blockingサーバー Client Client イベントループ 別サーバー 遅延 Client New! ブロックしちゃダメ!!
Non-Blocking IO対応ライブラリ 33 Blocking IO Non-Blocking IO DB JDBC R2DBC
Redis Jedis Lettuce Web framework Spring MVC Spring WebFlux Armeria HTTP Client Spring RestClient Spring Webclient
Non-Blocking IO WEBフレームワーク • Spring WebFlux • Armeria • Vert.x
• Quarkus • Micronaut • Helidon 34
Blocking Non-Blocking 多くのリクエストを捌くのに 必要なリソース 多くのリソース 少数のリソース スケーラビリティ 低い ⾼い 実装の複雑性
(コードの追いやすさ) シンプル 複雑 学習コスト 低い ⾼い 35 Non-Blocking vs Blocking
出前館について システム刷新 gRPC と Non-Blocking 技術選定 苦労した点 01 02 03
04 05 36 ⽬次 https://github.com/sato9818/jjug-sample
システム概要 37
システム概要 38
Buf Protobuf のコンパイラ。Protoc のプラグインを使える。 特徴 • Protoc の2倍の速さのコンパイル • Protobuf
の Linter を備えている • Protobuf が破壊的変更をしたかどうか検知できる • gRPC の Request の validation をできる • Buf Schema Registry という Protobuf を⼀元管理してくれるプラットフォームを 提供している 39
Buf Gradleプラグインも提供されている。 (https://github.com/bufbuild/buf-gradle-plugin) Gralde タスクを通して • ソースコードの⽣成 • Lint •
破壊的変更の検知 などができる。 40
Buf 実際にgradleで⽣成する⽅法をみてみましょう。 ブランチ: 1-buf-build 41
技術選定 42
gRPC-java Java で gRPC サーバー、クライアントを作るライブラリ群。 • サーバー側は Netty でできているのでこのライブラリでサーバーを作成すると Non-Blocking
なサーバーになる。 • しかし、アプリケーションが実⾏されるスレッドはブロッキングされても良いような 実装になっているのでブロッキングする実装でもOK。 • ⼀般的に java で gRPC サーバーやクライアントを作りたい場合はこのライブラリ を使うことになる。 参考: https://github.com/grpc/grpc-java 43
gRPC-java ⼀旦 gRPC-java だけを使ってサーバーとクライアントがどのように動くかみてみましょう。 ブランチ: 2-grpc-java 44
技術選定 45
Spring Boot ⾔わずと知れた Java の Web フレームワーク 特徴 • Dependency
Injection • Transaction Manager • Data Binding 選定理由 出前館のマイクロサービスのほとんどは Spring Boot を使っているので、 共通フレームワークの1つとして認識されている。 46
Spring Boot with gRPC gRPC-java と Spring Boot は親和性がない。 Spring
Boot の機能を使って gRPC を実装したい︕ • LogNet/grpc-spring-boot-starter: 2023年9⽉に開発が⽌まってる。 • grpc-ecosystem/grpc-spring • line/armeria 47
Spring Boot with gRPC grpc-ecosystem/grpc-spring • Spring Security も対応している •
アノテーションベースで Spring Like な開発ができる line/armeria • LINEヤフー社で開発しているので、サポートしてもらいやすい • LINEヤフー社内事例が多く存在し、困った時に社内のコードを検索すると 参考になるコードがたくさんある • 便利機能がたくさんある 参考: https://github.com/grpc/grpc-java 48
Armeria Netty の創始者である Trustin が作った Non-Blocking な RPC フレームワーク 特徴
• 旧LINEで開発が始まったOSS • Netty をベースとした Non-Blocking HTTP/2 サーバー • gRPC-java を内包しているので、Non-Blocking な gRPC サーバーを作成できる 49
Armeria いいところ • LINEヤフー社内事例が多く存在し、困った時に社内のコードを検索すると 参考になるコードがたくさんある。 • LINEヤフー社内 slack に help
チャンネルがあり、困った時にすぐに聞ける環境 が存在する。(外部向けにも discord server があり、そこでも質問できる) • 便利機能が多くある。 50
Armeria 便利機能その1 • DocService: SwaggerのようなgRPC対応のドキュメンテーションサービス 51
Armeria 便利機能その2 • Decorator Decorator機能を使うことで、リクエストやレスポンスの前後に処理を挟むことができる 例 • Logging: リクエスト、レスポンスのログをいい感じに出してくれる。 •
Retry: クライアントのリクエストでタイムアウトなどが発⽣した際にリトライをする機能。 • CircuitBreaker: リクエスト先のサーバーで何か異常があった時に、リクエストを遮断する機能。 52
Armeria ⼀旦 Spring Boot は置いといて、Armeria単体でどのようにサーバー実装 をするのかみてみましょう。 ブランチ: 3-armeria 53
Armeria with Spring Boot Armeriaは Spring Boot との統合も提供している。 何がいいか サーバーはArmeriaのものを使って
• Dependency Injection • Transaction Manager • Data Binding といった 機能は Spring Boot のものを使うということができる。 54
Armeria with Spring Boot どのように Armeria と Spring Boot を統合させるかみてみましょう。
ブランチ: 4-armeria-spring 55
技術選定 56
HTTP Client 決済をするには外部決済代⾏会社にリクエストをする必要がある Armeria が HTTP Client を提供している。 • Retrofit
• Spring WebClient 57
HTTP Client Retrofit • Square社が開発している Java や Android 向けの Http
Client。 Non-Blocking に対応している。 • インターフェイスを定義する形で API リクエストを定義できる。 • Mock ライブラリなど、周辺ライブラリも充実している。 WebClient • Spring Framework の1つで Non-Blocking に対応した Http Client。 • プログラム的に API リクエストを設定する。 • Reactive Streamsに対応している。 58
Armeria with Retrofit Armeriaと統合することで何がいいか • Decoratorが使える • Retry機能 • Circuit
breaker機能 59 ArmeriaRetrofit armeriaRetrofit = ArmeriaRetrofit.builder() .baseUrl("http://example.com") .decorator(LoggingClient.newDecorator()) .decorator(CircuitBreakerClient.newDecorator(circuitBreaker)) .decorator(RetryingClient.newDecorator(retryConfig)) .build();
技術選定 60
R2DBC (Reactive Relational Database Connectivity) Reactive Streams をベースにアクセスを Non-Blocking にするDBドライバ。
JDBCのようなドライバーでDBに Blocking アクセスをすると、DBアクセスの間 スレッドがブロックされて、パフォーマンス悪化の原因になる。 • r2dbc-mysql: MySQL ⽤のドライバー • r2dbc-pool: コネクションプーリングライブラリ • Spring-boot-starter-data-r2dbc: Spring Boot と R2DBC の統合 61
技術選定 62
出前館について システム刷新 gRPC と Non-Blocking 技術選定 苦労した点 01 02 03
04 05 63 ⽬次
苦労した点 • モダンな技術を使っているので、資料がたくさんあるわけではなく、理解するために 実際にコード読んだりするのが⼤変だった。 • 欲しい機能がない場合は実際 PR 作ってコントリビュートしたりした。 • https://github.com/line/armeria/pull/5555
• https://github.com/line/armeria/pull/5613 • https://github.com/line/armeria/pull/5617 • https://github.com/bufbuild/buf-gradle-plugin/pull/170 • でも総じてモダンな技術に触れられて楽しい︕ 64
宣伝 こんなモダンな技術を使える出前館に⼊社してみませんか︕︖ • 新卒採⽤ • エンジニア • 中途採⽤ • サーバーサイドエンジニア
• シニアサーバーサイドエンジニア • フロントエンドエンジニア • インフラエンジニア • データベースエンジニア • SRE • QAエンジニア https://recruit.demae-can.co.jp/ 65
66