Slide 1

Slide 1 text

終了の危機にあった15年続くWebサー ビスを全力で存続させる 
 〜Twilog・Togetter統合の舞台裏〜
 by 吉田俊明、青山民人|トゥギャッター株式会社
 PHP Conference Japan 2024


Slide 2

Slide 2 text

自己紹介
 吉田俊明 @yositosi
 2009年ヤフー在籍中に趣味でTogetterを開発、2010年会社化。経営も嗜みつ つ、エンジニアとしてコードもガンガン書いている。Twilogの移管に際してはかなり の部分のコードを書いている。
 2人の男の子の育児中
 青山民人(アオヤマ ミント) @MintoAoyama
 SIer・コンテンツ変換ソリューションのITベンチャー・モバイルゲーム会社などを経 て、2015年にTogetter社に入社。以降、Togetterのインフラをほぼ1人で見てい る。
 最近はモータースポーツ観戦や YouTube Live での音声配信が楽しい 


Slide 3

Slide 3 text

TwilogとTogetterについて 
 どちらも、2009年に個人によって開発
 Twilog:Twitter(X)上の個人のログを自動的に収 集してブログ形式で保存、閲覧できるようにする サービス
 Togetter:Twitter(X)上ツイートを自由に組み合 わせてまとめを作って保存できるサービス


Slide 4

Slide 4 text

Twitter APIの有料化が発表 
 2022年にイーロンマスクに買収されて以後、様々 な変更が加えられてきていましたが、ついにAPI にも魔の手が
 
 2023年3月、無料だったAPIの有料化が発表、そ の金額が月に600万円を超える金額であることが 判明する。


Slide 5

Slide 5 text

Twilogへの買収提案 
 ● Twitterの動向が不透明な中、クライアント を中心にサービス終了が加速
 ● 終了するサービスを引き取る形で取り込む 場合も事前に想定していた
 ● API有料化により、厳しくなると思われてい たTwilogにDMで統合を打診
 ● 2023年3月末に打診 -> EnterpriseAPI契約 完了 -> 5/1に買収 -> 5/12にTogetter統 合発表


Slide 6

Slide 6 text

フェーズ0:ドメインのみ統合 
 ● 2023年4月にTwilogの Twitter API が停止 
 ● 早期に復旧させるため、ログイン機能の回復を試みる
 ● 専用のログイン機能をTwilog側に提供し、Twitterのアクセストーク ンを安全に交換する仕組みを実装
 ● twilog.org から twilog.togetter.com に切替・リダイレクト
 ● 5月末に復活 👏


Slide 7

Slide 7 text

Twilog 統合前(2023年4月時点)のシステム構成 
 「さくらの専用サーバ PHY 」* 2 … 月額 6万円 程度 
 ● 物理専有ホスティングサービス
 ○ スペックに対するコスパは良い
 ○ クラウドサービスほど柔軟な課金体系ではない
 ● スペックとソフトウェア構成
 ○ 8コア 1CPU / 32GBメモリ / 7TB SSD / 100 Mbps
 ○ Apache + Ruby (rbenv) + MySQL MyISAM
 ○ MySQLレプリカを含め、合計2台稼働
 ● 合理的かつシンプルな印象


Slide 8

Slide 8 text

6TB超・32GB mem の MySQL を AWS に移すと? 
 storage だけでざっくり見積もっても 月間
 ● Aurora Standard … 720 USD = 約 11万円
 ● 汎用 SSD (gp3) … 576 USD = 約 9万円
 ● スループット最適化 HDD (st1) … 324 USD = 約 5万円
 ● S3 標準 … 150 USD = 約 2.3万円
 compute でざっくり見積もると 更に 月間
 ● Aurora RDS(db.r7g.xlarge) … 354 USD = 約 5.4万円
 ● EC2(t4g.2xlarge / reserved)… 150 USD = 約 2.3万円


Slide 9

Slide 9 text

フェーズ1:アプリケーションコードを統合 
 ● AWSにそのまま移行するとコストが月6万円から数十万円超に増 えることが予想
 ● まずはAWSから さくら に対してDB接続することを検討
 ● Rubyを全てPHPに書き換え Togetterの一部 として稼働
 Togetter Twilog(旧) Twilog(フェーズ1) 運用環境 AWS さくら専用サーバ AWS 言語 PHP Ruby PHP データベース Aurora(MySQL) MySQL MySQL DBサーバ AWS さくら専用サーバ さくら専用サーバ

Slide 10

Slide 10 text

フェーズ1:2ヶ月でコードの統合を目指す 
 ● フェーズ0の裏で、買収直後から移行計画をスタート
 ● とはいえ、社内に人的な余裕もなくRubyに長けた人材も無し
 
 🤔


Slide 11

Slide 11 text

フェーズ1:めもりーさんにコード移行をまるっと任せる 
 ● たまたまTwitterで退職を発表
 ● 以前、当社の業務委託で働いており、 Togetterのソースコードは把握済み
 ● Twilogの仕様書やテストなどはなく、あるの はコードだけ
 ● Rubyもきっと詳しいはず
 ● 「DBはそのままで仕様を全て満たして動作 するものをゼロから作って」
 ● とりあえず打診 -> すぐに快諾
 @m3m0r7


Slide 12

Slide 12 text

フェーズ1:想定以上のスピードでPHP化が完了 
 ● めもりーさんとの契約期間が2ヶ月ということで、お互いかなり巻きで 取り組んだこともあり、予定通りに移行完了
 ● バックエンドは全てPHPへ(Togetterとの統合)
 ● フロントエンドはデザインはそのままに一部React化も実施
 ● DBは旧Twilogのものをそのまま利用して動作するように実装
 ● 旧Twilogのコードは一切使っていない状態(リポジトリは破棄可能)


Slide 13

Slide 13 text

フェーズ1:AWS↔さくら間のデータベース接続 
 App
 (EC2)
 MySQL
 (Aurora)
 MySQL
 (さくら)
 ● IPアドレス制限や暗号化を行った上で AWS から接続
 ● ログイン情報などの基本的なデータは Aurora にある
 🔒
 AWS


Slide 14

Slide 14 text

フェーズ1:AWS↔さくら間のデータベース接続 → 失敗
 ● 事前検証時のレイテンシ自体に大きな問題はなし
 ● 本番環境におけるリクエスト数もそこまで多くはなかった
 ● デプロイ後に処理が詰まり、Twilogがダウン
 ● AWS↔さくら間の通信コストを過小評価していた


Slide 15

Slide 15 text

フェーズ2:データベース移行 
 フェーズ1をスキップして、DBのAWS移行を前倒しへ
 Togetter Twilog(旧) Twilog(フェーズ2) 運用環境 AWS さくら専用サーバ AWS 言語 PHP Ruby PHP データベース Aurora(MySQL) MySQL Aurora(MySQL)? DBサーバ AWS さくら専用サーバ AWS

Slide 16

Slide 16 text

フェーズ2:データベース移行の課題 
 ● メンテ時間を最小にしながら、破損なくデータを移行できるか
 ● 6TBを超える15年に渡り溜め込まれたツイートのログを Aurora に 移行するとストレージ料金も嵩み、月数十万に
 ○ RDS for MySQL を選択しても大きくは変わらない
 ● Twilogのツイート検索はMyISAMの全文検索機能に依存していた が、AuroraのストレージエンジンはMyISAMを非サポート


Slide 17

Slide 17 text

フェーズ2:AWS↔さくら間でのレプリケーション 
 ● 本番稼働しながらレプリケーション・移行完了まで継続する
 ● レプリケーションの前に sqldump を転送し稼働しておく
 MySQL
 (Aurora)
 MySQL
 (さくら)
 🔒
 AWS
 sqldump
 +
 binlog


Slide 18

Slide 18 text

フェーズ2:AWS↔さくら間でのレプリケーション 
 sqldump の “生成・転送” をより速くするために
 ● mydumper + pzstd で作成!
 ○ 並列処理でより速く、圧縮でより(サイズを)軽く
 ○ 動作しない場合は mysqldump などもオススメ
 ● 「さくら → EC2 → Aurora」と経由して転送する
 ○ 転送元のグローバルネットワーク帯域を使い切るか増やす
 ○ ローカルネットワーク上の別マシンを活かしてもいい
 ■ 対象ファイルを分割・並行転送で倍近くに改善👍


Slide 19

Slide 19 text

フェーズ2:AWS↔さくら間でのレプリケーション 
 sqldump の “生成・転送” をより速くするために
 ● EC2 及び Aurora のスペックを “盛れる” だけ “盛る”
 ○ vCPU / メモリ / EBS / ネットワーク帯域 など
 ● サイズ・スペックによっては全工程が長期に及ぶこともある
 ○ 可能な限りスクリプトで自動化する
 ■ 進行状況、異常発見のためのロギングも必要
 ○ 処理が停止した時のために途中再開可能にする
 ○ 一つ一つの処理を極力早く終わらせるために工夫を重ねる


Slide 20

Slide 20 text

フェーズ2:ストレージコスト増大に対する対策 
 ● 案1:S3にログデータをテキストとして保存し、S3 Selectを使って全 文検索を実現
 ○ 事前の予測でS3 Selectのコストが月に数百万円になる想定のためNG
 ● 案2:S3にログデータをテキストとして保存し、ローカルでgrepなどを 用いて全文検索を実行する
 ○ 実装は可能なもののデータの取り扱いが不便
 ● 案3:S3にログデータをSQLiteでユーザ毎に保存し、SQLiteの全文 検索機能を利用
 ○ データの巨大なユーザでも高速に全文検索可能で、RDBの機能も活用できる


Slide 21

Slide 21 text

フェーズ2:SQLiteの採用を決定 
 ● 1ユーザ、1SQLiteファイルとし、100万を超えるユーザ分のSQLiteを 全てS3上に設置することに
 Togetter Twilog(旧) Twilog(フェーズ2) 運用環境 AWS さくら専用サーバ AWS 言語 PHP Ruby PHP データベース Aurora(MySQL) MySQL Aurora(MySQL)+ SQLite DBサーバ AWS さくら専用サーバ AWS

Slide 22

Slide 22 text

フェーズ2:SQLiteを用いたマルチマスター環境の実装 
 ● MasterであるAurora側に最終の更新日時とS3にSync済みかどうか のカラムを追加
 ● SQLite側にもAurora側の最終更新日時と同じデータを入れておく
 ● アプリケーション側でSQLiteを見る際に、MasterとSQLiteの最終更 新日時に差があれば、「正しくSyncできていない」として手元の SQLiteの更新を裏で実施する
 ● is_syncがfalseの場合は、最新のデータがs3にもないと判断し、true になるまで待機


Slide 23

Slide 23 text

フェーズ2:SQLiteを用いたマルチマスター環境の実装 
 Aurora
 App
 S3
 App
 App
 user.sqlite(v2)
 ①userにアクセス
 ②sqliteの状態を確認 
 user.sqlite(v1)
 ③最新はv2でsync済み 
 ④v2を取得
 ⑤user.sqlite(v2)


Slide 24

Slide 24 text

フェーズ2:MySQLからSQLiteへの変換 
 ● Twilog全体をSQLiteに変換するには数日かかる
 ○ Twilog全体を止めずに可能な限り最小の時間で本番を切り替えたい
 ○ どのユーザのどのレコードにCRUDが行われたのか、MySQLだけから検知す るのは困難
 ○ 旧Twilog側のユーザレコードに、last_update_atを追加してもらい、何か更新が 発生したらこの値を更新してもらう実装を依頼
 ○ そこの値を常にチェックして、更新が入ったユーザのSQLiteを再生成するプロ セスを実行して、常に最新が取り込まれるように


Slide 25

Slide 25 text

フェーズ2:デプロイ未遂(2023年12月) 
 ● 旧Twilogをメンテモードの切り替え、last_update_atの更新が止まるま でログを監視
 ● 全ての更新がSQLite側に反映されたのを確認した時点で、新しい Togetter統合版に切り替え
 ● データサイズの大きなユーザで正しく検索結果が表示されない不具 合
 ○ 手元の検証環境などでは再現していなかった


Slide 26

Slide 26 text

フェーズ3:SQLite + MySQL “Cache” 戦略へ 
 ● SQLiteはマスターデータとして残しつつ、さらにMySQL(MyISAM)を 各サーバのローカル環境に立てて、そこをCache&全文検索エンジ ンとして利用
 ● SQLiteのSync機構に追加して、ローカルのMySQLにCacheを非同 期にCacheを展開する機能を実装
 ○ SQLiteに対して直接クエリーを投げないので、先の全文検索が 正しく動作しない問題は解消
 ○ ローカルに設置してあるMySQLからデータを取るのでレスポン スタイムも早い


Slide 27

Slide 27 text

フェーズ3:サーバ構成 
 Aurora
 S3
 App
 MySQL
 user.sqlite(v2)
 user.sqlite(v2)
 user.cache
 ユーザデータ等の
 マスターデータ
 ログの
 マスターデータ
 ログデータの
 Cache


Slide 28

Slide 28 text

フェーズ3:Twitter (X) API v2 対応 
 ● 開発中に Twitter(X)API v1.1 の廃止がアナウンスされたため、並 行してTogetter / Twilog の API v2 対応を実施
 ● 一部のAPIが廃止になるなどしていたため、仕様変更などにも対応


Slide 29

Slide 29 text

フェーズ3:デプロイ(2024年3月) 
 
 ● Twitter (X) API v 1.1 の終了が月末に予定されていたため、旧 Twilogは事実上動作しなくなり、タイムリミットとなる
 ● 高速にデプロイするために「ハイスペックなインスタンスを用意して、 そこでCacheの生成を行って都度rsyncする」などのテクニックを要す る
 ○ lsyncd (GitHub) … inotify や fsevents などを活用して「目的の ファイルに対する更新」をリアルタイム検知し、「任意の処理を実 行できる」仕組み


Slide 30

Slide 30 text

フェーズ4:SQLiteの廃止 
 ● Twilogの移行は完了したものの、内部的な課題が残る
 ○ SQLiteのマルチマスター機能は動作しているものの、複数台構成での本番適用がで きていなかった(壊れる可能性が否定できない)
 ○ 結果、ハイスペックなサーバ1台でWebとDBを兼ねて動作させている状態 
 ■ ソースコードデプロイの際も瞬断が避けられない状態に
 ○ 高いサーバコストと高負荷に弱い状態になっており、良い状態ではなかった 
 ● Cache 用 MySQL が安定して動作していることを確認
 ○ Cache的に導入した MySQL on EC2 が、速度・検索性能の面で問題ないことが明ら かになった(ページキャッシュが無くても十分速い!)
 ○ Cacheの役割から昇格しMasterへ、SQLiteを破棄することに 


Slide 31

Slide 31 text

フェーズ4:MySQL on EC2(MyISAM)の運用 
 ● Writer + Reader の2台構成
 ● Reader は定期的に物理バックアップ
 ○ レプリケーションの一時停止
 ○ /var/lib/mysql 配下を zstd 圧縮 + s3 転送
 ● Writer 側の binlog も定期的に s3 バックアップ
 
 ⇒ TB(テラバイト)級のストレージ利用は実現できるのか? 


Slide 32

Slide 32 text

大容量ストレージによる MySQL を d3 / d3en で 実現 
 d3 / d3en には大容量HDD(最小 6TB 、最大 336TB)がインスタンス ストアとして付属する!
 ● 今回は d3en.xlarge (28 TB / 4vCPU / 16GiB)を選択
 ○ 一定期間の binlog を保持して半分程度の使用率
 ○ リザーブドなら 月額 4.6 万円 程度 と現実的
 ● 複数に分割して提供されるので RAID0 などで利用
 ○ 耐障害性がないが、再起動で揮発するインスタンスストアとは 相性が良い(?)


Slide 33

Slide 33 text

フェーズ4:SQLiteの廃止 
 ● キャッシュ用途から独自運用のMySQL(マスター)へと昇格
 ● Togetterが動作しているサーバでTwilogも動かす
 ● サーバも共有になり実質のWebサーバ費用がゼロに
 Togetter Twilog(旧) Twilog(フェーズ2) 運用環境 AWS さくら専用サーバ AWS 言語 PHP Ruby PHP データベース Aurora(MySQL) MySQL Aurora(MySQL)+ MySQL on EC2 DBサーバ AWS さくら専用サーバ AWS

Slide 34

Slide 34 text

フェーズ4:事前の負荷テスト 
 ● 新Twilogで処理しているリクエストを Mirroring して、フェーズ4環境 (Togetter本番)に直接流し込みテスト
 ○ Mirroring は nginx の post_action で実現
 ● TwilogおよびTogetterがそれらのリクエストを受けても、正常に動作 することを事前に確認
 ● 安心して環境切り替えが可能に


Slide 35

Slide 35 text

最終形態
 ● Twilog専用のAuroraも廃止し、Togetterと統合済み
 ● WebサーバもTogetterと共通化済みでTwilog用に動作しているイン スタンスは無し
 ● ログ用独自MySQLサーバは、28TBのストレージがデフォルトで付い ている d3en.xlarge * 2 のみで 月10万円 程度
 


Slide 36

Slide 36 text

反省点
 ● AWS↔さくら間の通信コストの見積もり
 ○ データを取得しにいく処理のコストをデプロイ前に検証、可能ならもっと前もっ てテストし現実的かどうか確認しておくべき
 ○ サーバ間のレイテンシーだけでなく、クエリー結果が大きい場合にどの程度の 遅延になるかも見ておくべきだった
 ● SQLiteの採用
 ○ ストレージコストが安いS3を利用したいという思いが強すぎて、SQLiteを諦め るという発想ができなかった
 ○ 複雑さが増しているにも関わらず、技術や運用でカバーできるという過信があ り、判断を鈍らせた


Slide 37

Slide 37 text

良い点
 ● さくら時代とあまり変わらないコスト感でサービスを運営できている
 ○ 約6万円 -> 約10万円
 ● コードの最新化により新機能の開発にも着手でき、サブスクモデル やアーカイブインポート機能なども開発し、収益性も大幅向上


Slide 38

Slide 38 text

移行完了、おめでとう 


Slide 39

Slide 39 text

サブスク登録、よろしくおねがいします 


Slide 40

Slide 40 text

ご清聴ありがとうございました