1. 人間FM
  2. #66: リアルタイム非同期通信
2023-03-26 15:44

#66: リアルタイム非同期通信

※普通に仕事の話をしています。睡眠導入として活用ください。

※途中「BFF」を「Background For Frontends」と説明していますが、「"Backends" For Frontends」の誤りです。すみません(Best Friend Foreverでもありません)


よこやまは途中からついていけなくなりました。


gRPCとは | https://atmarkit.itmedia.co.jp/ait/articles/2211/04/news002.html


---

人間FMへのおたよりはこちら

https://forms.gle/atg3mpRJ6W83DjYv9

API処理の時間問題
横山です 太宙です 一応ちょっと注釈としてなんか今から僕らは全然多分みんなに伝わるような話をするつもりがない
普通に相談をしようと思ってるんですけど まあ良かったら睡眠導入としてなんかよくわかんない話を聞くっていうことで使いたい人が
いればこの先も再生してください はい でまぁAPI作ってるんですけれどもとあるAPI
アプリってウェブアプリですか そうですね ウェブアプリ作っててまあAPIで基本的にAWS使って作ってるんですね
僕はそのバックエンド作っていて処理時間が異常に長い APIっていうのを作っちゃったんですよ
というのもデータを収集してそれを圧縮してそれを返すっていうものなんですね だからS3においてある大量のデータを圧縮してダウンロード可能な状態に
するっていう機能を作ったんですよ 大量においてあるデータって何個あるかわかんないじゃないですか
最初作ってたタイミングだとまあこんぐらいっしょって思ってまあ数キロバイトのものをいくつか置いて圧縮っていう処理でかませてたんですね
データってちなみになんかどういう 何でもありです
画像だったりもするし動画だったりもするし文字だったりもするしそれらが混ざってるかもしれないみたいな
それを圧縮しようとなるとある日使ってるユーザーが 数百メガのデータを圧縮処理かけたんですね
そうなると何秒で終わるかわかんないんですね ラムダをAPIゲートで使って叩いてそのラムダの中で圧縮処理っていうのをやってたんですよ
APIゲートへの最大許容時間というか待ち時間が29秒だったんですね
そうなんですね
30秒以上かかるような処理はAPIゲートへ返せなくなってエラーで落ちちゃうんですよ
今それを絶賛直してるところなんですね
これどうやってアプローチしようかなっていうのをずっと考えてて
進捗状況の伝え方
やりようがあるとしたらラムダをバッチ化してまずAPIゲートへはそのラムダを圧縮処理っていうのを受け付けましたっていうのをもとに
まず一旦データを返却しちゃう 30秒以内で絶対データが返ってくるっていう風にして
裏側で圧縮処理を走らせるっていう風に変えようと思ってるんですね
それをクライアント側はじゃあどうやって監視し続けようかなっていうことで今ちょっと困ってるんですよ
なるほど
だからその膨大な時間がかかる処理っていうのをいつ終わったかっていうのをちゃんと確認した上でユーザーに対して適切なレスポンスを返すっていう風にしたくて
ここのレスポンスの部分の設計がちょっと今うまくいってないっていう現状です
そうなんですね
考え得るアプローチとしてはラムダの状態っていうのをどっかで保持し続ける
例えばDynamoDBとかにラムダが今何してるよっていう状態を持たせておくと
圧縮処理が何パーセント終わってますっていうのをDynamoDBに置いておいて
そのDynamoDBの状態っていうのを監視し続ける別のAPIっていうのを作って
今圧縮処理終わってないよ終わってないよ終わってないよ終わったよっていうタイミングで
クライアント側に適切なレスポンスを返すっていう風にしようかなって思ったりとか
DynamoDBはめんどくさいんでそこを他の管理方法としてS3にログを吐き出すだけにしようかとか
そもそもクラウドウォッチのログをクライアント側から監視しに行こうかとか色々考えてるんですね
何がいいかなって思って
なるほど
前提として僕そこら辺そんなに強いところじゃないんで
あんまりベストプラクティスわかってますっていうよりは壁打ち程度の話なんですけど
あとちょっとどこまでちゃんとした作りにするかみたいな
とりあえず楽に実装するかもうちょい堅牢な作りにするかとか
そこら辺によっても変わってくるなとは思うんですけど
考えなきゃいけないこととして2つの方向性があると思っていて
1個がデータの処理状態をどうやってデータとして持つかみたいな話
例えば圧縮処理を開始しますっていうのを開始が終わったよ終わってないだけなのか
何パーセントみたいな感じののをどっかに出すかみたいな話
とか残り処理時間みたいなのを出すかみたいな
そういうのをどうやってサーバーサイドとしてデータに持たせるかって話が1つ
ともう1個はそのリアルタイム状況をどうやってクライアントに伝えるかって話の2つの方向性があって
ユーザー体験の改善
まあ後者に関しては結構僕は分かるっていうか別に普通のことやればいいかなって思ってるんですけど
前者の話として要件としては進捗状況を伝える必要がないんですね
じゃあもう終わったか終わってないかだけでいい
今それで進めちゃってるんですけれどもやっぱ気持ち悪いんですよ
ユーザー体験として
そもそもエラーで落ちたのかどうかってのが分かりにくいじゃないですか
この処理本当に前に進んでるのってのが見えないんで
例えばそれこそ何百メガっていうデータを圧縮するのって絶対1分2分以上かかるじゃないですか
なるほどはい
だからあれこれ死んでねってことでリロードかけちゃう痛くなるタイミングが出たりとか
がユーザーとしてあると思うんでそこはせめて何かしらの進捗は出したいんですよ
だからそこの進捗を見せつつ
進捗とエラーが分かるってまたちょっと違う話じゃないですか
そうですねエラーも今見とれないつかめないんですよ
エラーがつかめるっていうのは多分できると思うんですけど今から作ろうとしてる部分がいくと
進捗なんですよね問題は
であのgoogleドライブをフォルダごとダウンロードするときも別に進捗見えないんですよ
だから結構難しいことやらなきゃいけないのかなと思ってて
いい方法ないかなって
そもそもそんな膨大なデータをダウンロードするなよって話もあるかもしれない
進捗どうやって分かるんですかねそれはちょっとよく分かんないですね
一応調べたんですけど圧縮処理に対する進捗を監視し続けるような
Pythonのモジュールは存在しなくて
監視はちょっとまた別の話じゃないですかねどうやって進捗状態を分かるかっていう話ですよね
少なくともそのPython側でも今圧縮処理が何をしてるかっていうのは見えないんですよ
生きてるか死んでるかの情報しか渡せなくてちょっと困ったなっていう
生きてるか死んでるかが分かればまあいいってこと最低限いいってことですよね
何パーセントか分かんなくても
クライアント側のステータス検知について
要件的には今やってますで落ちたっていうのを伝える仕組みはあった方が望ましい
プログレスバー的なのはいらない
はいはいはいじゃあそのステータスだけはDynamoDBか分かんないですけど
どっかにDBとしてステータス持っておけばいいんじゃないですかね
でエクセプション発生したらまあなんか普通に以上終了ということで
なるほどダイナモ立てるほどの話なのかな
それかまあそれを適当にやるんだったら目的地のなんかディレクトリあるじゃないですか
そこに以上終了の場合はなんか
置く
そこになんか以上ですの置くそれは本当に適当に作るパターンのやつですけどね
それならすぐできますわ今その以上終了って部分だけできてないんですよ
ああそうなんですね
だから死んだってことか絶対にクライアント側が分かんない状態になっちゃってるんで
その作業ディレクトリに対して新しい空テキストファイルみたいなのをポンって置いて
クライアント側はそこのディレクトリ内に今何のデータが入ってるっていうのを操作して
エラーって書いてあるテキストファイルが置いてあるよっていうのことを見たらエラーとする
まあそこはクライアント側ってよりはAPI側の責務かなっていうのは思うんですけど
まあそこら辺であの後者の話に移ってきて
リアルタイム通信の実現方法について
クライアント側から見てステータス変わったってことをどうやって検知しようかっていう
なんかそこの選択肢の話になってくると思っていて
まあやっぱりある程度クライアント側がずっとそのページを表示しっぱなしでも
終わったら終わったよっていうのが分かってほしいみたいな話ですよね多分
それはあれですが5秒に1回API叩くっていうのをクライアントにやらせるっていうのは微妙ですかね
まあぶっちゃけそれでいいと思ってます
本当にそこはリアルタイム性によると思っていて
これがチャットみたいな話だと5秒に1回じゃちょっとなんか5秒叩かないとこないのしんどいよとかあるんですけど
まあそういう系だったら5秒に1回とかなんならもうちょいなんか大きくてもいいんじゃないって思ったりしますね
かつそれが一番簡単かなとは思います
一応リアルタイムみたいな話だとなんですかねそれこそグラフQLとかGRPCとか
WebSocketとかなんかサーバーセントプッシュでしたっけ
まあなんかそこら辺のなんか選択肢が結構たくさんあると思うんですけど
正直ボーリングでいいんじゃないAPI Gateway既にあってかつそんなになんか頑張るつもりのないサービスだったら
基本的にリロードしないと何も新しいものが更新されないっていう状態なんで
だからレッドマインみたいな状態になっちゃってるんですよ
あれいけてないじゃないですか
まあそうですね
ノーションとかやっぱ一番使ってて気持ちいいと思っていて
それこそもう複数のメンバーが同時に作業してもバッティングしないでリアルタイムにレーダーが書き換わるっていうのって
やっぱ今風のWebシステムって感じがして作れるの羨ましいなって思うんですよね
でもあれそういう仕組みを実現させてるエンジニアっていうか職種っていうのはプロント側の人たちなんですか
それとも全体を通してそういう設計にした上で作り込まないといけないっていうものなんですかね
全体を通してだと思いますけどどっちかというとサーバーサイトじゃないですか
まあ両方あると思いますけど
クライアント側は一体何をしてるんですかサーバー戦闘イベントの時って
まあ普通にAPIリクエストしてるのと一緒ですよ
常に口を開いてるみたいな状態になってる
リアルタイム通信のプロトコルについて
ブラウザー側とサーバー側のプロトコルの仕様みたいな話なんで
Httpリクエストはどのようにパケットの更新をしてるかみたいな話なんで
そういうのはちょっと僕あんまり詳しくないです
まあ今のレベルで言うとポーリングで全然問題ないかなって5秒に1回10秒に1回
技術的に試してみたいんだったらなんかちょっとそういうリアルタイム通信の仕組みとか
相互通信みたいなサーバー側からのプッシュどうするのみたいな
なんかそういうのを調べてみてもいいかもしれないですけどね
なんかユーザーが使ってて気持ちいい風には近づけたいなって思うから
まあ予算との関係もあるけど
そうですねまあ単純に要件の実現で言うと
ポーリングでもう今は十分すぎる感じ
だけどそれ以上に試してみたいんだったらなんかいろいろ選択肢あるんで
あとどれがベストかっていうのは
AWS使ってるんだったらなんかAWSにそういうのないですかみたいな
確かにAWSのサーバーセントイベントっていうかリアルタイム系の通信の仕組み
ちょっと調べる価値ありそうですね
AppSyncとかなるんですかね
AppSyncってGraphQL系でしたっけ
GraphQLの導入について
そうですね最初からGraphQLだったらそれが一番いいと思うんですけど
もうそれの単体だけにAppSync入れるかどうかっていうのは正直あんまりよくわかってないです
ちなみにこれ2年前から作ってるシステムなんで
このREST APIとMySQL使って作ってるやつだから
いきなりGraphQLに行こうとかってしんどいやつですね
なんか理由があるんだったらいいですけどね
予算が落ちないですねまず
GraphQLなんで入らないのかみたいな話
この前ちょっと見たんですけど
適当なブログかなんか
僕GraphQL使ったことないんですよ
僕もないです
チュートリアルぐらいならあるけど本格的に使ったってことはないですね
そうですねやっぱGraphQL使う時ってなんで使うかっていうと
BFFが必要な時みたいな話で
なんすかBFF
Background for Frontend
だからなんていうかGraphQL多分使われる一般的なユースケースって
RESTful APIあるじゃないですか
でこのAPIがありますそのAPI叩いてこれ返ってきますみたいな
ででもフロント側の用件ってコロコロ買うじゃないですか
いやこれも欲しいこれも欲しいこういうページが欲しいみたいな
なった時に一個のページになった時に
このAPIもこのAPIもこのAPIも叩くとか
このAPI叩くけどほとんどデータ使わないのにそのせいで処理が遅いとか
ここの開発ライフサイクルが結構なんか違って
もっとこっちを早くしたいのに間に合わないみたいなことがあるんですね
だからフロントエンドがバックグラウンド
バックエンドの開発完了待たずになんかほいほい
フロントエンド用に取ってくるデータをカスタマイズしたいっていう場合に
結構便利なのがグラフQLだと思うんですよ
だからそういう用件の場合に必要なものであって
フロントエンドとバックエンドがそもそも一つのチームとか
それぐらいに規模が小さい開発だったりとかすると
別に必要ないみたいな話だったりして
で結構僕らがやってるのはそのぐらい小さいのを
なんかポンポン開発するみたいな系だから
あんまり必要ないのかなっていう
あと普通に学習コストが高くていざ導入ってやりづらいですよね
やらなきゃいけないんだろうけど
結構webだとわかんないですけど
GRPCのプロトコルについて
僕の観測範囲だとGRPC結構流行り始めてるっていうか
なんでじゃっけGRPC
GRPCは言葉の定義としてはなんかRPCっていうリモートプロシージャーコール
普通関数呼び出しってするじゃないですか
関数呼び出しなんですけどリモートプロシージャーコールは
関数呼び出しだけど実体それがリモート
関数呼び出しをする感じで実は中身それ通信してるみたいな
YAMLが作ったリモートで関数呼び出しするためのプロトコル
プロトコルっていうのか
オープンAPI使ってますか
使ってますよ
SUAGAのYAMLみたいの書いてそこからコード生成して
でクライアント側とかはその関数を叩いたら
実際そのリクエストみたいな感じじゃないですか
なんかあれと同じような感じなんですよ
GRPCっていうのはJSONスキマじゃなくて
なんていうんだっけあれ
プロトコルバッファーだ
YAMLみたいなものを書くんですよ
要はAPIの定義をするんですね
それとかデータモデルの定義をして
でそこからコードを生成されるんですね
である意味本当に同じなんですけど
オープンAPIの自動生成と一緒ですか
オープンAPIの自動生成と一緒ですか
そうですねある意味一緒ですね
そういうのがサーバーサイド側とフロントエンド側で
両方ともコードができて
多分開発体験としてはオープンAPIとほぼ変わんないと
ような気がしますね
ただ違うのが結構どうなんだろうな
型がある程度ちゃんとしてるっていうのと
中身でバイナリで通信してるみたいな話で
HTTP2の仕組みを使って通信することで
早いみたいなんですね
普通のHTTPリクエストよりは
つまりRESTfulの呼び出しよりは早いみたいなんですよ
っていうので使われてるんですけど
HTTP2が必須になるんで
ウェブだとなんか基本的に普通には使えなくて
ここまで来るとあれです
設計全体を考えないといけなくなってくる
だから全然今やるみたいな話じゃないですね
今後同じようなパターンがあるんだったら
GRPCとか使ってみても面白いかもしれないですね
今一番やりたいのは普通に
GraphQLとDynamoDB
AppSyncとDynamoDB使って
リアルタイム系の新規のサービスを作って
実はまだDynamoDBもうまく使えた試しがないんで
確かにDynamoは僕も分かんないですね
NoSQL系どうDB設計すればいいんだろうみたいな
カオスですよね
ずっとDynamoDBの
NoSQLの設計の仕方みたいな
技術ブログを書く
AWSのドキュメントみたいなのをずっとブックマークはして
いつか読まなきゃと思って
もう多分3年ぐらい経ってますね
いつか読むやつ
今回の結論としては
とりあえずもう予算もそんなにないんで
エラーハンドリングは
状態管理はお茶を濁す感じで
テキストファイルでやります
大した情報じゃないんで
その上でクライアントからの
状態チェックっていうのは
ポーリングでやるっていうので
結論が出ましたね
一番安くやるスタイルになっちゃって
あんまり挑戦的じゃないけど
これでいきましょう
APIの使い方をちょっと非同期にするみたいなのは
もしかしたら新しい挑戦なのか
確かに
分かんないけど
よしじゃあ問題解決しました
月曜からこれで実装進めたいと思います
皆さんよく眠れましたか
(エンディング)
15:44

コメント

スクロール