Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

hogelog (小室 直) ● 2013/8 クックパッド株式会社 入社 ○ レシピ投稿関連の開発等(Web, Android) ○ 会員事業関連、OEM 向け API 開発等 (Web, Android) ○ 技術部開発基盤(いろいろ)

Slide 3

Slide 3 text

大きな Rails アプリケーション 開発してますか?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

cookpad_all とは ● cookpad.com を支える複数の Rails アプリと共有ロジック をまとめた shared gem を含むリポジトリ ● cookpad_all 内の各アプリはほとんど共有 DB

Slide 7

Slide 7 text

一昔前のクックパッドの開発風景 ● 大多数の社内エンジニアが 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

Slide 8

Slide 8 text

2016 年頃のクックパッドの開発風景 ● Microservices が進み cookpad_all 以外の開発が増える ● cookpad_all は巨大だし辛い ● cookpad_all は基盤からレガシーな部分が多く整備コストも 高い ○ Microservices 基盤は整っていく ○ クックパッドにおける最近のMicroservices事例 by @adorechic https://techlife.cookpad.com/entry/2016/03/16/100043

Slide 9

Slide 9 text

2017 年、お台場プロジェクト発足 ● @aamine により立ち上げられた cookpad_all 改善プロ ジェクト ● 裏の目標は「開発基盤」というチームの解散 ○ cookpad_all はもうサービス開発チームが高い意識による片手間程度でメ ンテナンスできる規模ではない ○ cookpad_all を徹底的に改善し、普通の開発チームでメンテナンスできる 状態にする

Slide 10

Slide 10 text

お台場プロジェクト やったこと

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

開発メトリクスの定点観測 ● コード量、起動時間などの開発メトリクスを InfluxDB に記 録、Grafana のダッシュボードで定点観測 ○ 大きな Rails アプリケーションをなんとかしよう。まずは計測と可視化からは じめよう。 by @hogelog https://techlife.cookpad.com/entry/2018/06/08/080000

Slide 13

Slide 13 text

CI Duration ● CI にかかった時間

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Code Statistics ● rails stats を記録

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Dependent Gem Count ● 依存 gem 数

Slide 19

Slide 19 text

GemCollector Up-to-date Point ● 依存 gem の最新度 ○ この gem を使っているアプリケーションを探す by @eagletmt https://techlife.cookpad.com/entry/2018/06/08/080000

Slide 20

Slide 20 text

システム削除 ● cookpad_all 内の不要なシステムを削除する ○ 工夫はとくになし

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

api の削除 ● cookpad 内のレガシー HTTP API 機能を削除 ○ 社内でも動作確認不可能な古いモバイルアプリだけから使われていた ○ 関係者、責任者と話を詰めて削除

Slide 23

Slide 23 text

api の削除 ● cookpad のデプロイ先が1個減る(デプロイ先3つ)

Slide 24

Slide 24 text

background worker の削除 ● cookpad 内のレガシー非同期処理システムを削除 ○ resque 製非同期処理基盤 ○ モダン非同期処理基盤としては barbeque が整備されていたので移行 ■ ECS を利用したオフラインジョブの実行環境 by @k0kubun https://techlife.cookpad.com/entry/2016/09/09/235007

Slide 25

Slide 25 text

background worker の削除 ● cookpad のデプロイ先が1個減る(デプロイ先2つ)

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

pantry の分割 ● cookpad と pantry を分割 (cookpad_all 内で) ○ デプロイ先により挙動が変わる不思議なアプリを分割 ○ 本質的に共有するものは多くなかった (切り離しはもちろん大変だった)

Slide 28

Slide 28 text

pantry の分割 ● 1アプリ1デプロイ先という自然な状態に

Slide 29

Slide 29 text

様々な Microservices アプリへの切り出し ● 検索機能、料理きろく API、モバイルアプリ AB テスト用 API、ユーザ認証関連機能、など数々なアプリを cookpad_all から切り出し ○ 切り出す単位は組織構造にフィットする、それでいてひとまとまりになってい て細かすぎないサイズ ■ つまり「ちょうどいいサイズに」

Slide 30

Slide 30 text

様々な Microservices アプリへの切り出し ● 色んな機能群を Microservices アプリ として切り出し

Slide 31

Slide 31 text

mobile の作り直し ● ガラケー向けサイトモバれぴバックエンドのmobile ○ アクティブに開発していないので作り直しのブロッカーがいない ○ モダンな基盤で作り直す ■ Hako (ECS) 環境, gRPC, Service Mesh, ...

Slide 32

Slide 32 text

mobile の作り直し(移行中) ● cookpad_all 内の アプリが4つに

Slide 33

Slide 33 text

コード削除 ● 不要コードを削除する ○ がんばって不要コードを探して削除 ○ Gemfile をジッと眺めて不要 gem を探す ○ lazy loading を利用し不要 gem を検出 ○ 棚卸し Issue の自動作成 ○ Iseq 実行処理を記録し不要コードを探す

Slide 34

Slide 34 text

がんばって不要コードを探して削除 ● 不要コードをがんばって探して削除する ● Code Cleaning Contest を開催 ○ 期間一ヶ月のコード削除コンテスト ○ 掃除にちなんだ豪華景品も

Slide 35

Slide 35 text

棚卸し Issue の自動作成 ● 棚卸し Issue 作成、コード削除うながす作業を(半)自動化 ○ 不要そうなコードを検出しコミッタからランダムにアサインしてコード削除か 必要なコードであるか記録するよう促す ○ 元データはアクセスログ、バッチ処理実行ログ等 ● 削除可否だけ聞いてお台場プロジェクトメンバーが削除する ことも

Slide 36

Slide 36 text

Gemfile をジッと眺めて不要 gem を探す ● Gemfile を見て不要そうな gem を削除 ○ jquery-rjs, aws-sdk-v1, …… ● 工夫特になし

Slide 37

Slide 37 text

lazy loading を利用し不要 gem を検出 ● ruby に手を加え lazy loading 利用し不要 gem を検出 ○ Ruby の lazy loading の仕組みを利用して未使用の gem を探す by @riseshia https://techlife.cookpad.com/entry/2018/04/04/080000

Slide 38

Slide 38 text

Iseq 実行処理を記録し不要コードを探す ● ruby に手を加え Iseq 実行ログを記録し不要コードを探す ○ 本番で記録したログを Redshift に蓄積 ○ 詳細は近日中に @riseshia から techlife かどこかで発表など ○ ruby 2.6 では素の ruby で可能になるかも ■ Feature #15022 Oneshot coverage by @mame https://bugs.ruby-lang.org/issues/15022

Slide 39

Slide 39 text

その他 ● gem の更新 ○ rails, rspec など様々な gem のアップグレード ○ Machinist 1 -> FactoryBot 移行 ○ リポジトリに埋め込まれていた改造 gem を捨てて OSS 最新版に更新 ○ bootsnap の導入 ● ruby アップグレード ● EC2 インスタンスの式年遷宮 (CentOS 6 -> Ubuntu 16)

Slide 40

Slide 40 text

うまく進んでいる要因? ● 「お台場プロジェクト」という名前をつけた ○ 名前があると自分も他人も認識する ● 人をアサインしている ○ メインタスクとして稼働している優秀なエンジニアが何人もいる ● すぐ近くに ruby コミッタが二人いる ○ Iseq 実行ログの記録や lazy loading の活用なんかはガッツリサポートして もらいました

Slide 41

Slide 41 text

まとめ

Slide 42

Slide 42 text

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