ニコニコの就業型インターンでサーバーサイドの開発に参加してきました!
はじめに
はじめまして!同志社大学大学院 理工学研究科に所属しています、修士2年のbe3(@Blossomrail)です。
私は、2023年の1月~3月までの期間、ドワンゴのインターンシップでサーバーサイド領域の開発に参加させていただきました。
このリンクは2023年度のインターンシップ募集ページになりますが、私はこちらの2022年度のインターンシップに参加させていただきました。
本記事の内容は、以下の通りです。
- DMS開発部について
- インターンシップ中の業務について
- インターンシップを通して学び得たこと
- 大学院生活との両立について
主な対象読者は、サーバーサイド領域におけるソフトウェア開発に興味がある学生や、メディア配信サービスの構築に興味がある学生になるかと思います。
また、上記に該当している一方で、研究とインターンシップの両立が気になっている大学院生にとって参考になるかもしれません。
DMS開発部について
私の業務内容をお伝えする前に、まずは私がインターン生として配属されたDMS開発部についてお伝えしたいと思います。
DMS開発部は、ドワンゴのメディア配信を支え続けているDWANGO Media Cluster(以下、DMC)を、パブリッククラウドの使用に適した設計で新たなシステムDWANGO Media Services(以下、DMS)にリプレイスするための部署です。
従来のDMCでは、運用が始まって6~7年間が経過して、さまざまな課題を抱えることになりました。
全てではないですが、いくつか例を以下に挙げます。
- オンプレ運用によるメンテナンスやデプロイの手間
- モノリス設計システムの肥大化による機能追加の難しさ
そこで、DMSとして再構築し直すことで、以下のようなメリットを生み出すことを検討しました。
- パブリッククラウドを活用した運用コストの緩和
- マイクロサービスアーキテクチャの採用による機能拡張性の向上
私がこの話をマネージャーの久保田さんからお聞きした時、サービスが開始してから何年も経ちユーザも多いニコニコ系サービスのメディア配信基盤を刷新するのは途方もない計画のように感じました。
しかし、これは大変なミッションであると感じたと共に、そんなチームに配属していただいて開発業務に携わる機会を頂けたことをとても嬉しく思ったのを覚えています。
より詳しく知りたい方は、こちらの記事を読んでみてください。
私を3ヶ月間支えて下さったマネージャーである久保田さんがDMS開発部についてお話されています。
インターンシップ中の業務について
どんなシステムを開発したのか
それでは、私が配属されたDMS開発部とそのミッションについてお伝えできたということで、次に私がDMS開発部にて取り組んだ業務内容についてお伝えしたいと思います。
私がインターンシップ中に取り組んだ業務は、DMSもしくはDMCが保有する動画を社内システムへ中継するAPIサーバー(以下、MovieRelay)の構築です。
MovieRelayの主な機能要件は以下の通りです。
- 社内システムからのリクエストに対して、動画や動画情報(json)をレスポンス
- リクエストで指定された動画IDや動画品質に応じたコンテンツ(動画/動画情報)をDMSもしくはDMCから取得
- DMSにおけるコンテンツの有無に応じて、DMCにコンテンツを問い合わせ
- もしくは、DMCにおけるコンテンツの有無に応じて、DMSにコンテンツを問い合わせ(設定値次第で逆順も可な仕様)
- DMSのレスポンスから取得した動画形式をHLSから内部用動画フォーマットへ変換
上記の機能要件を図にすると、以下のようになります。
今後、DMC(旧システム)からDMS(新システム)への移行が段階的に行われる予定で、その過程で一部の動画はDMSにその他の動画はDMCにあるという状況が発生することがあります。
そのため、DMCかDMSのどちらかに問い合わせた後に、コンテンツがなかった場合にもう一方のシステムに問い合わせる必要があります。
システムの概要設計
次に、上記で示した機能要件を満たすようなMovieRelayを構築するにあたって、まずはシステムの概要設計から行うことになりました。
本システムに求められるAPI仕様は予め定義されていたため、そのAPI仕様をどのように満たせば良いのかを様々な社内資料を参考に考えて、以下の内容についてドキュメント化しました。
- MovieRelayがDMS、DMCのAPIをどのように利用すれば良いのか
- HLSから内部用動画フォーマットへの変換はどのように行うのか
また、システム内における処理と構成要素についても考える必要があり、MovieRelayの内部での処理を整理し、処理の種類に応じてシステムの構成要素に切り分けました。
マネージャーの久保田さんとの相談やDMS開発部の方々からのレビューを経て、最終的には以下のような構成になりました。
各構成要素の役割は以下の通りです。
- relay: 社内システムに対してAPIを提供し、コンテンツの有無に応じて、DMSとDMCに問い合わせ
- DMS interface: DMSのAPIと通信し、動画や動画情報を取得してrelayへ返す
- DMC interface: DMCのAPIと通信し、動画や動画情報を取得してrelayへ返す
- converter: DMS interfaceが取得したHLS動画を内部用動画フォーマットに変換
動画形式の変換について
本システムの特徴である動画形式の変換について述べたいと思います。
前述の通り、MovieRelayは動画の形式をHLSから内部用動画フォーマットへ変換する必要があります。
HLSは、HTTP Live Streamingの略称で、動画のオンデマンド配信とライブ配信の両方が可能なストリーミングプロトコルの一つです。
また、正確にはHLSはファイル形式ではなくプロトコルであり、HLSを内部用動画フォーマットに変換するということは、HLSという規格に従ったファイル形式(m3u8ファイルやtsファイルなど)から対象のフォーマットへ変換するということになります。
MovieRelayでは、HLSのファイルを入力すると内部用動画フォーマットを出力するコマンドをGo側で実行して、コマンドの出力結果をHTTPレスポンスに渡す形で実装しました。
具体的には、os/execパッケージを利用して以下のような実装を行いました。
cmd := exec.CommandContext(ctx, "convert-cmd", args) // コマンドの指定
cmd.Stdout = responseWriter // 出力先を標準出力からHTTPレスポンスに変更(io.Writer)
err := cmd.Run() // コマンドの実行
簡単な実装ではありますが、ここでポイントとなる部分は2行目で、標準出力に出力される内容(変換結果)をHTTPレスポンスに出力するよう変更することです。
ここで示している変数responseWriterは、io.Writerを満たすHTTPレスポンスの構造体で、関数の引数として外部から受け取るものとして想定しています。
動画の変換結果を安易に[]byte型で受け取り関数の戻り値として返そうとすると、HTTPレスポンスとして変換結果をネットワークに送り出す前に、変換結果を一度メモリに載せることになってしまいます。(初めにそういう実装をしてしまいました…。)
ローカル環境で実行している分には動作に支障はありませんが、MovieRelayは業務システムとして今後運用されていくため、複数のリクエストを並行して捌くことが考えられ、また動画の尺や画質次第では、大きいファイルを扱う可能性も出てきます。
そのため、こうした実装をしてしまうと、メモリがひっ迫した結果、パフォーマンスの低下やプログラムのクラッシュなどの問題が発生してしまう可能性があります。
そこで、io.Writerというインタフェースを介して、コマンドの実行結果をHTTPレスポンスとして送出しました。
io.Writerという低レベルなインタフェースで共通化されていることで、出力先を簡単に変更できるところがGoの良いところだと実感できました。
インターンシップの感想
業務システムの設計・開発を通して、実践的なソフトウェア開発を味わえる有意義なインターンシップだったと感じています。
何か特定の技術について学びが得られることよりも、目標とするシステムを構築する上で技術的なアプローチの良し悪しを考えることの重要性について学べたことが、今回のインターンシップでの一番の成果だったのではないかと思います。
プロダクションレベルの開発業務に携わることで、プロフェッショナルな開発者としての姿勢や仕事への取り組み方を学ぶことができました。
また、システムのパフォーマンス、コードの耐変更性や可読性などを意識した実装を経験することができました。
これにより、実際のプロジェクトにおけるベストプラクティスを学ぶことができ、自分のコーディングスキルを向上させることができたと感じています。
また、MovieRelayは業務に欠かせないシステムであるため、設計や開発の中でDMS開発部の皆さんから様々なアドバイスやご指摘をいただきました。
何度もPull Requestを更新して自身の実力不足を痛感し、社員さんに度々レビューをお願いした時は申し訳なく感じることもありましたが、チームとの協力を通じて高品質な成果物を提供することの重要性も実感できたと思います。
その他にも多くのことを経験できましたが、長くなるので簡単にまとめると以下になります。
- 設計を通して経験できたこと
- 機能要件の整理
- 概要設計
- システムの構成
- 実装を通して経験できたこと
- goroutineを用いた非同期処理
- メモリの使用を意識した実装
- interfaceを用いた共通化
- 開発を通して経験できた技術
- Go
- HLS
- gRPC
大学院生活との両立
ここでは、大学院生である私が大学院生活とドワンゴでのインターンシップをどのように両立していたかについて述べたいと思います。
まず、ドワンゴでの勤務頻度は以下になります。
- 1月:週3回、1日8時間勤務
- 2月, 3月:週3~4回、1日8時間勤務
基本的に週3日が多かったのですが、2月と3月は大学院の授業がなく研究室での業務が落ち着いている時期だったので、週4日勤務をさせていただく週もありました。
研究や研究室での予定で忙しいことが多い大学院生にとって、上記のような勤務頻度はあまり見かけないかもしれません。
こうした勤務頻度でインターンシップに参加できた理由としては、私の趣味がプログラミング関連だったため、元々技術書を読むことや個人開発をすることに充てていた時間がインターンシップの時間に置き換わっただけであることが大きいと思います。
そのため、平日はインターンシップと研究に時間を使い、土日はさらに研究にまとまった時間を充てるといったような生活を送っていました。
また、私が所属したDMS開発部では、大まかな勤務曜日や時間だけを予め伝えておき、詳細な日時については毎週末に共有するといった形を取らせていただいていました。
勤務日時の更新間隔を短く設けていただけたお陰で、研究や研究室の予定の都合による急な勤務日時の変更にも対応しやすいことが大変助かりました。
おわりに
本インターンシップは、システム開発の現場に飛び込み、エンジニアとしての成長に素晴らしい機会でした!
本記事を通して、ドワンゴやドワンゴのインターンシップに興味を持っていただければ幸いです。