はじめに
こんにちは、京都大学工学部電気電子工学科 4 回生の武田和樹です。先日の 9/3~9/5 の 3 日間で開催された、短期ソフトウェアエンジニアリングコースのサマーインターンに参加させていただきました!サーバーサイド担当として参加して学んだ知見や、感想などを話していければと思います!
TL;DR
- 未曾有の大災害時に使える安否確認メッセージツール「Kizuna」を作り優勝しました!
- バックエンドとして参加し、初期状態の 0.07 req/s の処理能力から、約 10000 req/s まで捌けるように改善しました!
インターンに応募した経緯
DeNA のサマーインターンの存在は、私の学科の先輩であり現在 DeNA で働かれている@p1lass さんの インターン参加記ブログ で知りました。ブログを読んだ当時はあまりサーバーサイドのコードを書いた経験がなく、何をしているのか皆目見当もつきませんでしたがいつかこういうインターンに参加したい!と強く思っていました。
今年もインターンがオンライン開催ということもあり、せっかくの機会だということで応募したところ、なんとか合格をいただけて無事インターンに参加することができました。
インターンシップの課題
今年度の課題は、「東京湾に複数の巨大怪獣が出現」「東京の各地を急襲」「国内のサーバーがやられて通信不可能」という絶望的な状況下で、3 日間で既存のポンコツチャットアプリを改良して使えるようにしてね!というものでした。
それに加えて、想定される 10 万人同接と 10000 req/s に耐えられるようにしてほしいとのことで、本当にできるのだろうかと不安な気持ちでいっぱいでした。
またフロントエンドに関してもとても使えたような代物ではなく、わかりにくい UI やチャットチャンネルを表示するまでに 20 秒近くかかるなど改善点が山積していました。
チームでやったこと
チームはフロントエンド 2 人、バックエンド 3 人、社員メンター 2 人の 7 人チームでした。インターン期間は 3 日間しかないということで、初日はチャットアプリの方針を立てた上で、優先順位をつけて開発することを話し合いで決めました。 特に、方針については時間をかけて綿密に話し合い、「安否確認機能」「個人チャンネル」「一般チャンネル」など災害時に必要になるであろう必要かつ最低限の機能をつけることでまとまりました。 「個人チャンネル」はかつての駅の伝言板のように、自分の状況や簡単なメッセージを書き込めるチャンネルです。「一般チャンネル」は自治体などが避難所や食料配布などの有益情報を書き込めるチャンネルです。 安否に関する簡単なステータスについては「安否確認機能」で誰でも一目で閲覧できるように構想しました。
このようにチャットチャンネルの役割を分離することで、検索等利便性の観点からチームの個性として打ち出すことにしました。
この方針決めの際、メンターさん方は私たちが脱線しすぎないように間接的にアドバイスをしてくださっており、とても助かりました。
負荷試験
CTO の nekokak さんが初めにお話しされていましたが、負荷試験などを通してパフォーマンスを計測して改善の効果を確認することが大切です。私たちはメンバーの使用経験があった Apache Bench を用いて負荷試験をしました。初期実装では 0.07 req/s しか捌けない実装になっていました。何が原因だろうと色々確認してみると、
- MySQL にメッセージが 1000+万件
- 全件取得
- インデックスなし
- 画像は MySQL に base64 で格納
- N+1
- などなど…
といった感じで重たい処理が多くあり、初期実装の遅さにも納得しました(笑)。
バックエンドでやったこと
バックエンドは 3 人なので、役割分担をすることにしました。私は ISUCON によく出ており、ある程度知識があったので Golang で書かれた API の改修・新規機能追加と、MySQL 周りのチューニングを担当しました。 一番意識した点は、フロントエンドとの連携です。フロントで新規機能を実装する際に API がまだできていない!といったことが起きないように、優先順位を調整して円滑に回るようにバリバリ実装を進めました。Zoom のブレイクアウトルームを活用し、API の仕様決めや完成報告は部屋を行き来して報告することを心がけました。
バックエンドのチーム内でも報告を心がけていましたが、お互いの進捗が分かりにくかったりうまくいかない点も多々あったのでコミュニケーションの大切さを感じました。
新技術への挑戦
開会式で nekokak さんが「新しいことに挑戦してみよう」といったお話をされていて、せっかくなのでやったことのない技術に失敗覚悟で挑戦してみました。
あまりネタバレしないようにその他私がやったことをまとめると、
- N+1 の修正
- MySQL のパラメータチューニング
- テーブルパーティショニング
- レプリケーション
などをやりました。今回初めて挑戦した 2 つの技術について紹介します。
テーブルパーティショニング
テーブルパーティショニングはキャッシュ対策として導入しました。メッセージテーブルには 1000 万件超えの膨大なデータが保存されており、それに加えて I/O コストが非常に高い状況でした。インデックスを貼ってもインデックスサイズが巨大になってしまい、キャッシュに乗りにくいことが想定されました。そこで、チャンネル ID を基準にテーブルを適切に分割することで、I/O を分散させインデックスサイズを小さくする手法を取りました。
レプリケーション
レプリケーションは高負荷に耐えるためにマストだと感じたので導入しました。合計 10 台までc5.large
インスタンスが使えるとのことだったので、1 台をマスター DB、6 台をスレーブ DB にする構成を取りました。
想定されるユースケースは、情報の発信««閲覧 であると考えられたので、参照系のクエリをスレーブ DB に分散させることにしました。
このような改善もしつつ、他のメンバーが行っていた改善をマージしたところ、目標であった約 10000 req/s の処理速度を達成することができました!
インターンを通して学んだこと
いままでチーム開発というものをあまりしてこなかったので、今回のサマーインターンは新鮮な経験でした。チームメンバーの皆さんはそれぞれ様々な得意領域を持っていて、各々の強みを活かして 1 つの目標まで(妥協しつつも)辿り着けたのは忘れられない経験になったと思います。
加えてチームビルディングの難しさ・大切さについて気付かされることが多かった 3 日間でもありました。1 日目は探り探りの状態で、私自身も発言することが少なくメンターさんにファシリテートしてもらう場面が少なくありませんでした。夕方チームで行った KPT などの振り返りを通して、徐々にメンバーの考えや得意領域などが明らかになっていき、信頼関係も生まれ、こうしてチームが形成されていくのかと納得しました。 3 日目にもなるとお互い頻繁に意見交換するようになり、新しいアイデアも生まれました。私たちのチャットアプリ名の『Kizuna』であったり、アプリのテーマカラーである暖色カラーなどがその例です。 もうあと数日あればさらに洗練されたチームが出来上がっていたのではないかと思えるくらい良いチームになりました(笑)
最後に
今回のサマーインターンは、単に技術力を結集し 1 つのプロダクトを改善するというものではなく、チームビルディングを通してチームとしての個性を出しつつ、個々人の持つ技術力以上のプロダクトに仕上げるという点で学びが非常に多かったインターンでした。 また、他チームの発表を見てまだまだ自分にはこの視点・技術が足りていないと今後の成長ポイントを気づかせてくれるインターンでもありました。
DeNA のサマーインターンは、エンジニアとしてのコミュニケーション力と技術力を試せる素晴らしいインターンです。これを見て少しでも興味を持った方は来年是非申し込んでみてください!
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。