Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Ruby on Railsで持続可能な開発を行うために取り組んでいること
Search
akina
March 01, 2025
Technology
3
140
Ruby on Railsで持続可能な開発を行うために取り組んでいること
TokyoWomen.rb #1の登壇資料です。
https://tokyowomenrb.connpass.com/event/342573/
akina
March 01, 2025
Tweet
Share
More Decks by akina
See All by akina
クラシルの現在とこれから
am1157154
1
1.1k
Other Decks in Technology
See All in Technology
OSS構成管理ツールCMDBuildを使ったAWSリソース管理の自動化
satorufunai
0
640
いまからでも遅くない!コンテナでWebアプリを動かしてみよう!コンテナハンズオン編
nomu
0
150
サイト信頼性エンジニアリングとAmazon Web Services / SRE and AWS
ymotongpoo
7
1.5k
1行のコードから社会課題の解決へ: EMの探究、事業・技術・組織を紡ぐ実践知 / EM Conf 2025
9ma3r
10
3.7k
AIエージェント元年
shukob
0
160
技術スタックだけじゃない、業務ドメイン知識のオンボーディングも同じくらいの量が必要な話
niftycorp
PRO
0
100
php-conference-nagoya-2025
fuwasegu
0
150
システム・ML活用を広げるdbtのデータモデリング / Expanding System & ML Use with dbt Modeling
i125
1
320
Active Directory攻防
cryptopeg
PRO
8
5.4k
Share my, our lessons from the road to re:Invent
naospon
0
140
ABWG2024採択者が語るエンジニアとしての自分自身の見つけ方〜発信して、つながって、世界を広げていく〜
maimyyym
1
140
Oracle Database Technology Night #87-1 : Exadata Database Service on Exascale Infrastructure(ExaDB-XS)サービス詳細
oracle4engineer
PRO
1
170
Featured
See All Featured
Unsuck your backbone
ammeep
669
57k
The Cost Of JavaScript in 2023
addyosmani
47
7.4k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
430
Bash Introduction
62gerente
611
210k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
29
1k
Six Lessons from altMBA
skipperchong
27
3.6k
RailsConf 2023
tenderlove
29
1k
How GitHub (no longer) Works
holman
314
140k
Agile that works and the tools we love
rasmusluckow
328
21k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Designing for humans not robots
tammielis
250
25k
Transcript
Akina Matsushima 2025/03/01 TokyoWoman.rb #1 Ruby on Railsで 持続可能な開発を行うために 取り組んでいること
松嶋 瑛奈 (Matsushima Akina) dely株式会社 バックエンドエンジニア • 2019/11~: 現職にSREとして入社 •
2022/10~: バックエンドエンジニアに転向 • Ruby/Rails歴3年目 💎 • Kaigi on Rails 2024のスポンサーLTが初登 壇、 今回で2回目です! 📣 自己紹介 @25_aaa 3 @akingo55
None
None
今回のテーマは、「持続可能な開発」
持続可能な開発? 🤔
プロダクトの性質やフェーズにあわせて、 「品質」と「開発速度」のバランスを取る こと
バランスを取りやすくするためには、 どうすればいいのか?
不要な複雑さを減らし、ソフトウェアを 「単純」にすること
今日話すこと 1. デッドコードを定期的に削除している話 2. Datadog APMを用いてパフォーマンス改善している話 💡 9年目を迎えたRailsアプリケーションを運用する中で、私たちがソフト ウェアを「単純」にするために取り組んできた2つのことについて話します。
1.デッドコードの削除 🧹
消そう。以上。 実行されないコードは消すだけだ。 引用:「Tidy First? 2章 デッドコー ド」
なぜ不要なコードが蓄積されてしまうのか? • 時間を捻出できない ⏰ ◦ 普段は機能開発に追われているため、改善系のタスクに着手する時間がとれない ◦ 改善チームやPjTを立ち上げられたらいいが、そもそも人手不足 • 後回しにして忘れ去られてしまう
◦ とりあえずバックログに入れるが、優先度低くて一生やらないタスクになる ◦ そして忘却の彼方に • そういう文化がない 😢 ◦ 機能開発こそが価値を生むものだなど、運用を軽視する文化が根強いと放置されがち ◦ 誰かが声を上げない or 障害が起きて大惨事にならない限り変わらない
私たちの解決策 • 時間を捻出できない ⏰ or 後回しにして忘れ去られてしまう ◦ 機能開発が落ち着く年末に、早めにコードフリーズして時間つくる(去年は12/19) ◦
高頻度である必要はないし、年に1回程度だと調整・説得しやすい ◦ 誰でも運用を回せるように、あらかじめ削除フローは整備しておく ◦ 年1回のコードの大掃除としてイベント化する ▪ 「年末 = 大掃除」のイメージがあるので定着しやすい • そういう文化がない 😢 ◦ 一朝一夕で文化は変わらない ◦ 強い気持ちで、根気強く地道に浸透させていくしかない
どのような手段を使うか? • 動的解析ツールを使って、プロダクションコードの使用率を計測す る (ex. coverband) • 静的解析ツールを使って、ソースコードから使われていないメソッ ドやクラスを抽出する(ex. debride)
• プロダクション環境のアクセスログからAPI単位で不要なコードを抽 出する
どのような手段を使うか? • 動的解析ツールを使って、プロダクションコードの使用率を計測す る (ex. coverband) • 静的解析ツールを使って、ソースコードから使われていないメソッ ドやクラスを抽出する(ex. debride)
• 👉プロダクション環境のアクセスログからAPI単位で不要なコード を抽出する 既存のログ基盤を活用できること && 年1回の運用なので運用コストが 一番少ない方法を選択
何を消していくのか? • サポート対象外のバージョンで使われていたモバイルのAPI • 機能として既に存在しないWebのAPI • 誰も使わなくなった社内の管理サイトの機能 ◦ 1年以上アクセスがないページや使われた痕跡がない機能は基本的に削除する •
運用が既に止まっているrakeタスク • 不要なバッチ処理 ◦ 効果の薄いプッシュ通知、誰も見ていないSlack通知 etc.
削除フロー例 1. 現在使われているAPIのパスとメソッド一覧をペアにしてCSV形式で出力 a. モバイルAPIはモバイルエンジニアに依頼する b. アクセスログから抽出する 2. ActionDispatch::Routingで出力したルーティング一覧と照らし合わせ る
※削除対象のAPIを抽出するスクリプトをチームで使い回せるようにしてい るが、年1回の実施なので完全自動化まではしていない
コードの大掃除の効果 • 毎年1万弱のコードが削除されている ◦ 2024年は約9200行削除できた 🎉 ◦ 年1運用なので、負担も少なく継続しやすかった • CIの時間が短くなる
◦ CIの時間を短縮するTipsは様々あるが、コード削除だけでも1分以上短くできる • 年末早めのコードフリーズで、運用や改善タスクを実施する時間も割 けるようになった ◦ gemのバージョンアップ ◦ APIのパフォーマンス改善 ◦ 後回しにしていたアプリケーションエラーの解消等
2. パフォーマンス改善 💨
そもそも何でパフォーマンスを改善するのか? 理由は以下の3つしかないと言われている 1. 顧客体験を向上させる 2. 運用コストを減らす 3. トラフィック増加による障害を防ぐ 引用:「Ruby on
Rails パフォーマンスアポクリファ 第1章」 • 現代のWebアプリケーションは、高速であることが「当たり前」 • Googleの研究によると、検索結果の表示が100ms~400ms遅くなるだけ で0.2~0.6%の利用ユーザーが減少したと報告されている 引用:https://research.google/blog/speed-matters/
パフォーマンス改善のお作法 • 推測するな、計測せよ && まずボトルネックを解消せよ ◦ APMを導入し、トレースデータを活用すると改善が捗りやすい(Datadog, NewRelic etc.) ◦
パフォーマンスの良し悪しを判断する指標があるとベター(SLOなど) • ダッシュボードを作成し、パフォーマンスを可視化する ◦ 作っておしまいにならないことが大事!!! ◦ 弊社の場合 ▪ 週次のサーバーサイド定例でダッシュボードを眺める時間を確保 ▪ 短期と長期の観点で見て異変がないか ▪ 改善が必要と判断されたものはチーム単位で改善タスクとして積む
効果的にパフォーマンスを改善するには? 🌟 最もユーザー体験の改善に繋がるものから順番に改善していく! どんな指標をもとに判断すればいい? • 99パーセンタイル値のレイテンシが悪い順? • リクエスト数✕平均レイテンシの値が悪い順?
個人的におすすめなやり方 • レイテンシの閾値を設定し、エン ドポイントごとにこの閾値を超え た回数をカウントする • その回数が最も多いエンドポイン トから改善していく • ユーザーに負の体験を与えている
ものから効果的に改善できる 実際のDatadogのダッシュボードから抜 粋
実際の改善事例の紹介 🐶
事例①:eager_loadの罠 • ページングありで取得するレコード数も制限されている • N+1対策のためのeager loadもしていて問題なさそう ・・・? • 早いときもあるし遅いときもあるぞ
事例①:eager_loadの罠 • レシピに紐づくユーザーのレーティングに関するレコードが膨大 になっていた • 人気なレシピの場合、レーティングが数万件ついてることも ・・・ 👈 犯人!
事例①:eager_loadの罠 • SQL実行時に ActiveSupport::Notifications経由で instantiation.active_recordイベントを取 得しているので、トレースデータのスパンタグ にセットされる • SQLの実行には取得レコード数が増えても 0.1s以下だが、ActiveRecordはインスタン
ス化するのに時間がかかってしまう
事例①:改善方法 UserRatingはリアルタイムに取得する必要はないので、recipesテーブル にuser_rating_countカラムを追加、バッチ処理で更新するスタイルに変 更 • その結果、P99の値が平均して1/10まで減少した 👏 • includesメソッドは便利で容易に使いがちだが、取得されるレコー ド数も考慮にいれないとパフォーマンスに影響する
✏
事例②: IN演算子の使い方には気を付けよう • あれ、謎の空白が目立つな? • トレースデータに何も表示されず、何が起きてるのか分からない • 発行されているSQLはINNER JOINしているな •
SQLも改善できそうだけど、空白の部分の時間が長すぎるぞ
事例②: IN演算子の使い方には気を付けよう ①で取得したIDを②のクエリのIN演算子に渡しているので、インスタンス化する時に オーバーヘッドが生じてそう 🤢(JOINするとトレースに表示されない ⚠) ① ② IN演算子に大量のIDが渡っ てきているこれは・・・
😇
事例②: IN演算子の使い方には気を付けよう • 初期からある内部リンク用API で、ロジックの見直しは今まで されていなかった • 記事に関連するレシピを取得し ているが、MIN_LIMITだけ決 めて、MAX値を決めてなかった
のでIN演算子に大量のIDを渡し てしまっていた • IN演算子も大量の要素を渡して しまうと、インデックスが使わ れずフルスキャンが走る可能性 があるので注意!
事例②: 改善方法 IN演算子に渡すID数に制限を設け、オーバーヘッドをなくす 全体で見ると1/10、クエリの速度は1/20まで改善 🎉 ① ②
事例③:効果的なインデックス貼れてないかも・・・ • 複数のテーブルをINNER JOINいるが、最適なインデックスが存在していな いことで、非常に遅いクエリが実行されていた 😇
事例③:効果的なインデックス貼れてないかも・・・ • explainで実行計画見ると、一番 カーディナリティの低いインデック スが使用されていた • そのインデックスは消去法で選択さ れており、他に使われている箇所は なく、有用なインデックスではな かった
• sys.schema_index_statisticsで インデックス使用率見れるよ (MySQL)
事例③:改善方法 • 不要なインデックスは削除し、WHERE句で指定されているカラムで複合インデッ クスを貼ることで改善した(2.61s → 347ms) • 複合インデックスは左から順に使われるので、WHERE句に指定する順番には注意 ⚠(leftmost prefixルール)
• Railsだとscope使うときにインデックスがどう貼られているか気をつけると
改善結果 • 他にもエンドポイントごとに様々な改善を実施した ◦ APIのレスポンスデータは余分なものを減らし、必要最低限なものだけ 返すようにしたり ◦ 過剰に発行されているクエリを削減したり ◦ 過度なDRYによって、非効率なクエリが発行されているコードを最適
化したり etc. • 最終的に、全体のP99.9の値が800-900msから300ms台まで減らせた 🎉
まとめ • プロダクトの品質と開発速度のバランスを取ることは難しいですが、ソフ トウェアを単純にしていくことで、両者のバランスは実現可能 • 単純さの追求は、Railsアプリケーションを安全に楽しく開発できること にもつながるよ • そのための手段として、「デッドコードの削除」や「パフォーマンス改 善」を効果的に行うための事例を紹介しました
• 年末のコードのお掃除会、おすすめなのでぜひ! • APMはそれなりに高いけどパフォーマンス改善が捗るし、どの部分がボト ルネックになりやすいのか理解が深まるのでおすすめ!
ありがとうございました!