2024.10.10
将来は卵1パックの価格が2倍に? 多くの日本人が知らない世界の新潮流、「動物福祉」とは
リンクをコピー
記事をブックマーク
江頭宏亮氏(以下、江頭):次に、オリジンのYatagarasuへのリクエストを具体的にどのようにやっているのか、説明したいと思います。
先ほど見せたスクリーンショットだと、右側にモジュールが3つ並んでいたと思いますが、実際は縦スクロールでもっと大量のモジュールが表示されているので、一度のリクエストで複数のモジュールをハンドリングする必要があります。なので、FetchModulesの関数の引数にidsが複数来るようになっていて、ここにもモジュールのIDみたいなものが入ってくるかたちになっています。
今回、万が一、Yatagarasuの仕組みが高負荷状態になってスローダウンすることがあってもきちんと動くように、まずタイムアウトの設定を入れています。これを書かないと、万が一Yatagarasuの本体のサービスがスローダウンしたケースにgoroutineが滞留し、OOMになることが想定できたので、ここでタイムアウトをきちんと設定しています。
そして、複数のモジュールで並列に取りに行くためにgoroutineを作成して、一つずつ取りに行って、最終的にWaitGroupで待つということをやっています。取れたあとにインメモリとRedis、それぞれにキャッシュするという処理になっています。
また、万が一キャッシュがなくなった時に、オリジンに行くリクエストが集中する、キャッシュスタンピード問題を防ぐために、singleflightというパッケージを活用しています。
このsingleflightというパッケージは、同時に関数を呼び出すことを抑制できます。なので、キャッシュが切れたタイミングでオリジンにむちゃくちゃリクエストが行くというケースが発生したとしても、それを1つにまとめてくれるので、1つのリクエストしか飛ばないということが実現できます。
(スライドを示して)ちょっと見にくいかもしれませんが、singleflight.Doというのがその具体的な関数になっていて、そのDoの関数の第1引数には、リクエストを識別するキー、文字列を指定します。第2引数に具体的な処理、関数を渡します。
そしてDoの返り値は3つあります。module、errorというところに具体的な処理の返り値がそのまま来て、具体的に処理がまとめられたケースの場合、sharedにtrueとかが返ってきます。
なので、このサンプルのケースだと、処理が返ってきた返り値でsharedがtrueだった場合、functionは共有された、リクエストはまとめられたよということ。そのあとに通常どおりエラーのチェックをして、このDoの返り値はinterface{}、anyになるので、最終的にキャストする。こういう処理を入れています。
江頭:最後にまとめになるのですが、レコメンドシステムへのリクエストを削減するために今回Goでプロキシを開発しました。もともとインメモリのキャッシュだけを検討していましたが、よりオリジンへのリクエストを減らすために、インメモリのLRUとRedisの2層構造を採用しました。
また、キャッシュが切れた時にオリジンへのリクエストが集中して複数回飛ぶのを防ぐために、singleflightパッケージを活用してオリジンへの同一リクエストを抑制しています。
結果、時間帯にもよりますが、オリジンへのリクエストは90パーセントぐらい削減でき、これによって10分の1ぐらいのインフラリソースで捌けるようになったので、インフラコストの最適化を実現できました。
以上です。ご清聴ありがとうございました。
(会場拍手)
司会者:江頭さん、発表をありがとうございました。Slidoでけっこういっぱい質問が来ているので、順々に聞いていきたいと思います。
1個目が「特徴量が多いと、キャッシュキーの空間が広くなってヒット率が下がってしまうのではないか?」という質問です。そのヒット率を上げるためになにか工夫はしていますか?
江頭:そうですね……。ものによっては、ほとんどキャッシュがヒットしないものもありますが、レコメンドチームとけっこう連携して特徴量を最小限にするとか、そういう取り組みは最初にしました。
司会者:じゃあ、けっこう別のチームと密接に事前に打ち合わせをして設計して作った感じなんですかね。
江頭:そうですね。
司会者:なるほど。ありがとうございます。
司会者:ちょっといっぱい(質問が)来ているので、どんどんいこうと思います。「先ほど前段でご紹介されていたように、Goのプロキシサーバーをスクラッチで開発されたと思いますが、スクラッチだからこそ出せたバリューって何ですか?」という質問があります。
江頭:たぶん標準のリバースプロキシみたいなものは、パッケージに実装されていると思いますが、それがちょっと使えなかったという背景があるので、型変換みたいなことをやって、独自の処理をいろいろ実装できる点がメリットですかね。
司会者:やはりABEMAゆえにけっこう独特な処理も多いのかなと思うのですが、そういったところで使っている、バリューが出せたという感じですかね。ありがとうございます。
司会者:けっこう似たような質問もいろいろ来ているのですが、やはりGoといえば、先ほどもおっしゃっていただいたとおり、並行処理があると思います。それを使う箇所、使わない箇所。けっこう「サーバーサイドのアプリでgoroutineを使うべきなのか?」という論争もよくあるのですが、「ここはgoroutineで処理しよう」みたいな判断は何を基準にされたんですか?
江頭:基本的には、I/O waitが発生するような処理は、goroutineにしています。
司会者:なるほど。ということは、I/O waitを待っている間にgoroutineで非同期でなにか別の処理をしておいて、その間にCPUの時間を有効活用したい。そのために導入した、みたいな?
江頭:そうですね。
司会者:もし出せたらでいいんですけど、なにか具体的な実装箇所を思いついたりしますか? ちょっと言えなかったら大丈夫ですが。
江頭:今使っているところとか、あとは、うーん……。例えば1個メッチャ重い処理があったとして、ユーザーのレスポンスには影響を及ぼしたくないし、失敗してもユーザーに返さなくていいという処理とかは、普通のAPIの実装でも入っていたりします。
司会者:そうなんですね。
江頭:なんかサブ処理というか。
司会者:なるほど、ありがとうございます。
司会者:(質問を見て)これ、いいですね。かなり「いいね」もついています。「goroutineで非同期処理が多そうでしたが、テストコードとかを書くのはやはり非同期だとけっこう難しいんじゃないかなと思います。そこらへんはどうですか?」
江頭:そうですね。基本的にはgomockを使ってモック化して書いていて、今回のようなケースだとそれでいけています。もうちょっと複雑なものもあったりして、フレイキーテストとかになっちゃうこともあるのですが、でもだいたいはgomockとかを使ってうまい感じに書けていますね。
司会者:けっこうそれでカバレッジとかもきちんと出せて、プロダクション……。
江頭:そうですね。
司会者:なるほど。ありがとうございます。
司会者:次に来ているのが、これはキャッシュのお話ですね。「LRUとTTLの両方が必要な理由って何なんでしょうか?」。補足として、「LRUがあればTTLはいらないんじゃないか?」というコメントが来ています。
江頭:ABEMAの場合、リニア配信がある都合上、最新コンテンツを推したいケースや、刻一刻と見られるコンテンツ・見られないコンテンツが変わっていくので、けっこうデータの鮮度が重要です。LRUとかでキャッシュしてしまうと、いつそのキャッシュが切れるかのハンドリングがしにくくなるので、TTLも欲しかったという。
司会者:どっちも必要だったということですね。なるほど、ありがとうございます。
司会者:(質問を見て)これはいいですね。「ほかの言語ではなく、Goを採用する上で期待していたこと、そして実際にそのバリューは果たされたのかを教えてほしい」とのことですが、なにかGo特有の「ここがうれしかったな」みたいなポイントはあったりしますか?
江頭:2つあります。1つがやはり、先ほどのgo-redisとかじゃないですが、ライブラリがけっこう充実していること。特にサーバーや大規模アクセスに耐え得るようなライブラリが充実しているところと、あとはやはりgoroutineが強いなと思います。
具体的に、今回は最初Pythonで実装しようとしたのですが、ライブラリの選定から慣れていないので、メチャクチャ時間がかかってしまいました。やはりそういう時もGoはこういうのがメチャメチャ充実しているなと思いましたね。
司会者:なるほど、そうですね。
司会者:これは僕個人の質問ですが、やはりGoはチーム開発でも導入しやすいと思いますが、今のプロキシサーバーとかは何人で開発されたんですか?
江頭:これは2人です。
司会者:あ、2人か。少ない(笑)。
江頭:しかもこれは実際2日で作っています(笑)。
司会者:すごい、2日(笑)。けっこう突貫だった感じですかね。
江頭:そうです。まぁ背景がアレなので、突貫で作りました。
司会者:でも、それでもきちんとプロダクションに耐え得る運用もできるし、先ほど言ったとおり、テストコードとかもきちんと書いてリリースできた感じですかね。
江頭:そうですね。テストコードもきちんと書きました。
司会者:それはまぁ、もちろん本人のエンジニア力もあると思うんですけど(笑)、そういった中でもやはり書きやすさや導入しやすさでやりやすかったということですかね。ありがとうございます。
司会者:次に来ているのが、またキャッシュのお話です。「Yatagarasuを介するアクセスとキャッシュを利用する場合で、レイテンシの差はけっこう出てくるものなんでしょうか?」
江頭:けっこう出てきますね。
司会者:具体的な数値はたぶん言えないと思いますが、体感的にもけっこう出てくる?
江頭:エンドユーザーが感じるのはほぼないとは思いますが、インメモリキャッシュだと本当に1msecとか数msecで返せるので、もうレイテンシはめちゃくちゃスピードが違いますね。
司会者:ありがとうございます。100ミリ……1秒以上遅らせると、ユーザーは体感で「遅いな」と思うとよく言いますが、そこらへんもぜんぜんないキャッシュの速度で返せている感じですかね。
江頭:そうですね。
司会者:ありがとうございます。
司会者:本当に(質問が)いっぱい来ているのですが、次はライブラリのお話を拾います。「先ほど、gobを使っているというお話がありましたが、パフォーマンスイシューとかは開発中や運用中は特に見つからなかったですか?」
江頭:そうですね。gob以外もいろいろな方が作ったエンコーディングフォーマットやライブラリがあるのですが、たぶんデータサイズなどにも依存するので、どれがいいとか、どれが微妙とかを判断するのはけっこう難しくて。
先ほど短期間で作ったという背景も説明しましたが、とにかく短期間で作る必要があったという点で、パフォーマンスもそんなに悪くないし、シンプルなgobを使ったという感じですね。
司会者:なるほど。やはりGoを使う人たちは、すごくフルスタックなライブラリとか豪華なライブラリとかより、シンプルなライブラリを使う印象がありますよね。ほかのも使っている中で、ライブラリの選定理由はけっこうそこが多かったりしますか?
江頭:そうですね。あるかもしれないですね。
司会者:なるほど、ありがとうございます。
司会者:次が、「先ほど、RedisのRingクライアントを使っているという話がありましたが、選定理由はなにかありますか?」
江頭:そうですね。いろいろな背景がありますが、Google CloudのRedisだと基本的には、HA構成、スタンダード構成、1個メインがあったらリードレプリカが置ける構成、単純に1台だけある構成です。
今回、HA構成とかだとメインが落ちた時に若干ダウンタイムが発生してしまいます。そういったことも避けたいのですが、Redisクラスタの選択肢にGoogle Cloudがないので、使いやすいRingクライアントを採用した感じです。
司会者:はい。ありがとうございます。
司会者:だいぶ捌けてきたのですが、そうですね……これはちょっとベンチマークのお話ですね。インフラのほうじゃないのですが、「各関数のパフォーマンスのプロファイリングに関して、GoのBenchmark関数などを活用していますか?」
江頭:そうですね……。この機能では使いませんでしたが、たぶんこの次のセッションでは具体的に使っています。
司会者:なるほど。じゃあ次のセッションをお楽しみにしていただければと思います。
という感じで、あとはだいたい同じような……あ、じゃあちょっと最後に1個だけ、すみません、拾わせてください。「逆に、実際に運用してみてGoだからこそ感じたパフォーマンス面のデメリットはありましたか?」 特になかったですかね?
江頭:そうですね、特には。
司会者:特にはない。ありがとうございます。じゃあプロダクトでもガンガン高負荷を流せるよという感じ?
江頭:そうですね。
司会者:ありがとうございます。では、いったんここらへんで質問の時間は区切らせていただこうかなと思います。あらためて、江頭さん、発表をありがとうございました。
江頭:ありがとうございました。
(会場拍手)
関連タグ:
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.12
自分の人生にプラスに働く「イライラ」は才能 自分の強みや才能につながる“良いイライラ”を見分けるポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.11
気づいたら借金、倒産して身ぐるみを剥がされる経営者 起業に「立派な動機」を求められる恐ろしさ
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.12
先週まで元気だったのに、突然辞める「びっくり退職」 退職代行サービスの影響も?上司と部下の“すれ違い”が起きる原因
2024.11.14
よってたかってハイリスクのビジネスモデルに仕立て上げるステークホルダー 「社会的理由」が求められる時代の起業戦略