GeekGig 『DONUTS×Showcase Gig』〜Goでゼロから作り直した話〜 で発表したスライドです。
https://showcase-gig.connpass.com/event/235635/
confidentialGo+gRPCで作った次世代店舗の裏側 2022-02-22GeekGig 『DONUTS×Showcase Gig』〜Goでゼロから作り直した話〜🐔 Hayashi Takuya
View Slide
confidentialHayashi Takuya 自己紹介Showcase Gig店内機器の開発 /連携を行うチームのエンジニア兼チームリーダーをやっていますGitHub: howyitwitter: @howyi_lq
confidential©Showcase Gig● 次世代店舗の紹介● 次世代店舗のシステム構成● gRPCサーバの利用者向けSDKの用意● ロッカーとの接続を行うエッジサーバについて● gRPCを採用してよかったこと今日話すこと
confidential©Showcase Gig次世代店舗の紹介
confidential©Showcase Gig● スマホから事前に注文&決済● QRを読み取り、自動で開くロッカーから非対面で受け取りThe Label Fruit
confidential©Showcase GigThe Label Fruit ● 店外に商品の出来上がりを通知するサイネージ● 注文はリアルタイムでサイネージに表示される● 受取ロッカーの各扉にディスプレイ● QRコードの読み取り後、ロッカーの扉は専用の演出が流れる
confidential©Showcase Gig次世代店舗のシステム構成
confidential©Showcase Gig次世代店舗のシステム構成 O:der Platformモバイルオーダーの基盤となる機能を提供するバックエンド注文の永続化、支払い処理、外部サービスへの通知等、モバイルオーダーを実装するための基盤を持つ
confidential©Showcase Gig次世代店舗のシステム構成 店内機器リアルタイム通信基盤店内機器リアルタイム通信基盤店舗内の機器とリアルタイム通信を確立するためのバックエンド機器の管理、認証基盤としての機能も持つ機器とのリアルタイム通信には gRPCStreamingを使用する配信内容の例● 注文の状態● ロッカーの状態
confidential©Showcase Gig次世代店舗のシステム構成 店内機器リアルタイム通信基盤Streaming Streaming ロッカー サイネージ キッチンディスプレイ (調理場に注文を伝えるアプリ)
confidential©Showcase GiggRPCサーバの利用者向けSDKの用意
confidential©Showcase GiggRPCサーバの利用者向けSDKの用意 複数箇所からAPIを叩くため、各リポジトリに同様のコードが散在しないよう APIを利用するにあたっての最低限の機能を提供するSDKの機能● APIのprotoから生成したコード(go/gen/)以下● 認証周りの機能ディレクトリ構成
confidential©Showcase GiggRPCサーバの利用者向けSDKの用意 go.modがリポジトリ直下以外にある場合、 goはそのリポジトリをMulti-Module Repositoriesとして認識するディレクトリ構成
confidential©Showcase GiggRPCサーバの利用者向けSDKの用意 このとき、目的のモジュールへタグを打つときはv1.0.0ではなく、go.modへの相対パスをプレフィックスに含める必要がある今回の例だと、go/v1.0.0 のタグを打って初めてgo get github.com/showcase-gig/sdk/[email protected]といった形でパッケージをインストールすることができるディレクトリ構成
confidential©Showcase GiggRPCサーバの利用者向けSDKの用意 タグをGitHubリリースした時ときに自動で go/{tag} のタグを切るようにGitHub Actionsで設定しているname: "On release"env:CI: trueon:release:types: [published]jobs:go-release:name: go releaseruns-on: ubuntu-lateststeps:- name: Set version variableid: versionrun: |VERSION=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")echo ::set-output name=version::$VERSION- name: checkoutuses: actions/checkout@v2- name: tag to go sdkrun: |git tag go/${{ steps.version.outputs.version }}git push origin go/${{ steps.version.outputs.version }}
confidential©Showcase Gigロッカーとの接続を行うエッジサーバについて
confidential©Showcase Gig次世代店舗のシステム構成 店内機器リアルタイム通信基盤Streaming ロッカー
confidential©Showcase Gigロッカーの機能 ロッカー 店内機器リアルタイム通信基盤ドアの解錠命令 (gRPC Streaming) QRコードの読み取り等 (gRPCUnary)
confidential©Showcase Gig既存のIoTロッカーとの兼ね合い 店内機器リアルタイム通信基盤ロッカー IoTロッカー(既存のものを流用) IoTロッカー ソフトウェアドアの解錠命令 (gRPC Streaming) QRコードの読み取り等 (gRPCUnary) QRコードの読み取り等 (HTTPPOST) ドアの解錠命令 (WebSocket) 🥺 ロッカーのソフトウェアと、リアルタイム通信基盤はそもそも別の用途で作られていたため、使用している通信技術が大きく変わっている
confidential©Showcase Gig既存のIoTロッカーとの兼ね合い 店内機器リアルタイム通信基盤ロッカー IoTロッカー(既存のものを流用) IoTロッカー ソフトウェアドアの解錠命令 (gRPC Streaming) QRコードの読み取り等 (gRPCUnary) QRコードの読み取り等 (HTTPPOST) ドアの解錠命令 (WebSocket) IoTロッカーとリアルタイム通信基盤を変換するサーバを新設する案● HTTP&WebSocketのサーバとして動作し、ロッカーソフトウェアの認証を行う● 常にgRPC Streamingで基盤と接続を確立する変換サーバ
confidential©Showcase Gig既存のIoTロッカーとの兼ね合い 店内機器リアルタイム通信基盤ロッカー IoTロッカー(既存のものを流用) IoTロッカー ソフトウェアドアの解錠命令 (gRPC Streaming) QRコードの読み取り等 (gRPCUnary) QRコードの読み取り等 (HTTPPOST) ドアの解錠命令 (WebSocket) IoTロッカーとリアルタイム通信基盤を変換するサーバを新設する案● 新規サーバ構築にあたっての基盤構築の必要性● 今回のロッカーソフトウェア専用のサーバとなり、負債となるリスク変換サーバ
confidential©Showcase Gigエッジサーバの配置による解決 店内機器リアルタイム通信基盤ロッカー IoTロッカー(既存のものを流用) IoTロッカー ソフトウェアドアの解錠命令 (gRPC Streaming) QRコードの読み取り等 (gRPCUnary) QRコードの読み取り等 (HTTPPOST) ドアの解錠命令 (WebSocket) エッジサーバロッカー内部に通信を仲介するエッジサーバを作ってしまう案● 既存のIoTロッカーはlocalhostに向けて今まで通り通信してもらう● エッジサーバは通信を変換し、認証情報を付与したうえでロッカーとして振る舞う● 既存のハードウェアに入り、運用するサーバや端末が増えることはない● ロッカー <-> エッジサーバ間はローカル通信のため、認証について考える必要がない
confidential©Showcase Gigエッジサーバの開発 ドアの解錠命令 (gRPC Streaming) QRコードの読み取り等 (gRPCUnary) QRコードの読み取り等 (HTTPPOST) ドアの解錠命令 (WebSocket) エッジサーバ必要な機能● gRPC Streamingで基盤との常時接続を保つ● HTTPサーバとして動き、リクエストを gRPC Unaryに変換してサーバへ送信する● WebSocketサーバとして起動しgRPC Streamingのイベントを接続中のクライアントに配信する● gRPCの接続時は認証情報を付与し、サーバにはロッカーとして振る舞う● cliツールとして配布し、 IoTロッカーソフトウェアの起動時に同時に裏で起動する店内機器リアルタイム通信基盤IoTロッカー ソフトウェア
confidential©Showcase Gigエッジサーバの開発 ● CLIアプリケーションとして動作すればいいことから、使い慣れているGoを採用● 店内機器リアルタイム通信基盤用のSDKを使用しているため、リポジトリ内のコード量はかなり少なく済んだ● 簡単に各OS向けのビルドができ、ビルドしたバイナリを配布するだけでエッジデバイス上で動かせるのはGoの大きなメリット○ 実際、macで開発しwindowsで動かしていたが、OS毎での問題には一度も直面しなかったビルドコマンド例GOOS=windows GOARCH=386 go build -o edge.exe cmd/locker-edge/main.go
confidential©Showcase Gigエッジサーバの開発 実行時にsync.ErrGroupで● gRPCのStreaming(Subscribe)● HTTPサーバ (POST, WebSocket)のgoroutineを起動eg, ctx := errgroup.WithContext(ctx)httpServer := di.NewHttpServer(cfg, logger)eg.Go(func() error {err := httpServer.Start()return err})grpcClient := di.NewGrpcClient(cfg, logger)eg.Go(func() error {err = grpcClient.Subscribe(ctx)return err})<-ctx.Done()// シャットダウン処理
confidential©Showcase GiggRPCを採用してよかったこと
confidential©Showcase GigProtocolBuffersによる API定義の一元管理 柔軟な表現が可能gRPCを採用してよかったことgoのコード生成時にマッピングする package名google提供のannotation機能のimportサービスのRPCを定義optionでgrpc-gatewayのpathを定義grpc-gatewayのサンプルコードStringMessageという型を定義
confidential©Showcase GigProtocolBuffersによる API定義の一元管理 柔軟な表現が可能コメントなども含めてドキュメントに出力することも可能なため、protoファイル以外の場所にパラメータの細かい仕様などが散在する状況をある程度避けられるgRPCを採用してよかったことprotobuffetを使うとこのような形で protoからAPIドキュメントを生成できる
confidential©Showcase GiggRPCのコード生成 protoc(Protocol Buffer Compiler)によるコード生成が手厚いgRPCを採用してよかったこと公式でコード生成をサポートしている言語
confidential©Showcase GiggRPCのコード生成 protoc(Protocol Buffer Compiler)によるコード生成が手厚いAPIを利用するにあたって書くコードが大幅に少なく済み、かつ型安全になる社内ではprotoから複数のプログラミング言語に向けてのSDKを自動生成するように○ PHP/Go/Dart/Kotlin/JavaScript○ https://note.com/scg_tech/n/n45c13047c648gRPCを採用してよかったこと
confidential©Showcase Gigまとめ
confidential©Showcase Gigまとめ ● まずサーバを作るという判断をせず、他の方法でも解決できないか考える● Goの用途は幅広く、並行処理も書きやすいのでエッジサーバなどの用途でも便利● gRPCはコード生成も手厚く、リアルタイム通信も使いやすい○ ブラウザの場合は直接利用できないが、grpc-webなどの手段で対応可能
confidential©Showcase Gigおわり