【インターン体験記】ミラティブでのエンジニア体験を通して得られた失敗と成長
はじめまして!
2023年5月〜6月の2ヶ月間、ミラティブで就業型インターンシップに参加させていただいていましたbe3(@Blossomrail)です。
本記事では、ミラティブでの私の2ヶ月間の経験をお伝えしたいと思います。就活中でミラティブのインターンを検討している方の参考になれば幸いです。
自己紹介
現在は同志社大学大学院に修士2年として在籍しています。
学部4年頃からWebのバックエンド開発を趣味で始め、24卒としてWebのバックエンド開発ができる企業、職種を探していました。参考までにプログラミング歴もお伝えしておくと、プログラミング自体は大学に入学してから授業で初めて学びました。
私がミラティブのインターンシップに応募した理由は、以下です。
ライブゲーミングの開発に興味があるため
Go言語を用いたバックエンド開発に興味があるため
ミラティブのミッションとバリューに共感したため
インターンシップで取り組んだ内容
初めの週は、環境構築をしつつメンターの方とタスクの方向性を模索しました。私のタスクの希望としては、以下の内容を洗い出しました。
実装仕様から決められる
Go言語を書きたい
ミドルウェアの理解を深めたい
実サービスに影響がある
メンターさんに用意していただいた様々な候補タスクのうち、担当するタスクを上記の要件を満たしていると感じて、インターンシップ中には以下2つのタスクに取り組みました。
重複するSlack通知を解消する
ライブゲームにAPI Rate Limitを実装する
「重複するSlack通知を解消する」タスクは、正常でないデータが運用の中で確認された場合に、botによるSlack通知が1日に2回以上実行されてしまうという不具合を解消したものです。
こちらの不具合には、キャッシュに次回の実行可能日時を記録しておくことで、1日の実行回数を必ず1回までに抑えるという対処をしました。
以降では、私がインターン中に最も注力した「ライブゲームにAPI Rate Limitを実装する」タスクを中心にお話したいと思います。
タスクの内容
ここからは具体的なタスクの内容をお話したいと思います。まず、一般的にAPI Rate Limitとは、一定時間内におけるAPIへのリクエスト回数の制限やその仕組みを指します。
Mirrativには、一般的なゲームとは違った、ライブ配信中に視聴者が配信者のゲームプレイに介入できるライブゲームがあります。
以下の写真は、エモモ・バトルドロップというライブゲームの画面です。このように、ライブゲームをプレイする配信者は、視聴者と一緒にゲームを楽しむことができます。
そして、Mirrativでは以下のようなシーケンス図で、ライブゲームを開発している外部パートナー企業さまに対してAPIを提供しています。ライブゲームを利用する際の処理は、次のような一連の流れになります。
まず、ユーザーはMirrativアプリ内でライブゲームを選択し起動します。
次に、起動したライブゲームはライブゲームサーバーにリクエストを送ることで、ライブゲームの機能を呼び出します。
そして、ライブゲームサーバーはMirrativサーバーにリクエストを送ることで、ライブ配信の機能を呼び出します。
最後に、Mirrativサーバーからのレスポンスを受け取って処理を完了したライブゲームサーバーは、ライブゲームに対してレスポンスを送ります。
今回のタスクでは、以下に示す箇所に一定時間内におけるリクエスト回数の制限を設けることがゴールです。
本タスクの目的は、一部ユーザーのリクエスト数の増大によってサーバーやデータベースへの負荷が急上昇することで、サービスの停止や遅延などといったMirrativユーザー全体に対する悪影響を防ぐことです。
タスクの進行
上記のタスクを進めるにあたって、2ヶ月間(週3勤務なので24営業日)で以下のような順番でサブタスクに取り組んでいきました。
機能要件の整理(5/15〜)
リクエスト数の調査(5/18〜)
実装仕様の検討(6/1〜)
MirrativサーバーでTimespanコマンドを使えるように実装(6/9〜)
調査と仕様検討の結果をドキュメント化(6/16〜)
リクエスト状況を分析するツールをredash上に作成(6/23〜)
サブタスクの内容を見ると分かるかもしれませんが、インターン期間中にAPI Rate Limitの実装にまで到達することはできませんでした...。orz
厳密には、実装仕様を作成するための情報(上記の2と3)をまとめるところまでを進めました。そして、工数的に残りの営業日でAPI Rate Limitの実装が終わらないと判断して、リクエスト数の調査の際に作成した分析クエリを改良して、定期的にリクエスト状況を見るためのツールを作成しチームに共有することに工数を割く形となりました。
悔しい結果となりましたが、なぜ期間内に終えられなかったのかについては「Mirrativでのエンジニア体験、そして失敗と気付き」の章で振り返りたいと思います。
実装に向けた調査と検討
API Rate Limitの実装を行う上で、以下のような検討をする必要がありました。
Rate Limitにはどういった閾値を設けるか
APIアクセス数の集計に適したデータストアは何か
どんなアルゴリズムでRate Limitを設定するか
データストアにどれだけの負荷がかかるのか
●リクエスト数の調査
まずは、Rate Limitの閾値を決めるための情報収集として、各種APIに対するリクエスト数を調査しました。
具体的には、ライブゲームAPIへのアクセスログを格納しているBigQueryに対してSQLを実行して、月間のリクエスト数における最小値、中央値、最大値を出したり、アクセス頻度が高いAPIなどを調査をしました。
●リクエスト数を記録・集計する仕組み作り
次に、Rate Limitに到達したかどうかを判断するためのリクエスト数のカウント方法について検討しました。ミラティブではradisha(ラディシャ)というRedis互換のサーバーをデータストアとして運用しています。
radishaは、KeyValueやHashといったRedisが持つ機能以外に、独自の機能をいくつか持っています。今回はその独自の機能の中から、期間内におけるカウント数の集計に特化した、Timespanと呼ばれる機能をAPI Rate Limitの実装に利用できないか検討しました。
Timespanは、RedisのHashと同様のデータ構造を持っていますが、Setできる値は1以上の整数だけとなっており、期間内の集計を行うことを目的とした機能です。
具体的なTimespanの使用方法について説明します。
{KEY} {FIELD} {TTL} {VALUE}を指定して一定時間だけ数値を溜めるTSSETEXコマンドと、{KEY} {FIELD}を指定して溜めた数値の集計を取得するTSGETコマンドを使うことで、以下のようにしてリクエスト数を記録&集計することができます。
また、KEYにAPIのPathとライブゲームIDを組み合わせた文字列を、FIELDにユーザーIDを指定することで、エンドポイントとライブゲームとユーザーの組み合わせ別にリクエスト数を管理できます。
# e.g. 10秒に1回リクエストがある場合
127.0.0.1:6379> TSSETEX APIPath01-LiveGameID01 UserID01 60 1
OK
127.0.0.1:6379> TSSETEX APIPath01-LiveGameID01 UserID01 60 1
OK
127.0.0.1:6379> TSSETEX APIPath01-LiveGameID01 UserID01 60 1
OK
127.0.0.1:6379> TSSETEX APIPath01-LiveGameID01 UserID01 60 1
OK
127.0.0.1:6379> TSSETEX APIPath01-LiveGameID01 UserID01 60 1
OK
127.0.0.1:6379> TSSETEX APIPath01-LiveGameID01 UserID01 60 1
OK
# この瞬間での集計結果
127.0.0.1:6379> TSGET APIPath01-LiveGameID01 UserID01
(integer) 6
# 10秒後に取得すると、最初に送った 1 のTTLが切れて 5 が返る
127.0.0.1:6379> TSGET APIPath01-LiveGameID01 UserID01
(integer) 5
以上のような集計の仕組みをライブゲームAPIサーバーに適用します。
リクエスト処理時にリクエスト数が最大リクエスト数を超えれば、エラーを返し、越えなければリクエスト数を加算します。
●インフラチームとの実装仕様の検討
そして、調査や実装仕様案を終えた段階で、データストアとしてradishaが使えないかインフラチームの方に相談しました。その結果、radishaを利用する懸念点として、大きく以下の2点が指摘されました。
radishaサーバーのレコード数が大きくなりすぎて、パフォーマンスに問題が出ないか?
radishaサーバーへのTSSETEXリクエストが高頻度すぎないか?
相談の結果、一つの方針として、「ライブゲームAPIサーバー側で一定時間だけリクエスト集計を溜めた(バッファリングした)上で、radishaに対してリクエストをする」という方針が固まりました。
そして、インフラチームの方にベンチマークをしてもらった結果、ライブゲームAPIサーバーへのリクエストの度にradishaにTSコマンドを実行してしまうと、アクセス頻度の多さからradishaへの負荷が高まり、radishaのレイテンシーが増大してしまう傾向が見られました。
また、Timespanはレコードを追記しつつGet時に集計するというデータ構造を取っているため、単位時間あたりのリクエストが極端に多い場合にレコードが増えすぎてしまいます。
上記のような状況が発生すると、リクエストがタイムアウトしてしまう可能性が高くなり、ユーザーがライブゲームを利用できない状況が発生してしまいます。そのような状況をリクエスト数を調整して回避するよう、バッファリングを第一に検討するという結論になりました。
私がAPI Rate Limitの実装に向けて取り組めた内容はここまでで、以上の内容を今後社員さんが実装する際の助けになるよう、社内ドキュメントを作成しました。
ミラティブでのエンジニア体験、そして失敗と気付き
サービスへの影響度が高い、責任感のあるエンジニアリング体験
API Rate Limitを実装するタスクは、事業に直結する責任感のあるタスクだったと感じています。API Rate Limitは、ライブゲームを利用するユーザーの目には見えない仕様であるものの、サービスを安定して稼働させるための仕様です。
API Rate Limitがきちんと機能すれば、一部のユーザーやライブゲーム会社による膨大なリクエストが発生したとしても、大多数のユーザーにとってのユーザー体験を良くないものにしてしまう状況を未然に防ぐことができます。
また一方で、適切な設計や許容リクエスト数を決められないと、正常な量のリクエストを受けているにも関わらずリクエストに制限をかけるような仕組みになってしまい、ユーザー体験を悪くしてしまう可能性もあります。
以上のようなサービスへの影響度が高いタスクをいただけたことは、メンターさんを初めとした社員さんからの手厚いサポートがあったお陰であり、タスクを進める上で必要な相談や手解きの時間を多く頂きました。
ユーザーにとっての価値を考えるエンジニアリング体験
今回のタスクを通して、メンターであるバックエンドエンジニアのshirakawaさんやインフラエンジニアのkondoさんから沢山のお時間をいただいて、リクエスト数調査の方向性やAPI Rate Limitの仕様、radishaの利用方法、インフラへの負荷などについて相談させていただきました。
仕様を決める中で様々な選択肢が出てきて決断に悩むことがよくありましたが、焦点が当たることはいつも「それはユーザーにとって有益か?不利益にならないか?」という問いでした。
そして、社員さんに相談をさせてもらう度に、私はこの問いに立ち返って考える力がまだまだ足りていないことを痛感しました。また、この問いに対する社員さんの答えは、自分よりもずっと解像度が高いことも実感しました。
その違いの要因は、エンジニアとしてのスキルや経験が自分よりもずっと高いことはもちろんですが、それ以外にもMirrativというサービスへの理解度に差があることの方が大きいのではないかと思いました。
それからは、Mirrativのアプリを立ち上げてみて、処理のシーケンスをイメージしながら実際にライブゲームを遊んでみることが増えました。そうすると、これまでよりもタスクとサービスの繋がりが見えやすくなり、ユーザーにとっての価値を想像する癖がついたり、社員さんへ相談をする際に言語化がしやすくなるといった成長を感じることができました。
なぜ2ヶ月以内に終わらなかったのか?
API Rate Limit実装を2ヶ月以内に完結できなかったことについて振り返った結果、以下の3点が原因であると考えました。
リクエスト数の調査に時間をかけすぎた点
相談や協力を上手く仰げなかった点
工数管理に対する意識が足りていなかった点
1番の原因は、リクエスト数の調査に時間をかけすぎてしまったことだと考えています。
ライブゲームの処理がどんなシーケンスになるのか、どんなAPI Rate Limitにするのか、が自分の中で曖昧な状態のままリクエスト数を調べようとしたために、リクエスト数の調査をするためにどんなSQLを実行すれば良いのかが浮かばず右往左往してしまいました。
2点目は、行き詰まった時に1人で時間をかけて悩みすぎてしまったことです。
エンジニアに限らず大事なことになると思いますが、自分がどんな状況にいて何が分からないか、相手に何を求めているかを明確にした上で、チームメンバーに相談や協力をお願いすることが大事だと痛感しました...。
インターン序盤の時期に、悩み続けた結果、1日の終わりにメンターさんとの1on1でやっと悩みが解消されるといったことを繰り返してしまったため、タスクの進行スケジュールが逼迫してしまったのだと思います。
3つ目は、工数管理に対する意識の足りなさも間接的な原因だったと思います。
インターン中の総工数、タスクの細分化、今取り組んでいるタスクの工数見積もり、工数見積もりに応じて決まるスケジュール感などを詳細に考えずにタスクを進めていたことで、インターン序盤の週はタスク進行がかなり遅れていることを自覚できていませんでした。
工数管理に対する意識がもっとあれば、進行度を早めるための工夫を早い段階で行えていたと思います。
以上が振り返りです。初歩的な話で恐縮ですが、この内容が見習いエンジニアやエンジニア志望の学生の方の参考になれば幸いです。
社内のエンジニア勉強会に参加してみて
どんな勉強会だったか
インターン期間中は、タスクの遂行と別に社内のエンジニア勉強会に参加させていただいていました。
私が参加した勉強会では、「Googleのソフトウェアエンジニアリング」という書籍を輪読していました。この書籍では、ソフトウェアエンジニアリングにおける文化やプロセスに対するGoogle社内のベストプラクティスが綴られています。
この書籍に興味があるのはもちろんのこと、ミラティブのエンジニアの方々がどういった形で勉強会をされているのかに興味があり、勉強会に参加させていただきました。
実際に参加してみたところ、書籍で論じられていることでMirrativにも活かせる部分はあるか、Mirrativにも共通する問題はないかといった会話が勉強会の中でされており、知見を吸収するだけでなく知見を組織にどう活かすかを考える時間にもなっていたことが分かりました。
実践できたこと
書籍の内容のうちインターン中に実践しやすかった章は、第3章「知識共有」でした。本章と本章を読んで実践できたことについていくつかお話したいと思います。
まずは、「初心者のする間違いの中で最大のものは、行き詰まったときに助けを求めないことである」という内容です。インターンの振り返りでも話しましたが、インターン序盤は結構これをしてしまっていたと思います...。
本章を読んでいて、この行為が工数の浪費に繋がってしまっている可能性があると気付いてからは、行き詰まったと感じたらメンターさんに何度も壁打ちをさせてもらい、タスクが停滞するのを防ぐことができたと思います。
次が、「ドキュメントを書くことで、自分が進んだ道を他者が簡単に続けるようになる」という内容です。インターン期間中にAPI Rate Limitの実装まで進むことは叶いませんでしたが、実装に向けて調査・検討した内容をドキュメントとしてまとめる必要がありました。
自分で手掛けることが出来ず悔しい思いをしましたが、これまで時間をかけて整理した内容が後任の方の工数を削減する情報源になると思うと、自分が取り組んだ内容を少し誇らしく思えるようになりました。
そのため、インターン終了後でも後任の方が円滑に文脈を得て実装に進められるように、正確かつ簡潔に社内ドキュメントとして記しました。
おわりに
以上が私のミラティブでのエンジニア体験になります!
ユーザーのためになる仕組み作りに携われただけでなく、自身の未熟な部分に気付く機会も得られた有意義なインターン生活を過ごすことができました。
本記事を通して、少しでもミラティブやミラティブのインターンに興味を持っていただけると幸いです。
ミラティブでは、現在インターンを募集しています!気になった方はぜひ応募してみてください!