この記事は CyberAgent Developers Advent Calendar 2024 13日目の記事です。
背景
こんにちは、ABEMAでバックエンドのディレクターをしている辻(jun06t)です。
僕は2013年新卒でサイバーエージェントに入社しました。当時はソシャゲ黎明期で、かつデバイスもガラケーからスマホに転換するタイミングであり、メディア事業のサービス・ゲーム部門は非常に注力されていた時期でした。
弊社は技術選定においてはプロジェクト毎にテックリードが選定する文化が強いのですが、プログラミング言語のように当時の課題に合わせて大きな判断をとった技術もあります。
この記事ではメディア事業のプログラミング言語の選定の歴史を紐解いていこうと思います。
注意事項
注意としてこれから述べる内容は、当時の背景および課題に基づいて技術選定が行われています。従って言語によって現在は解決されているものもあります。
言語選定の歴史
ブログ:2004/09~
技術スタック
2006/06頃のトラフィックは1500万PV/dayほどで、当時の技術スタックは以下でした。
- J2SE 5.0(Java 1.5)
- Struts 1.x
- CentOS 4
- MySQL 4
この頃はJavaがJVMによって「Write Once, Run Anywhere」の理念を実現できる言語であり、かつオブジェクト指向プログラミングによって大規模システムにも耐えれる言語としてWebでは急速に普及していた時期です。
なので当時の選定としては開発としても事業としても横展しやすい堅実な選択だったと思われます。
アメーバピグ:2009/02~
当時の課題
次のアメーバピグもJavaで開発したサービスです。ただ一方でこの頃課題として浮かび上がってきたのがC10K問題でした。C10K問題とはClientが10K(=10,000)を超えるとサーバリソースを枯渇して捌けなくなると言う問題で、2007年頃から懸念されはじめました。
もう少し踏み込んで説明すると、当時はリクエスト毎にプロセスやスレッドを起動するモデルが主流であり、「64 ビット環境での JVM デフォルトのスレッドあたりのスタック長は 1MB」「ガードページも含むとスレッド毎に数MB」になるため、リクエスト数の増加がリソースをかなり圧迫する問題がありました。
当時のアメーバピグではAdobe Flashを用いてアバターを動かすのですが、そのFlashとの通信が大量に発生する、つまりC10K問題にぶつかることが課題として挙がっていました。
当時の選定
そこで当時は独自のプロトコルを用意し、この課題を回避するように対応されました。以下の図でいうTCP Socketの部分ですね。
引用元:MySQLでNoSQL – アメーバピグでのNoSQLの実例
最終的な当時の技術スタックは以下の通りです。
- Java SE 6~7
- Flash
- MySQL 5.0
- 独自のソケットサーバ
- 同時接続数 100,000
しかしながら独自のプロトコルを運用・保守していくのは非常に大変ですし、他サービスに横展することも難しいという課題が残りました。
ゲーム黎明期:2011/05~
当時の課題
そもそものボトルネックは、
- コネクション確立後、クライアントからリクエストが送られてくるまでの待機時間
- DBや外部APIの処理をしている待機時間
といったread(2)やwrite(2)のシステムコールで実際にデータを読み書きするソケットの準備が整うまでの待ち時間が大半です。
メモリ共有・パイプ・Unixドメインソケットによるプロセス間通信に比べ、ネットワークを経由する処理は非常に遅いのです。
この話の詳細は過去に記事を書いたことがあるので興味ある方は読んでみてください。
イベント駆動モデル
この解決策として当時注目された技術がイベント駆動モデルです。
イベント駆動モデルは既存のプロセス・スレッドモデルと異なり、
- Non-Blocking I/Oで待ち時間にブロックしない
- 複数のソケットを監視してI/O多重化 (I/O Multiplexing)
- listenするソケット
- acceptした後のソケット
- ソケット準備が整ったら(新しいコネクションが来る or リクエストデータが来る)次の処理(=コールバック)へ
という設計になっているため、前述のボトルネックを解消することが可能です。
この考えはコンビニでいう「電子レンジでお弁当を温めている間、次のお客さんの応対をする」がイメージしやすいでしょう。
当時の選定
そこで当時はこのイベント駆動モデルを実現するプログラミング言語(細かく言うとランタイム環境ですが)として、Node.jsを採用しました。
ピグライフからNode.jsを採用しましたが、ピーク時は20万同時接続ほどあったにも関わらず、なんとたったの20台でリクエストを捌けるようになりました。
アメーバピグで10万同時接続を100台で捌いていた頃を考えると、単純計算で10倍近いスループット向上になっています。
その後も多数のサービスで採用し、僕が配属された
- ペコロッジ
- ミリオンチェイン
でも採用されていました。特にネイティブゲームは月初にリクエストが集中しましたが、この言語選定のおかげで大量のリクエストによるC10K問題は発生しなくなりました。
エンタメ:2014/07~
当時の課題
C10K問題も解決し、またJavaScriptはフロントの人も書けるので採用もしやすくめでたしめでたし、と言いたいところです。
しかしながら数々のサービスをリリースし、運用していくと別の問題が浮き上がってきました。開発がスケールしづらいのです。具体的に言うと次のような課題が顕在化してきました。
- スタートアップ時のスピード感は高いが、運用フェーズに移ってから可読性の悪化
- 自由に書けてしまうため書き方がバラバラに
- callback地獄
- 敷居が低いため乱立するライブラリ、ツール
- 非同期プログラミングの理解に一定の壁
おそらく当時Node.jsを採用していた方々は皆同じ苦労を感じていたと思います。
当時の選定
そこで当時選定されたのがGo言語でした。Goは次のような特徴があります。
- 言語仕様がシンプルで学習コストが低い
- 可読性が高い
- 標準ライブラリ/ツールの充実
- 軽量スレッドgoroutine
- GCがシンプルで現実的
こちらも詳細を別途まとめているので、気になる方は参考にしてください。
これはGo言語のゴールがスケーラビリティにあるためです。Simpleを重視したGo言語はチーム開発に向き、開発のスケールがしやすい言語でした。
当時ABEMAが立ち上がる少し前の頃にメディア事業部の中にエンタメ部門が立ち上がり、Ameba Ownd、takusuta、AWAなど新規のエンターテイメント系サービスが生まれました。
そこで初めてGo言語を採用し、今でもサイバーエージェントのGo言語を利用している文化の大元になっています。
まとめ
メディア事業の言語選定の歴史をまとめてみました。
新しい技術は何かしら背景・課題があって、それに対する解決策として生まれてきます。
従って自分たちの背景とそこで起きている課題がその技術が生まれた経緯とマッチし、解決することができる技術を選定するのが最も事業的に効果が高いと言えます。
Webサービスは特に技術の流行り廃りが激しい領域だと感じていますが、枯れた技術・廃りの技術でもマッチしていれば事業的なインパクトは大きいですし、逆に流行りでもマッチせずインパクトが小さければただの自己満足になってしまいます。なので流行り廃りに左右されず、「なぜこの技術は生まれたのか?」を考えて選定するのが良いでしょう。
最後に
普段個人の技術ブログに投稿することが多い自分ですが、この度会社のアドベントカレンダーの執筆をすることになりました。
気づいたらサイバーエージェントに10年以上在籍しており、「自分だからこそ伝えられる内容は何か」を考えた時に過去の技術選定のような歴史話をしようと決めました。
最後のまとめに書いたように技術選定の本質は課題に対する解決策であり、メディア事業の言語選定はそれを体現していたと感じています。