Slide 1

Slide 1 text

出張!Railsウォッチ
 in 銀座Rails#35
 森 雅智 / @morimorihoge 2021/07/30 1
 特集:~何かと便利なActiveSupport::Instrumentation~


Slide 2

Slide 2 text

About Me
 ● 森 雅智: @morimorihoge
 ● BPS株式会社でRailsの受託開発チームをやってたり、週1大学非常勤で Web開発を教えてたりします
 ● Ruby/Rails歴は11年くらい。Web開発は17年くらい
 ● 銀座Ralis #10でActiveRecordでVIEWを使おうという話をしました
 ● 銀座Rails #27でアプリケーションコンフィグの話をしました
 About BPS & TechRacho
 ● Web受託開発や電子書籍製品開発をやっている会社です
 ● TechRachoという自社技術Blogを運営しています
 ○ 5年ほど前から平日毎日更新してます
 ○ https://techracho.bpsinc.jp/ ● お仕事相談、転職相談、TechRachoへのご意見など気軽にどうぞ
 ○ https://www.bpsinc.jp/ 2


Slide 3

Slide 3 text

Railsウォッチとは?
 技術ブログTechRachoで毎週連載しているRails / Ruby界隈を中 心とした雑多な情報を提供する技術雑談マガジン
 3


Slide 4

Slide 4 text

これまでの出張Railsウォッチのピックアップテーマ
 ● 銀座Rails#12: 複数DB対応
 ● 銀座Rails#13: ActionText、Trix
 ● 銀座Rails#14: ActionMailbox
 ● 銀座Rails#15: production、development、staging環境について
 ● 銀座Rails#16: 機能開発の設計レビューについて
 ● 銀座Rails#17: リソース管理スコープについて
 ● 銀座Rails#19: 開発チームの冗長化について
 ● 銀座Rails#20: Excelと仲良くしよう
 ● 銀座Rails#21: 標準仕様を読むためのABNF
 ● 銀座Rails#22: CLIプログラムにOptionParserを使う
 ● 銀座Rails#23: ActiveRecordのSELECTベンチマーク
 ● 銀座Rails#24: 令和Devise事情
 ● 銀座Rails#28: 2020年の銀座Railsを振り返る
 ● 銀座Rails#29: Serverless Railsを試す
 ● 銀座Rails#30: Railsインフラ環境Overview
 ● 銀座Rails#31: Railsプロジェクトあるある
 ● 銀座Rails#32: MimeMagic騒動を振り返る
 ● 銀座Rails#33: Rails 7.0で入る予定の新機能(暫定版)
 ● 銀座Rails#34: もっとDBコメントを書こう
 4
 各回資料に興味がある方はこちらからどうぞ:https://speakerdeck.com/morimorihoge 


Slide 5

Slide 5 text

何かと便利なActiveSupport::Instrumentation
 5


Slide 6

Slide 6 text

ActiveSupport::Instrumentation
 ● Rails標準のPubSub(publisher/subscriber)ライブラリ
 ● パフォーマンス計測やデバッグ中心に使われている
 ● 便利な割に思ったより有効に活用されていない気がするので紹介
 6


Slide 7

Slide 7 text

PubSubとは?
 ● 基本の役割
 ○ Publisher: Event配信する人
 ○ Subscriber: Eventを受信したい人 
 ○ Event: やり取りしたい情報。メッセージと呼ぶこともある 
 ● PublisherはいつでもEventを配信できる
 ○ 購読しているSubscriberはいないかもしれないし、複数いるかもしれないが気にしない 
 ● SubscriberはいつでもEventを受信開始・解除できる
 ○ 流れてくるEventはないかもしれないが、気にしない 
 7
 Redis、AWS SNS、Google Cloud Pub/Subなど色々な所で使われている設計モデル 


Slide 8

Slide 8 text

トピック型PubSubシステム(AS::Instrumentation)
 ● トピック型ではPublisherがEventをどのchannelに流すかを決める
 ● Subscriberはchannelを指定してsubscribeし、流れてきたEventを受信する
 8
 ※コンテンツ型の場合はEventの仕分けをSubscriberが行う点が異なる 


Slide 9

Slide 9 text

AS::Instrumentsの利用例
 9
 channel名
 channel名
 eventのpayload


Slide 10

Slide 10 text

ActiveSupport::Notifications::Event
 AS::Notifications.subscribeのブロック引数に渡されるオブジェクト
 10
 元々パフォーマンス計測に使われている機能のため、instrumentにかかった時間を #durationで高精度に取ることもできる


Slide 11

Slide 11 text

Regex指定によるchannel subscribe
 11
 ginza35で始まる全てのchannelを受信
 正規表現でchannel subscribe


Slide 12

Slide 12 text

AS::Instrumentationの使い方まとめ
 ● AS::Notifications.subscribe(channel)で購読したいchannelを指定 し、ブロックにやらせたい処理を仕込んでおく
 ○ channelには正規表現も指定可能 
 ● AS::Notifications.instrument(channel, payload)でイベントを送 信する
 12
 これだけ!とてもシンプル 👍


Slide 13

Slide 13 text

ここから本編
 Railsにはあちこちにinstrumentが仕込んである
 ● [Edge Guide] https://edgeguides.rubyonrails.org/active_support_instrumentation.html#rails-framework-hooks 
 ● [日本語Guide] https://railsguides.jp/active_support_instrumentation.html 
 13
 眺めてみるとRailsのログに出ているような情報が取れることがわかる
 ※実際にはAS::LogSubscriberを使ってEventをログ出力用に整形している。詳しくは Railsのソースコードを読もう


Slide 14

Slide 14 text

例:でかい処理の中で実行されているSQLだけ取り出す
 このサービスクラス、何やってるかよくわからんのでとりあえず実行されてるSQLだけで も眺めてみるか・・・
 14
 ※sql.activerecord Eventのsqlはプレースホルダ化されているので、実際には:bindsも見ない とクエリ内に埋め込まれた値は分からないのに注意
 unsubscribeすればそれ以後は受信しない


Slide 15

Slide 15 text

例:特定のメール送信時にSlack通知したい
 15
 ※同期実行されるので、フロントから#deliver_now送信している場合などにはパフォーマンス に影響が出る可能性あり
 slack-notifier gemについては略


Slide 16

Slide 16 text

Gemの例:Rack::Attack
 IPアドレスやAPIコール数制限などで良く使われるRack::AttackはInstrumentation対応
 16
 APIコール数制限に達したログを記録したい 、などのケースをカバーすることができる 


Slide 17

Slide 17 text

自分でinstrumentを定義して使う
 ● 今すぐは使わないけど、後々このイベントは取得できるようにしたくなりそう
 ● デバッグの時だけ簡単に情報を拾えるようにしたいけど、普段はOFFにしておきたい
 ● Loggerに出すと他の大量のログと混じってしまうので、個別にイベントとして取得したい
 ● Datadog他のAPMツールで扱うアプリケーションイベントを定義・出力したい
 17
 それAS::Instrumentationでできるよ(ドヤァ
 ロジックコードの中にprintデバッグコードを入れると入れたり消したりが大変だが、 AS::Instrumentationならsubscriberを付け外しするだけで良い
 ※環境変数によってON/OFFするようなコードもsubscribeするところだけでOK


Slide 18

Slide 18 text

AS::Instrumentation使用上の注意点
 ● channel名はRailsアプリケーション全体でglobalなので、名前の衝突に注意
 ● instrumentメソッドの呼び出しはsubscriberの有無によらず発生するので、payload に渡すオブジェクト整形処理はパフォーマンスに悪影響を与える可能性がある
 ● subscriberブロックの呼び出しは同期処理なので、重い処理を書くのは危険
 ○ 非同期系クラウド系Pub/Subサービスのつもりで使うと危険 
 ○ きちんとやるならsubscriberブロックで非同期Jobを投入するような工夫が必要 
 ● あくまで1プロセス内でのpubsubなので、リクエストを跨いだ処理には使えない
 ○ ActionCableでは複数WebSocketを跨いだpub/subにRedisのpubsub機能を使うように推奨されてい る
 18


Slide 19

Slide 19 text

まとめ
 ● ActiveSupport::Instrumentationを使うとRails標準搭載の機能でPub/Subすることが できる
 ● あらかじめHookしておきたいような処理に#instrumentを仕込んでおくことで、必要 になったときに#subscribeして利用することができる
 ● どこで何回呼び出される分からない処理に対して予めHookを仕込んでおくような使 い方ができるので、コードのデバッグや障害調査に有用
 19


Slide 20

Slide 20 text

次回以降もブラッシュアップしていきます
 感想・リクエストなどあればTwitter
 #ginzarails
 @morimorihoge
 @hachi8833
 までお声かけください
 20