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
APMをちゃんと使おうとしたら、いつのまにか独自gemを作っていた話
Search
kokuyouwind
October 28, 2023
Programming
960
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
APMをちゃんと使おうとしたら、いつのまにか独自gemを作っていた話
Kaigi on Rails 2023 セッションの発表資料です
https://kaigionrails.org/2023/talks/kokuyouwind/
kokuyouwind
October 28, 2023
More Decks by kokuyouwind
See All by kokuyouwind
疑似コードによるプロンプト記述、どのくらい正確に実行される?
kokuyouwind
0
530
謎解きサイトを Rails SPA で作って RubyKaigi で配布した話
kokuyouwind
0
83
ドメイン指定Cookieとサービス間共有Redisで作る認証基盤サービス
kokuyouwind
0
36
Do LLMs dream of Type Inference?
kokuyouwind
0
39
Let's use LLMs from Ruby 〜 Refine RBS types using LLM 〜
kokuyouwind
0
8.4k
RBS meets LLMs - Type inference using LLM
kokuyouwind
0
1k
オンラインボードゲームを作りたい人生だった
kokuyouwind
0
690
1年間本番運用してわかった、スタートアップこそAWS Copilot CLIを使うべきNつの理由
kokuyouwind
2
12k
なるべく楽したいAWSセキュリティ
kokuyouwind
1
120
Other Decks in Programming
See All in Programming
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
壊れたパーサから始める関数型設計と構成的なパーサ
raiga0310
2
140
AI 輔助遺留系統現代化的經驗分享
jame2408
1
1.2k
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
340
Contextとはなにか
chiroruxx
1
390
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
230
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
190
dRuby over BLE
makicamel
2
410
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
240
ECSアプリログをFireLensでコスト削減しようとしたけど諦めた話 in Fargate×Node.js
akihisaikeda
2
4.2k
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
160
Featured
See All Featured
Speed Design
sergeychernyshev
33
1.9k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
My Coaching Mixtape
mlcsv
0
170
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
310
Amusing Abliteration
ianozsvald
1
220
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
260
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
62
55k
GraphQLとの向き合い方2022年版
quramy
50
15k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
The Cult of Friendly URLs
andyhume
79
6.9k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.6k
Transcript
APM をちゃんと使おうとしたら、 いつのまにか独⾃gem を作っていた話 Leaner Technologies, Inc. 黒曜 (@kokuyouwind)
$ whoami 黒曜 / @kokuyouwind Leaner Technologies Inc. 所属 Rails
エンジニア インフラ・SRE 的なこともやっている APM など開発周辺ツールの管理
APM の話をします
APM とは Application Performance Monitoring の略 リクエスト数や応答速度を監視・管理できる 代表的な APM サービス
etc.
APM の導⼊⾃体は結構簡単 https://docs.datadoghq.com/ja/tracing/trace_collection/dd_libraries/ruby/ ⼤抵の APM は エージェントソフトウェアと gem を設定するだけ #
Gemfile gem 'ddtrace', require: 'ddtrace/auto_instrument' # config/initializers/datadog.rb Datadog.configure do |c| c.service = 'my-service' end 1 2 3 4 5 6 7
APM の画⾯例 (1) https://docs.newrelic.com/jp/docs/apm/new-relic-apm/getting-started/introduction-apm/
APM の画⾯例 (2) https://docs.datadoghq.com/ja/tracing/other_telemetry/connect_logs_and_traces/
🤔 すごいけど、何を⾒ればいいの… ?
APM 導⼊後のあるある 導⼊で満⾜して、その後画⾯を開かなくなった 応答速度の遅いエンドポイントを⾒て、 「やっぱりここは重いよね〜」と話して終わる ソースコード上でどこが重いのか、結局わからない 筆者は過去に全部⼼当たりがあります…( ⼩声)
ひとつの参考事例として、 弊社での APM の使い⽅を紹介します
アジェンダ 簡単な APM の使い⽅ トレースを使ったパフォーマンス・チューニング APM Traceable gem を作った話 具体的なチューニング事例紹介
まとめ
アジェンダ 簡単な APM の使い⽅ トレースを使ったパフォーマンス・チューニング APM Traceable gem を作った話 具体的なチューニング事例紹介
まとめ
簡単な APM の使い⽅ ⼤抵の APM は集計単位ごとにページに分かれている サイト全体 エンドポイントごと リクエストごと 最初は「サイト全体」の指標で⼤まかな傾向を⾒ると良い
細かく掘り下げていくときに「エンドポイントごと」 「リクエストごと」の順に⾒ていく
ここから先は Datadog APM を例に スクリーンショットを出します ( 他APM でも同様の画⾯があるはず)
APM の⾒⽅ - 全体の統計
APM の⾒⽅ - 全体の統計
APM の⾒⽅ - 全体の統計 リクエスト数も応答速度も、極端な変化がないか確認 曜⽇や時間帯で傾向が違うため、前週同曜⽇と⽐較する サービスによっては⽉末・年末なども考慮する 異常値があった場合はトリアージする ⼀時的要因であれば様⼦⾒、問題がありそうなら調査・対応
APM の⾒⽅ - 個別エンドポイント
APM の⾒⽅ - 個別エンドポイント
APM の⾒⽅ - 個別エンドポイント
APM の⾒⽅ - 確認タイミング 週1 で「APM を⾒る会」を実施している 悪化傾向を⾒つけられるよう定期的に⾒る機会を作る トリアージもこのタイミングで実施 開発・運⽤に関わるメンバー全員で⼀緒に⾒ると良い
悪化しているエンドポイントに機能追加などの ⼼当たりがあるか確認しやすい
アジェンダ 簡単な APM の使い⽅ トレースを使ったパフォーマンス・チューニング APM Traceable gem を作った話 具体的なチューニング事例紹介
まとめ
重いエンドポイントを改善する際、 リクエストごとのトレースが⾜がかりになる
リクエストごとのトレース 何に時間がかかっているか( スパン) を表示できる DB アクセスやWeb API 呼び出しのスパンを⾃動で収集
N+1 クエリへの対処 SQL クエリを確認し、適切に includes などを設定する 特定条件やデータセットがないと発⽣しないN+1 クエリは bullet gem
などで⾒つけづらいケースがある
重いクエリへの対処 まずは EXPLAIN で実⾏計画を確認する インデックス追加だけで改善することも多い
時間が⾜りないので 詳しいチューニング⼿法は割愛
https://slides.com/kokuyouwind/rails-performance-tuning 詳細は以前の Kaigi on Rails 2020 で話した 「Rails パフォーマンス・チューニング⼊⾨」をご覧ください!
パフォーマンス・チューニングについては 他の⽅も発表されていたのでおすすめです! Rails アプリの 5,000 件の N+1 問題と戦っている話 初めてのパフォーマンス改善〜君たちはどう計測す( はか)
るか〜
アジェンダ 簡単な APM の使い⽅ トレースを使ったパフォーマンス・チューニング APM Traceable gem を作った話 具体的なチューニング事例紹介
まとめ
⾃動トレースは便利だが、 標準のトレースだけだと困るときがある
困るとき 1. SQL の発⾏場所がわからない ActionController スパン直下に SQL クエリのスパンがある 単なるメソッドの呼び出しは標準だとスパンにならない クエリ構築がどのコードで⾏われているかわからないと
修正しようがない ( 重いクエリの例を再掲)
困るとき2 . Ruby での処理が重いケース Ruby 処理は⾃動でスパンに区切られない 原因が全くわからないので対処もできなくなってしまう
⼿動インストゥルメンテーション https://docs.datadoghq.com/ja/tracing/trace_collection/dd_libraries/ruby/ Datadog::Tracing.trace(name, **options) do |span, trace| # 計測したい処理をここに記⼊ end
1 2 3 Datadog では Datadog::Tracing.trace を使って ⼿動でスパンを追加できる 渡したブロック内がスパンとして区切られる
Datadog::Tracing の微妙な使いづらさ # ↓ 標準だとこう書く必要がある class User def awesome_method Datadog::Tracing.trace(
'awesome_method', service: 'my-service', resource: 'User') do # ... 処理 end end end 1 2 3 4 5 6 7 8 9 10 11 処理対象をブロックで囲むとインデントが変わる 差分が⼤きくなって気軽につけ外ししづらい 引数が多く、記述がやや冗⻑
APM Traceable gem # ↓ こう書けるようにした class User include ApmTraceable::Tracer
trace_methods :awesome_method def awesome_method # ... 処理 end end 1 2 3 4 5 6 7 8 9 trace_methods にメソッド名を指定するとスパンとして表示 UseCase やPresenter など、独⾃レイヤークラスの呼び出し 重いメソッドを切り分けたプライベートメソッド
APM Traceable gem 各Presenter#call をtrace_methods した結果
APM Traceable gem 元々は1 モジュールでlib 以下に置いていた 以前 に書いた話 複数プロダクトに必要だったのでgem に切り出した
APM Traceable gem 本体 Datadog への送信⽤アダプタ アダプタを作れば他の APM にも切り替えられるようにした ブログ記事 apm_traceable apm_traceable-datadog
APM Traceable gem - 仕組み module ApmTraceable::Tracer def self.trace_methods(*method_names) wrapper
= Module.new do method_names.each do |method_name| define_method method_name do |*args, **options, &block| trace_span(method_name.to_s) { super(*args, **options, &block) } end end end prepend(wrapper) end end 1 2 3 4 5 6 7 8 9 10 11 12 13 trace_methods で各メソッドを持つモジュールを作り、 prepend して呼び出しをラップするだけ
APM Traceable gem - 仕組み Class User awesome_method prepended Module
awesome_method メソッド呼び出し Datadog Adapter trace_span トレース送信
アジェンダ 簡単な APM の使い⽅ トレースを使ったパフォーマンス・チューニング APM Traceable gem を作った話 具体的なチューニング事例紹介
まとめ
事例 1. SQL クエリの速度悪化 MySQL 8.0 に更新した際、特定エンドポイントだけ遅くなった
事例 1. SQL クエリの速度悪化
事例 1. SQL クエリの速度悪化 テンポラリテーブルでの SELECT COUNT(*) の問題っぽい… https://zenn.dev/hmatsu47/articles/mysql80-count-slowdown
事例 1. SQL クエリの速度悪化 元のクエリが GROUP BY してから最初の⾏を取っており、 実質 DISTINCT
相当の処理がテンポラリテーブルで⾏われていた DISTINCT を使えばテンポラリテーブルを使わなくなるので直した
事例 1. SQL クエリの速度悪化 元々 1.0sec -> 悪化して 4.0sec ->
改善後 100ms 結果的に元の10 倍に⾼速化🚀
事例 2. 外部API 呼び出しのトレース 外部 API を並列で呼び出す箇所のトレースが取れていなかった ( 単独だと取れるが、2 箇所以上Parallel
だと取れない)
事例 2. 外部API 呼び出しのトレース Parallel をまたぐとスパンの親⼦関係が途切れるようなので、 ⼿動で親ダイジェストを引き渡すよう修正 def search_parallel(clients) +
trace_span('search_parallel') do |_span, trace| results = Parallel.map(clients, in_processes: clients.count) do |client| + trace_span(client.name, continue_from: trace.to_digest) do client.search + end end + end end 1 2 3 4 5 6 7 8 9
事例 2. 外部API 呼び出しのトレース この変更で、きれいにトレースが⾒られるようになった 🎉
事例 2. 外部API 呼び出しのトレース トレースを精査したところ、外部API 呼び出しよりも XML レスポンスのパース処理に時間がかかっていた
事例 2. 外部API 呼び出しのトレース ローカルで再現させ、 Stackprof でプロファイルを取ったところ DidYouMean::Jaro.distance が⼤半を占めている… ?
事例 2. 外部API 呼び出しのトレース XML で未知の attribute が出てきた際、 const_get でNameError
が起こる実装になっていた。 const_defined? で確認を挟むよう実装を修正 klass = "CXML::#{camelize(key)}" - send("#{key}=", Object.const_get(klass).new(val)) + send("#{key}=", Object.const_get(klass).new(val)) + if Object.const_defined?(klass) + send("#{key}=", Object.const_get(klass).new(val)) + else 1 2 3 4 5 6
事例 2. 外部API 呼び出しのトレース
事例 2. 外部API 呼び出しのトレース エンドポイントのレスポンスタイムも、 修正を境に⾶び上がった値が出ることがなくなった
アジェンダ 簡単な APM の使い⽅ トレースを使ったパフォーマンス・チューニング APM Traceable gem を作った話 具体的なチューニング事例紹介
まとめ
まとめ APM は本番で起こっている問題を⾒つけるのに便利 統計値を定期的に⾒て、変化に気づけるようにすると良い トレースを⾒ると重い原因を⾒つける⾜がかりになる 重要なメソッドにスパンを仕込んでおくと原因を掘り下げやすい これをやりやすいように独⾃gem を作った トレースで⽬星をつけて、掘り下げた調査を別で⾏うこともある APM
全然使いこなせてないので、いい使い⽅教えてください! 休憩時間や懇親会でお話しましょう
補⾜資料
各 APM での⼿動トレース機能 New Relic add_method_tracer が trace_method とほぼ同等機能 Scout
APM だけで⼗分かもしれない Open Telemetry Ruby カスタムインストゥルメンテーション Custom Instrumentation Auto Instruments Manual Instrumentation