Slide 1

Slide 1 text

7 年間運用したソーシャルゲームを Amazon EC2 構成からAmazon ECS 構成へと 乗り換えた話 1

Slide 2

Slide 2 text

自己紹介 大澤 純 (@commojun) 2016~ サーバサイドエンジニア@KAYAC 2

Slide 3

Slide 3 text

アホみたいなことをつぶやいたり 3

Slide 4

Slide 4 text

バカゲーを作ってリリースしちゃったりしています https://twitter.com/kayac_inc/status/1434804351336255491 4

Slide 5

Slide 5 text

今日のお話 ぼくらの甲子園! ポケットという長期運用ゲームをコンテナベースのシステムへ移行した 長期運用特有・もしくはこのゲーム特有の事情に合わせた工夫点だったと思う箇所 専門的な内容でも理解を得ながら仕事を進めることの重要性 5

Slide 6

Slide 6 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 6

Slide 7

Slide 7 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 7

Slide 8

Slide 8 text

ぼくらの甲子園! ポケットは2014 年から運用を続けているソーシャルゲームタイトルです。 おかげさまで2021 年10 月で7 周年を迎えることができました。 https://koshien-pocket.kayac.com/ 8

Slide 9

Slide 9 text

ぼくらの甲子園! ポケットの特徴 ユーザは監督ではなく、選手である ユーザが9 人集まらないと試合すらできない チームメイトの一人ひとりがユーザ ユーザは選手になって甲子園を目指すため、青春を追体験できる 9

Slide 10

Slide 10 text

ぼくらの甲子園! ポケットの特徴 2 週間に1 回の甲子園大会に出場するためにリーグ戦を繰り返す 甲子園大会はトーナメント戦で1 日かけて行う 優勝すると、優勝チームの要望に応えた新聞を運営が作成し、ゲーム内に掲載する 10

Slide 11

Slide 11 text

ぼくらの甲子園! ポケットの特徴 リーグ戦の試合は毎日定刻に開始 参加するには決まった時間にログインしなければならない 作戦会議中にスキルを発動したり、仲間にエールを送ったりする 作戦会議が終了すると完全オートで試合が進行する 複雑なアクションは無く、戦況に応じてどのスキルを使うかが重要 打席・試合の結果は全てサーバのバッチ実行によって決定する 11

Slide 12

Slide 12 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 12

Slide 13

Slide 13 text

ぼくらの甲子園! ポケットは2014 年9 月12 日リリース 当然開発はそれよりも前に開始していた。その頃の時流に乗ったサーバ構成 13

Slide 14

Slide 14 text

役割に応じたEC2 インスタンスがあり、必要に応じてオートスケールをしたりする Aurora MySQL や、Elasticache (Redis )などマネジメントされた物を利用 batch サーバ上でcrond が常駐して、定刻の試合開始を行っている 14

Slide 15

Slide 15 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 15

Slide 16

Slide 16 text

1, Amazon Linux のサポート終了 EC2 上で利用しているOS のサポートが2020 年末に終了するため 何かしら手を打たなければならなかった 後継OS Amazon Linux2 への乗り換えという選択肢もあるが… https://aws.amazon.com/jp/blogs/news/update-on-amazon-linux-ami-end-of-life/ 16

Slide 17

Slide 17 text

2, コンテナを利用したサーバ構築が当たり前になりつつある 他のゲームタイトルやサービスで、Amazon ECS を使った サーバ構成について社内に知見が貯まっていた 17

Slide 18

Slide 18 text

3, このゲームの運用を10 年続けたい! 長期運用タイトルにする意思がチームの総意としてあった リリース時から時代が変わっているので、将来性のある構成に乗り換えよう! 18

Slide 19

Slide 19 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 19

Slide 20

Slide 20 text

運用が続くとゲーム体験に関係のある部分に関心が向きがち 20

Slide 21

Slide 21 text

言語のバージョンとモジュールのバージョンも長らくメンテされていなかった 21

Slide 22

Slide 22 text

Perl 5.16 👉 Perl 5.30 エイヤで言語バージョンを上げてみる 22

Slide 23

Slide 23 text

@INC 問題 23

Slide 24

Slide 24 text

Perl 5.26 での変更点 特にテストコードが影響を受けた https://perldoc.jp/docs/perl/5.26.0/perl5260delta.pod perl バイナリは @INC にパスのデフォルト集合を含んでいます。歴史的に、汚染モード (perl - T) が有効でない限り、最終的なエントリとして カレントディレクトリ (".") も含んでいまし た。 これは便利ですが、セキュリティ上の問題がありました: 例えば、 カレントディレクト リが(/tmp のように) 信頼できない場合、 スクリプトが追加のモジュールを読み込もうとする と、そのディレクトリの下から コードを読み込んで実行する可能性があります。 v5.26 から、"." は汚染モードの場合だけではなく、 常にデフォルトで 除去されるようになり ました。 これはモジュールのインストールとスクリプトの実行に大きな影響を与えます。 use t::Util; use strict; 1 use warnings; 2 use utf8; 3 4 use Test::More; 5 ... 6 24

Slide 25

Slide 25 text

@inc のドットに頼ったモジュールはそう多くなかったので、引っ越して対応 Before After https://perldoc.jp/docs/perl/5.26.0/perl5260delta.pod @inc からドットが除去されたことによるテストの問題を修正するとき、 @inc にドットを再挿 入するのは慎重に行うべきです、 これも実行時コードの実際の問題を抑制するかもしれない からです。 可能な限り、明示的な絶対/ 相対パスを使うという前述した手法を適用するか、 必要なファイルをサブディレクトリに再配置して、代わりに そのサブディレクトリを @inc に 追加することを勧めます。 /repository_root |--t |--Util.pm |--testa.t |--testb.t /repository_root |--t |--lib | |--t | |--Util.pm |--testa.t |--testb.t perl -Ilib -It/lib 25

Slide 26

Slide 26 text

コンパイルエラーしまくる 26

Slide 27

Slide 27 text

Perl 5.24 での変更点 こういうのがダメ https://perldoc.jp/docs/perl/5.24.0/perl5240delta.pod (autoderef 機能は取り除かれました) 実験的な autoderef 機能 (push, pop, shift, unshift, splice, keys, values, each をスカラ引数で呼び出せ るようにする) は失敗と 判断されました。 これは削除されました; この機能を use しようとす ると ( または以前は 引き起こされていた experimental::autoderef 警告を無効にしようとすると) 例外が発生するようになりました。 my $arrayref = [1,2,3]; while (my $num = shift $arrayref) { # NG! ... } 27

Slide 28

Slide 28 text

@ をつけて回る作業 ↓ my $item_dic = { one => "hoge", two => "fuga", three => "piyo", }; for my $item (keys $item_dic) { # NG! ... } for my $item (keys @$item_dic) { # OK my $item_dic = { 1 one => "hoge", 2 two => "fuga", 3 three => "piyo", 4 }; 5 6 ... 7 } 8 28

Slide 29

Slide 29 text

長いときはpostderef 機能に積極的に頼った ↓ https://perldoc.jp/docs/perl/5.24.0/perl5240delta.pod 接尾辞デリファレンスは実験的ではなくなりました postderef 機能と postderef_qq 機能を使っても警告が発生しなくなりました。 以前使われてい た、experimental::postderef 警告カテゴリを無効にしている 既存のコードはそのまま動作しま す。 postderef 機能は何の効果もありません; 全ての Perl コードは、スコープ内でどの機能が宣 言されているかに関わらず、接尾辞デリファレンスを使えます。 5.24 機能バンドルは postderef_qq 機能を含むようになりました。 my $arrayref_by_name = { one => [2,3,4], two => [5,6,7], }; while (my $num = shift $arrayref_by_name->{one}){ # NG! ... } while (my $num = shift $arrayref_by_name->{one}->@*){ # postderefに頼る my $arrayref_by_name = { 1 one => [2,3,4], 2 two => [5,6,7], 3 }; 4 5 ... 6 } 7 29

Slide 30

Slide 30 text

テストが運で落ちたり通ったりする 30

Slide 31

Slide 31 text

Perl 5.18 ハッシュのランダム化のあおりを受ける keys や values を使って取り出した配列を使ってfor 文を回すような箇所で、 配列の順番に依存したテストが落ちていた https://perldoc.jp/docs/perl/5.18.0/perl5180delta.pod#Hash32randomization Perl のハッシュ関数が使う種はランダムになりました。 これは、keys(), values(), each() のよう な関数が返すキー/ 値の 順序は実行毎に異なるということです。 my %tests = ( testa => sub { return "aaa" }, testb => sub { return "bbb" }, ); my @expected = ["aaa", "bbb"]; for my $test (values %tests) { is, $test(), shift @expected; # testa から実行されるとは限らない! } 31

Slide 32

Slide 32 text

モジュールのバージョンを上げてみる 32

Slide 33

Slide 33 text

蓋を開けてみると見えた問題 そもそも cpanfile.snapshot でのバージョン管理がなされていなかった 後方互換の無いモジュールバージョンアップがうっかり混入してあわてて固定する運用 モンキーパッチを当てたせいでバージョンを上げられない 日本語を含んだJSON のリクエストがどうしても上手くさばけない 33

Slide 34

Slide 34 text

2 つのOSS にPR を出させていただきました ネストされたJSON リクエストの中に日本語があると正しくエンコードされない問題 ネストされたJSON リクエストが正しくデコードされない問題 https://github.com/kazeburo/HTTP-Entity-Parser/pull/13 https://github.com/moznion/Plack-Request-WithEncoding/pull/3 34

Slide 35

Slide 35 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 35

Slide 36

Slide 36 text

EC2 構成からECS 構成へ コンテナベースのシステムへの転換 36

Slide 37

Slide 37 text

最も恩恵があるのがデプロイまわり 最も変化があるのがデプロイまわり 37

Slide 38

Slide 38 text

EC2 構成のデプロイ方法 strecher というOSS によるpull 型のデプロイツール デプロイサーバがリポジトリから配布物を取得する デプロイサーバが配布物を全て一つのアーカイブにまとめてAmazon S3 に保存する 各ホストがAmazon S3 から配布物を取得する https://techblog.kayac.com/10_stretcher.html 38

Slide 39

Slide 39 text

ECS 構成のデプロイ方法 とにかくコンテナイメージをビルドしてリポジトリに収める デプロイ = コンテナインスタンスの入れ替え 39

Slide 40

Slide 40 text

EC2 構成でのデプロイ方法の利点 Github 上でデプロイ用のブランチが準備できれば、その先のデプロイが迅速 そのスピード感に頼ってデプロイの頻度が多い運用となっていた 40

Slide 41

Slide 41 text

ビルドが長い ブランチの準備ができてから、ビルドする時間がかかる 41

Slide 42

Slide 42 text

circleci にビルドさせる ブランチにコミットさえすればビルドされる ECR へのPUSH までのパイプライン 42

Slide 43

Slide 43 text

2 階建て作戦 base イメージとapp イメージに分ける 夜中に依存パッケージ、モジュール、ツール類をbase イメージでインストール リリース用ブランチへのコミットがある度、アプリケーションコードをコンテナにコピー する Dockerfile.base Dockerfile 運用上必要な箇所のみにコンテナイメージビルドの時間をかける FROM perl:5.30.0-buster RUN apt-get install 必要なソフトウェア ... $ docker build -t app:base . FROM app:base COPY ./ /home/user/repo/ ... $ docker build -t app . 43

Slide 44

Slide 44 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 44

Slide 45

Slide 45 text

とにかくバッチサーバが命 試合進行というゲームの最重要要素が1 台のバッチサーバ(crontab) にかかっていた 45

Slide 46

Slide 46 text

batch サーバが突然死したときのバックアップ策が存在しなか った(!) ECS 移行を機に冗長化できないか? 46

Slide 47

Slide 47 text

他プロジェクトでの冗長化事例 CloudWatch Event + SQS + sqsjkr 作戦 47

Slide 48

Slide 48 text

CloudWatch Event( 今はEventBridge) + SQS + sqsjkr 作戦 CloudWatch Event: 定刻のイベント発火をマネジメントサービス化 SQS: 発火したジョブをキューイング sqsjkr: SQS からジョブを取得し実行する( 排他制御機能があり、冗長化可能) https://techblog.kayac.com/2017/04/10/090000 https://github.com/kayac/sqsjkr 48

Slide 49

Slide 49 text

ぼくらの甲子園! ポケットでは… crontab.txt cron 書式のテキストファイルで管理している テキストを解析して日時や内容の整合性をチェックするテストが作り込まれている 100 以上のエントリがあるのでCloudWatch Event の上限に引っかかる 運用上、頻繁に書き換える必要がある このフォーマットは維持したい… 10 00 * * * perl script/batch_aaa.pl 12 00 * * * perl script/batch_bbb.pl 16 00 * * * perl script/batch_ccc.pl ... 49

Slide 50

Slide 50 text

sqsjfr + SQS + sqsjkr 作戦 50

Slide 51

Slide 51 text

sqsjfr + SQS + sqsjkr 作戦 sqsjfr: crond と同様にスケジューラの役割を果たし、実行すべきジョブをSQS に送り込む SQS FIFO キュー: 同一メッセージを削除しながらジョブをキューイングする sqsjfr: SQS からジョブを取得し実行する SQS FIFO キューの重複削除機能によって、sqsjfr の冗長化ができる sqsjfr がcron 書式を解釈できるためcron 書式がそのまま使える! https://github.com/kayac/sqsjfr 51

Slide 52

Slide 52 text

目次 ぼくらの甲子園! ポケットについて EC2 時代のサーバ構成 なぜECS に乗り換えるか ホコリかぶったPerl とモジュールのバージョンアップ 時代に乗ったデプロイ方法にする ゲームの心臓なのにSPOF になっていたバッチサーバの冗長化作戦 非エンジニアに仕事をわかってもらう 52

Slide 53

Slide 53 text

ECS 構成への移行作業の意義を非エンジニアの人にわかってもらうのは難しい 53

Slide 54

Slide 54 text

「ECS 作業はユーザにとってどのようなメリットになりますか?」 54

Slide 55

Slide 55 text

「ええと…Amazon Linux のサポートが切れるからやらないとダメなんですよ… 」 55

Slide 56

Slide 56 text

これでわかってもらえる職場は果たして存在するだろうか?(反語) 56

Slide 57

Slide 57 text

ユーザに直接的なメリットははっきり言って無い でも長く運用するなら必要なこと 説明してわかってもらう必要がある! 57

Slide 58

Slide 58 text

エンジニアとしての背景知識が必要な専門用語を使っていたら理解してもらえない 58

Slide 59

Slide 59 text

受け手と伝え手が共に持っている共通言語を使った例えをうまく使う 59

Slide 60

Slide 60 text

Amazon Linux のサポート切れ Amazon Linux -> Windows に言い換えるととたんに実感がわく 60

Slide 61

Slide 61 text

なぜECS 構成に移行するのか? ECS (コンテナ技術)とはなにか? なぜわざわざAmazon Linux2 ではなくECS を選ぶのか? 61

Slide 62

Slide 62 text

それぞれのバックグラウンドを持つが 62

Slide 63

Slide 63 text

みんなゲーマーという点は共通だった 63

Slide 64

Slide 64 text

ゲーム機の時代変遷で例えて説明してみる ゲームカセット ≒ コンテナ コンテナの便利さと、いかに当たり前になったかを感じてもらえた https://ja.wikipedia.org/wiki/ ホーム・ポン https://ja.wikipedia.org/wiki/ ファミリーコンピュータ 64

Slide 65

Slide 65 text

コンテナ技術が当たり前だと訴える 65

Slide 66

Slide 66 text

66

Slide 67

Slide 67 text

ECS 移行を理解してもらうことの意義 準備作業はほぼサーバサイドエンジニアだけでやる仕事 それを運用中のサービスに適用するとなると、やはり運用メンバー全員の協力が必要 移行メンテナンスも一筋縄ではいかず、不具合もいくつか起こしてしまった それでも運用メンバー全員がその難易度と重要性を理解していたので 足並みを揃えて問題に対処し、移行作業を完了できた 67

Slide 68

Slide 68 text

エンジニアの説明責任? 諦めず工夫して説明すれば、高度に背景知識が必要なことも理解してもらえる 専門的すぎるからと非エンジニアの人に仕事の意義を理解してもらうことを怠ると 最終的に新しい技術への新陳代謝ができない組織になり、成長の可能性を閉ざしてしまう 一線級のエンジニアが現役のまま経営も兼ねている組織でもない限りは このような説明責任も担えるエンジニアが重宝されるのではないだろうか? 68

Slide 69

Slide 69 text

さいごに 69

Slide 70

Slide 70 text

泥臭い作業 この発表で紹介したことは、いわゆる 作戦がきれいにハマった 箇所にすぎない 環境変数の使われかたを正す config の場当たり的な書き方を正す 修正が必要そうな箇所の洗い出し(勘と経験と気合で) 結局、ホコリかぶっていた負債を全部見て回って全部直すパワープレイが必要 飽きずに長く運用やって全体把握できる人間じゃないと たぶん無理 70

Slide 71

Slide 71 text

ありがとうございました 71