- Ruby / Rails関連
週刊Railsウォッチ: Rubygems.orgのAPIキーに権限スコープが追加、RailsのDBパフォーマンス改善ほか(20220209後編)
こんにちは、hachi8833です。
🔗Ruby
🔗 BrakemanとRuby 2.6のEOL
- issue: Brakeman crashes while printing warning for Ruby EOL 2.6 · Issue #1671 · presidentbeef/brakeman
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で修正されました↓。
- PR: Add warnings codes for EOL software by presidentbeef · Pull Request #1673 · presidentbeef/brakeman
🔗 Rubyのメモリフットプリント
つっつきボイス:「これもruby-jp Slackで見かけました」「全般にRubyのバージョンが新しくなるとじわじわメモリフットプリントが増えてますね」
「他言語のメモリフットプリントセクションも興味深い」「Pythonのフットプリントが意外に小さいですね」「一番フットプリントがでかいのはNode.js」「JavaのOpenJDKが大きいのはしょうがない感があるけど、それよりNode.jsが大きいのが謎」「こうしてみるとdashとかtcshのフットプリントは圧倒的に小さいな〜、使いたくないけど😆」
🔗 Puma 5.6がリリース(Ruby Weeklyより)
- 元記事: Releases · puma/puma -- 現在は5.6.1が最新です
つっつきボイス:「新しい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より)
Test and Optimize Your Rails App's Database Performance: https://t.co/iy7QYXkNmn (Quickly covers three ways to investigate problems and then seven ways to mitigate said problems.)
— Ruby Inside (@RubyInside) January 30, 2022
つっつきボイス:「よくある記事っぽいですが、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のコンフィグに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_at
やupdated_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用のカーネルなのかな?」
- WebVM: https://webvm.io/
「プロセッサ数は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を検出
つっつきボイス:「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 + '!'
「ところでチェックされる正規表現はPythonフレーバーが前提なのかな?」「もしかするとそうかも」「Ruby(Onigmo)の正規表現はそこそこ独自性があるから、とりあえず基本的な正規表現に絞って使うのがいいのかも」「今度試してみます」
🔗 libtree: 共有ライブラリの依存関係をツリー表示
共有ライブラリ (.so) の依存関係を木構造で表示するツール。といか、なぜlddはデフォルトでこれをやってくれないんだ。https://t.co/ZPaUI0wH0J
— 新山祐介 (Yusuke Shinyama) (@mootastic) December 4, 2021
つっつきボイス:「お、こういうツールがあるんですね」「今までなかったのが不思議かも」「.soや.dylibなどのローダーの挙動を制御しなければならなくなるようなことは昔に比べて随分減りましたけどね」「昔はよくやりましたね」「組み込み系でよくやってたけどめっきりやらなくなった」「機械学習系みたいに外部ライブラリを使わざるを得ない分野だとたまに必要になるかも」
後編は以上です。
バックナンバー(2022年度第1四半期)
週刊Railsウォッチ: Rails 6.1を7.0にアップグレードしてみた、PostgreSQLでジョブキューほか(20220208前編)
- 20220201後編 Rubygems Adoptionフォームが開設、JetBrains Gateway、NGINX Unitほか
- 20220131前編 Sidekiqが10歳に、BuildKiteのテストを高速化、フィーチャーフラグほか
- 20220126後編 Rubyコンパイラの歴史動画、RubyのWebAssembly対応進む、ぼっち演算子の注意点ほか
- 20220124前編 Webpackerが公式に引退宣言、『Everyday Rails』日本語版がRails 7に対応ほか
- 20220118後編 Ruby 2.5〜3.1ベンチマーク、Opal 1.4、JRubyが20歳に、2022年のCSSほか
- 20220117前編 rails-ujs->Turboアップグレードガイド、RubyとWeb Componentsほか
- 20220112 Rails 7をRuby 3.1で動かす、クックパッドのRuby 3.1解説記事、Rails 6->7更新ほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)