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
内製化を加速させるlaC活用術
nrinetcom
PRO
2
140
遷移の高速化 ヤフートップの試行錯誤
narirou
6
1.1k
実は強い 非ViTな画像認識モデル
tattaka
2
1.2k
AWSではじめる Web APIテスト実践ガイド / A practical guide to testing Web APIs on AWS
yokawasa
7
660
PHPカンファレンス名古屋-テックリードの経験から学んだ設計の教訓
hayatokudou
2
540
Autonomous Database Serverless 技術詳細 / adb-s_technical_detail_jp
oracle4engineer
PRO
17
45k
【Findy】「正しく」失敗できる チームの作り方 〜リアルな事例から紐解く失敗を恐れない組織とは〜 / A team that can fail correctly by findy
i35_267
5
860
【詳説】コンテンツ配信 システムの複数機能 基盤への拡張
hatena
0
230
生成AI×財務経理:PoCで挑むSlack AI Bot開発と現場巻き込みのリアル
pohdccoe
1
630
ExaDB-XSで利用されているExadata Exascaleについて
oracle4engineer
PRO
3
240
Windows の新しい管理者保護モード
murachiakira
0
200
技術スタックだけじゃない、業務ドメイン知識のオンボーディングも同じくらいの量が必要な話
niftycorp
PRO
0
100
Featured
See All Featured
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
Embracing the Ebb and Flow
colly
84
4.6k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
Writing Fast Ruby
sferik
628
61k
StorybookのUI Testing Handbookを読んだ
zakiyama
28
5.5k
Build The Right Thing And Hit Your Dates
maggiecrowley
34
2.5k
Making Projects Easy
brettharned
116
6k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
430
Agile that works and the tools we love
rasmusluckow
328
21k
Code Reviewing Like a Champion
maltzj
521
39k
GitHub's CSS Performance
jonrohan
1030
460k
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はそれなりに高いけどパフォーマンス改善が捗るし、どの部分がボト ルネックになりやすいのか理解が深まるのでおすすめ!
ありがとうございました!