クックパッドの巨大 Rails アプリケーションの改善

8313c7d2124a05b77483f1535915ecdb?s=47 hogelog
September 12, 2018

クックパッドの巨大 Rails アプリケーションの改善

8313c7d2124a05b77483f1535915ecdb?s=128

hogelog

September 12, 2018
Tweet

Transcript

  1. クックパッドの巨大 Rails アプリケーションの改善 クックパッド株式会社 技術部開発基盤 @hogelog (小室直)

  2. hogelog (小室 直) • 2013/8 クックパッド株式会社 入社 ◦ レシピ投稿関連の開発等(Web, Android)

    ◦ 会員事業関連、OEM 向け API 開発等 (Web, Android) ◦ 技術部開発基盤(いろいろ)
  3. 大きな Rails アプリケーション 開発してますか?

  4. クックパッドでは 巨大 Rails アプリケーションを どう改善しているか

  5. 巨大 Rails アプリケーション リポジトリ cookpad_all の今昔

  6. cookpad_all とは • cookpad.com を支える複数の Rails アプリと共有ロジック をまとめた shared gem

    を含むリポジトリ • cookpad_all 内の各アプリはほとんど共有 DB
  7. 一昔前のクックパッドの開発風景 • 大多数の社内エンジニアが cookpad_all で開発する状況 • 開発基盤、インフラのリソースも cookpad_all に集中 ◦

    強いモノリシック Rails アプリの時代 ◦ The Recipe for the World's Largest Rails Monolith by @a_matsuda https://speakerdeck.com/a_matsuda/the-recipe-for-the-worlds-largest-rails-monolith
  8. 2016 年頃のクックパッドの開発風景 • Microservices が進み cookpad_all 以外の開発が増える • cookpad_all は巨大だし辛い

    • cookpad_all は基盤からレガシーな部分が多く整備コストも 高い ◦ Microservices 基盤は整っていく ◦ クックパッドにおける最近のMicroservices事例 by @adorechic https://techlife.cookpad.com/entry/2016/03/16/100043
  9. 2017 年、お台場プロジェクト発足 • @aamine により立ち上げられた cookpad_all 改善プロ ジェクト • 裏の目標は「開発基盤」というチームの解散

    ◦ cookpad_all はもうサービス開発チームが高い意識による片手間程度でメ ンテナンスできる規模ではない ◦ cookpad_all を徹底的に改善し、普通の開発チームでメンテナンスできる 状態にする
  10. お台場プロジェクト やったこと

  11. お台場プロジェクトでやったこと • 開発メトリクスの定点観測 • システム削除 • システム分割 • コード削除 •

    その他
  12. 開発メトリクスの定点観測 • コード量、起動時間などの開発メトリクスを InfluxDB に記 録、Grafana のダッシュボードで定点観測 ◦ 大きな Rails

    アプリケーションをなんとかしよう。まずは計測と可視化からは じめよう。 by @hogelog https://techlife.cookpad.com/entry/2018/06/08/080000
  13. CI Duration • CI にかかった時間

  14. App Load Time • アプリのロードにかかった時間

  15. Code Statistics • rails stats を記録

  16. 2017-07-01 時点の stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC

    | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 55217 | 44464 | 619 | 4505 | 7 | 7 | | Helpers | 16853 | 13810 | 21 | 1582 | 75 | 6 | | Models | 95824 | 75336 | 1892 | 8854 | 4 | 6 | | Mailers | 2011 | 1612 | 45 | 199 | 4 | 6 | | Workers | 841 | 712 | 25 | 40 | 1 | 15 | | Chanko units | 8656 | 7160 | 2 | 169 | 84 | 40 | | Libraries | 50869 | 42003 | 660 | 3779 | 5 | 9 | | Feature specs | 58694 | 47269 | 0 | 189 | 0 | 248 | | Request specs | 56536 | 48938 | 0 | 24 | 0 | 2037 | | Routing specs | 544 | 437 | 0 | 0 | 0 | 0 | | Controller specs | 63233 | 52246 | 6 | 123 | 20 | 422 | | Helper specs | 5318 | 4389 | 1 | 10 | 10 | 436 | | Model specs | 91372 | 75504 | 5 | 85 | 17 | 886 | | Worker specs | 1150 | 954 | 0 | 1 | 0 | 952 | | Chanko unit specs | 7845 | 6293 | 0 | 8 | 0 | 784 | | Library specs | 26156 | 21905 | 23 | 123 | 5 | 176 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 541119 | 443032 | 3299 | 19691 | 5 | 20 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 185097 Test LOC: 257935 Code to Test Ratio: 1:1.4
  17. 2018-09-12 時点の stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC

    | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 32080 | 25883 | 305 | 2690 | 8 | 7 | | Helpers | 13212 | 10739 | 17 | 1214 | 71 | 6 | | Models | 73703 | 58028 | 1282 | 6540 | 5 | 6 | | Mailers | 1663 | 1336 | 38 | 165 | 4 | 6 | | Workers | 0 | 0 | 0 | 0 | 0 | 0 | | Chanko units | 6154 | 5142 | 2 | 147 | 73 | 32 | | Libraries | 33604 | 28014 | 373 | 2449 | 6 | 9 | | Feature specs | 43505 | 34908 | 0 | 176 | 0 | 196 | | Request specs | 809 | 637 | 0 | 0 | 0 | 0 | | Routing specs | 406 | 328 | 0 | 0 | 0 | 0 | | Controller specs | 48137 | 39729 | 2 | 76 | 38 | 520 | | Helper specs | 4151 | 3430 | 0 | 9 | 0 | 379 | | Model specs | 63788 | 52339 | 2 | 52 | 26 | 1004 | | Worker specs | 0 | 0 | 0 | 0 | 0 | 0 | | Chanko unit specs | 2961 | 2359 | 0 | 1 | 0 | 2357 | | Library specs | 16383 | 13588 | 17 | 86 | 5 | 156 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 340556 | 276460 | 2038 | 13605 | 6 | 18 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 129142 Test LOC: 147318 Code to Test Ratio: 1:1.1
  18. Dependent Gem Count • 依存 gem 数

  19. GemCollector Up-to-date Point • 依存 gem の最新度 ◦ この gem

    を使っているアプリケーションを探す by @eagletmt https://techlife.cookpad.com/entry/2018/06/08/080000
  20. システム削除 • cookpad_all 内の不要なシステムを削除する ◦ 工夫はとくになし

  21. 2017 年当初の cookpad_all 構成 • cookpad というアプリが特に厳しい(1アプリでデプロイ先4つ)

  22. api の削除 • cookpad 内のレガシー HTTP API 機能を削除 ◦ 社内でも動作確認不可能な古いモバイルアプリだけから使われていた

    ◦ 関係者、責任者と話を詰めて削除
  23. api の削除 • cookpad のデプロイ先が1個減る(デプロイ先3つ)

  24. background worker の削除 • cookpad 内のレガシー非同期処理システムを削除 ◦ resque 製非同期処理基盤 ◦

    モダン非同期処理基盤としては barbeque が整備されていたので移行 ▪ ECS を利用したオフラインジョブの実行環境 by @k0kubun https://techlife.cookpad.com/entry/2016/09/09/235007
  25. background worker の削除 • cookpad のデプロイ先が1個減る(デプロイ先2つ)

  26. システム分割 • システムを正しく分割する • DB 共有はしない。アプリ間は API でやりとりする

  27. pantry の分割 • cookpad と pantry を分割 (cookpad_all 内で) ◦

    デプロイ先により挙動が変わる不思議なアプリを分割 ◦ 本質的に共有するものは多くなかった (切り離しはもちろん大変だった)
  28. pantry の分割 • 1アプリ1デプロイ先という自然な状態に

  29. 様々な Microservices アプリへの切り出し • 検索機能、料理きろく API、モバイルアプリ AB テスト用 API、ユーザ認証関連機能、など数々なアプリを cookpad_all

    から切り出し ◦ 切り出す単位は組織構造にフィットする、それでいてひとまとまりになってい て細かすぎないサイズ ▪ つまり「ちょうどいいサイズに」
  30. 様々な Microservices アプリへの切り出し • 色んな機能群を Microservices アプリ として切り出し

  31. mobile の作り直し • ガラケー向けサイトモバれぴバックエンドのmobile ◦ アクティブに開発していないので作り直しのブロッカーがいない ◦ モダンな基盤で作り直す ▪ Hako

    (ECS) 環境, gRPC, Service Mesh, ...
  32. mobile の作り直し(移行中) • cookpad_all 内の アプリが4つに

  33. コード削除 • 不要コードを削除する ◦ がんばって不要コードを探して削除 ◦ Gemfile をジッと眺めて不要 gem を探す

    ◦ lazy loading を利用し不要 gem を検出 ◦ 棚卸し Issue の自動作成 ◦ Iseq 実行処理を記録し不要コードを探す
  34. がんばって不要コードを探して削除 • 不要コードをがんばって探して削除する • Code Cleaning Contest を開催 ◦ 期間一ヶ月のコード削除コンテスト

    ◦ 掃除にちなんだ豪華景品も
  35. 棚卸し Issue の自動作成 • 棚卸し Issue 作成、コード削除うながす作業を(半)自動化 ◦ 不要そうなコードを検出しコミッタからランダムにアサインしてコード削除か 必要なコードであるか記録するよう促す

    ◦ 元データはアクセスログ、バッチ処理実行ログ等 • 削除可否だけ聞いてお台場プロジェクトメンバーが削除する ことも
  36. Gemfile をジッと眺めて不要 gem を探す • Gemfile を見て不要そうな gem を削除 ◦

    jquery-rjs, aws-sdk-v1, …… • 工夫特になし
  37. lazy loading を利用し不要 gem を検出 • ruby に手を加え lazy loading

    利用し不要 gem を検出 ◦ Ruby の lazy loading の仕組みを利用して未使用の gem を探す by @riseshia https://techlife.cookpad.com/entry/2018/04/04/080000
  38. Iseq 実行処理を記録し不要コードを探す • ruby に手を加え Iseq 実行ログを記録し不要コードを探す ◦ 本番で記録したログを Redshift

    に蓄積 ◦ 詳細は近日中に @riseshia から techlife かどこかで発表など ◦ ruby 2.6 では素の ruby で可能になるかも ▪ Feature #15022 Oneshot coverage by @mame https://bugs.ruby-lang.org/issues/15022
  39. その他 • gem の更新 ◦ rails, rspec など様々な gem のアップグレード

    ◦ Machinist 1 -> FactoryBot 移行 ◦ リポジトリに埋め込まれていた改造 gem を捨てて OSS 最新版に更新 ◦ bootsnap の導入 • ruby アップグレード • EC2 インスタンスの式年遷宮 (CentOS 6 -> Ubuntu 16)
  40. うまく進んでいる要因? • 「お台場プロジェクト」という名前をつけた ◦ 名前があると自分も他人も認識する • 人をアサインしている ◦ メインタスクとして稼働している優秀なエンジニアが何人もいる •

    すぐ近くに ruby コミッタが二人いる ◦ Iseq 実行ログの記録や lazy loading の活用なんかはガッツリサポートして もらいました
  41. まとめ

  42. まとめ • とにかく不要なコードを消したり分割したり、やっていってま す • まだまだ「ふつうの Rails アプリケーション」とは言えないの でチャレンジはいっぱい残されている