Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ: Rubygems.orgのAPIキーに権限スコープが追加、RailsのDBパフォーマンス改善ほか(20220209後編)

こんにちは、hachi8833です。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙏

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗Ruby

🔗 BrakemanとRuby 2.6のEOL

gems/brakeman-5.2.0/lib/brakeman/warning.rb:251:in `sprintf': can't convert nil into Integer (TypeError)

つっつきボイス:「ruby-jp Slackで見かけました」「BrakemanがRuby 2.6のEOL(End of Life: サポート終了)のwarningでエラーになったのか」「BrakemanはCIで動かすことが多いので、いきなりCIがクラッシュしたらびっくりするでしょうね」

このissueはBrakeman 5.2.1で修正されました↓。

🔗 Rubyのメモリフットプリント


つっつきボイス:「これもruby-jp Slackで見かけました」「全般にRubyのバージョンが新しくなるとじわじわメモリフットプリントが増えてますね」

他言語のメモリフットプリントセクションも興味深い」「Pythonのフットプリントが意外に小さいですね」「一番フットプリントがでかいのはNode.js」「JavaのOpenJDKが大きいのはしょうがない感があるけど、それよりNode.jsが大きいのが謎」「こうしてみるとdashとかtcshのフットプリントは圧倒的に小さいな〜、使いたくないけど😆」

🔗 Puma 5.6がリリース(Ruby Weeklyより)


つっつきボイス:「新しいPuma、もうインストールしましたよ」「早い」「Changelogをチェックして、CIが落ちなければ即インストールですね: こういうのはコツコツやっておかないと古いままになって後になるほどアップデートがつらくなるので」「そうですよね」「Changelogがたまってくるとつらいんですよ...」

🔗 Rubygems.orgにAPIキーで権限スコープが指定可能になった


つっつきボイス:「Rubygems.orgにまた新しい機能が入ったそうです」「おぉ、APIキーを生成するときに特定権限を付与できるようになったんですね: これによってリスクを下げやすくなるし、gemの権限や作業の一部を他の人に移譲しやすくなる👍」


後で見てみると、以下のスコープを指定して(複数指定可)APIキーを発行できるようになっていますね。

  • Index rubygems
  • Push rubygem
  • Yank rubygem
  • Add owner
  • Remove owner
  • Access webhooks
  • Show dashboard

🔗DB

🔗 Railsのデータベースパフォーマンスのテストと最適化(Ruby Weeklyより)


つっつきボイス:「よくある記事っぽいですが、AppSignalの記事なので何か新しい知見があるかなと思って取り上げてみました」

「データベースのパフォーマンスは、既に遅くなっている場合と遅くなりそうな場合で取り組み方が違ってくるので注意が必要です」

「1.のN+1対応、2.のインデックス設定とかはクエリのExplainなどで普通にやるやつ」「3.は自社のAppSignalでRailsアプリのパフォーマンスを測定しようとありますね」「AppSignalってどんなサービスでしたっけ?」「たしかNewRelicのようなアプリケーションパフォーマンス監視(APM)などいろいろやっているはず」

参考: AppSignal for Ruby | AppSignal documentation

🔗 limit

「そうそう、3.のlimitを付けるのも大事」「limit付け忘れて結果が大量になって死ぬ、あるある」

# 同記事より
User.where(country: "Germany").limit(100)

🔗 find_each

「4.はfind_each」「find_eachは主キー以外ではソートできなくて、自分で書かないといけなかった気がする」「そういえば以前find_in_batchesでORDER BYが効くかと思ったら効かなかったことがありました」

User.where(country: "Germany").find_each(:batch_size: 5000)

つっつき後、以下のプルリク(Rails 6.1にマージ済み)でorder: :descを指定できるようになっていると教わりました↓。それ以前は昇順のみだったようです。ソートの対象は主キーのみで、バッチ単位でソートされます。

🔗 pluck

「5.はpluckを使おうという話」「SELECTするカラムを減らすのは非常に大事ですね: カラムを減らすだけで急に速くなったりする」「そうそう」「ActiveRecord::Relationに対してpluckを使うと、SQLクエリレベルでSELECTするカラムが必要なカラムのみに絞り込まれるので、SQLの結果セットサイズを小さくでき、かつActive Recordのオブジェクト生成コストを削減できます」

# 同記事より
User.pluck(:id)
# SELECT "users"."id" FROM "users"

Railsの技: pluckはActive RecordモデルでもEnumerableでも使える(翻訳)

「そういえば最近のRailsのコンフィグにenumerate_columns_in_select_statementsという設定がありますね↓」「あれはSELECT *を実際のカラムに展開するオプションですが、それはカラムを減らす話とは別ですね」

参考: Rails アプリケーションを設定する - Railsガイド

enumerate_columns_in_select_statements設定オプションは単に*をカラムに展開するだけなので、結局全部のカラムをSELECTするんですよ: pluckのようにSELECTするカラムを絞り込むものではない」「そうだったのか...」「個人的には割と好きなオプションなので、名前を復唱して覚えておくぐらいはしてもいいと思います👍」

🔗 バルク操作

「6.のバルク操作は、フックを実行しなくていいときなら使っていいと思います」「そうそう、バルク系はフックが呼ばれないんですよね」「バルク系でもたとえばdestroy_allはフックが呼ばれるけどdelete_allは呼ばれないなどは注意が必要ですね」

「おや、こんな書き方↓ができる?ハッシュの配列をUser.createというクラスメソッドに渡して作成できるのか、これは知らなかった」「知りませんでした」

# 元記事より(一部修正)
users = [
  {name: "Milap", email: "milap@country.com", country: "Germany"},
  {name: "Aastha", email: "aastha@country.com", country: "Germany"}
]

User.create(users)

# INSERT INTO users (name, email, country)
# VALUES
#   ('Milap', 'milap@country.com', 'Germany'),
#   ('Aastha', 'aastha@country.com', 'Germany')

created_atupdated_atを指定しなくていいinsert_allみたいな感じですか?」「見た感じではbefore_*系フックは動きそうなので、フックを実行してからINSERT INTOすると思いたい」「お〜なるほど」「その場合1件ごとにフックが動くんでしょうか?」「仕組み上そうでないとまずいでしょうね」「それもそうですよね」「心配なら確認コードを書くのがいいと思います」


追記: ActiveRecord::Base.createは元記事でバルク操作として紹介されていますが、実際にはバルクではなく単にループでcreateを呼んでいる↓とつっつき後に教わりました。

参考: rails/persistence.rb at 76489d81ba77216271870e11fba6889088016fa5 · rails/rails

なお、手元で試したところActiveRecord::Base.createでフックは効きました。

🔗 インメモリ処理

「7.はインメモリの処理」「このあたりはデータベースチューニングでよく扱うところですね: データベースチューニングというとついSQLレベルでやろうとする人が多いんですが、以下のようにpluckで全部取ってきたものをRuby側で計算してからクエリをかけるとか、Railsのキャッシュに乗る方が速くなることもよくあります」「あ〜たしかに」

# 同記事より
existing_countries = User.distinct.pluck(:countries)
puts countries - existing_countries

# SELECT DISTINCT `users`.`countries` FROM `users`

「こういう定番のノウハウが盛り込まれている記事は何度読んでもいいもの👍」「そうですね」

🔗クラウド/コンテナ/インフラ/Serverless

🔗 Docker Desktop無料の猶予期間が終了(Publickeyより)


つっつきボイス:「ついにDocker Desktop無料の猶予期間が終了か」「従業員250名以上か年間売り上げ1000万ドル以上の組織が有料ということなので、自分のところはさしあたって対象外ですけどね」

🔗CSS/HTML/フロントエンド/テスト/デザイン

🔗 WebVM(Publickeyより)


つっつきボイス:「これはちょっと凄い」「ついにブラウザ上でLinuxが素で動くようになった🎉」「以下のリンクをクリックすると即起動しました↓」「WebAssembly用のカーネルなのかな?」

「プロセッサ数は1だけどnprocは2になっている」「2で固定かな?」「root権限は取れなさそう」「Ctrl-Cが効かなかったのでブラウザを閉じました」「う、Safariでは動かない...他のブラウザで開けと言われてしまった😢」

「/procが見当たらないな: おそらくprocファイルシステムが入っていなくて、それを参照するコマンドも動かないんでしょうね」「psコマンドが効かないのもそのせいでしょうか?」「おそらくそうでしょうね」

「触った限りでは、呼べないシステムコールやドライバが結構ありそうな環境なので、実行できないものがいろいろあるのはしょうがないかな: バーチャルドライバを作ればいろいろ動かせるようになりそう」


「最近のWebAssemblyはアツいですね」「最近はAmazon Primeの動画再生もWebAssemblyになったらしい↓」「お〜」「動画再生のようにシビアな分野でWebAssemblyを導入して、しかも高速化したのは凄い」

参考: Amazon Prime Videoが動画再生にWebAssemblyを採用。再生デバイス上にWasm VMをデプロイ、高フレームレートなど実現 - Publickey

🔗言語/ツール/OS/CPU

🔗 regexploit: 正規表現のReDoSを検出

doyensec/regexploit - GitHub


つっつきボイス:「Pythonで書かれたReDoS検出ツールだそうです」「お〜、CIとかで自分のRubyコードをRuboCop的なツールで解析するときに正規表現を抽出してこれにかけられるといいな」

# 同リポジトリより
$ regexploit
v\w*_\w*_\w*$
Pattern: v\w*_\w*_\w*$
---
Worst-case complexity: 3 ⭐⭐⭐ (cubic)
Repeated character: [5f:_]
Final character to cause backtracking: [^WORD]
Example: 'v' + '_' * 3456 + '!'

参考: ReDoS - Wikipedia

「ところでチェックされる正規表現はPythonフレーバーが前提なのかな?」「もしかするとそうかも」「Ruby(Onigmo)の正規表現はそこそこ独自性があるから、とりあえず基本的な正規表現に絞って使うのがいいのかも」「今度試してみます」

はじめての正規表現とベストプラクティス1: 基本となる8つの正規表現

🔗 libtree: 共有ライブラリの依存関係をツリー表示


つっつきボイス:「お、こういうツールがあるんですね」「今までなかったのが不思議かも」「.soや.dylibなどのローダーの挙動を制御しなければならなくなるようなことは昔に比べて随分減りましたけどね」「昔はよくやりましたね」「組み込み系でよくやってたけどめっきりやらなくなった」「機械学習系みたいに外部ライブラリを使わざるを得ない分野だとたまに必要になるかも」


後編は以上です。

バックナンバー(2022年度第1四半期)

週刊Railsウォッチ: Rails 6.1を7.0にアップグレードしてみた、PostgreSQLでジョブキューほか(20220208前編)

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Ruby Weekly

Publickey

publickey_banner_captured


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。