pitchfork
https://github.com/Shopify/pitchfork
Shopify製のprefork型Rack HTTP server
Copy-on-Writeのパフォーマンスを最大化することでメモリ使用量を最小限に抑えるように設計されている
当初はunicornのパッチとして始まったが、unicorn本体が古いRubyをサポートするのでメンテナンスが難しく、forkして実装されることになった
ohbarye.icon pitchforkによって解決される問題はとても狭いのでよほどの理由がなければ移行は避けた方がよさそう
refork
https://github.com/Shopify/pitchfork/blob/master/docs/REFORKING.md
pitchfork最大の特徴
Copy-on-Writeでforkされた子プロセスがメモリの共有ページに何も書き込まなければ、コピーされないので実質無料
しかしRuby プロセスでは一般に遅延初期化されるメモリ領域が大量にある
Ruby VMのインラインキャッシュ、YJIT を使用する場合の JITコード、およびメモ化などのアプリケーションの一般的なパターン
workerプロセスを起動直後にforkすると、これらのコードパスが実行される前なのでメモリ共有のメリットは時間経過で失われていく
pitchforkはウォームアップされてキャッシュが十分に効いているプロセスを昇格させ、fork元として使う
新しいfork元 (mold) が昇格したら、moldから新しいプロセスをforkして古いworkerをロールアウトで置き換えていく
reforkはレイテンシを増加させる
子プロセスがメモリに書き込むとき、カーネルはプロセスを停止してメモリページをコピーする必要があり、これは非常にコストのかかる操作
つまり、reforkの利用はメモリ使用量とレイテンシのトレードオフになる
用途
https://github.com/Shopify/pitchfork/blob/master/docs/PHILOSOPHY.md
すべてのアプリケーションに適しているわけではない
CPU/メモリ/ディスクを大量に使用し、外部リソース (データベース サーバーや外部 API など) の待機時間がほとんどないアプリケーション向けに最適化されている
https://github.com/Shopify/pitchfork/blob/master/docs/WHY_MIGRATE.md
First and foremost, if you don't have any specific problem with your current server, then don't.
Pitchfork isn't a silver bullet, it's a very opinionated software that focus on very specific tradeoffs, that are different from other servers.
unicornのメモリ使用量に困っており、かつpumaなどへ移行できないとき
ただしアプリケーションをfork safeにするのも簡単ではない
Rack 3を使いたいとき
unicornの持つデーモン化、pid ファイル管理、ホット リロードなどの多くの機能を削除している
コンテナ化された世界で意味のある機能のみを残している
Shopifyでの効果
https://railsatscale.com/2023-10-23-pitchfork-impact-on-shopify-monolith/
Shopifyにおけるpitchforkの成果
メモリ使用量だけでなくレイテンシも改善している
ウォームアップされたworkerにより、インラインキャッシュヒットやJITコードも改善するため
スタディサプリでの効果
https://blog.studysapuri.jp/entry/2024-pitchfork-into-the-largest-rails-application-in-studysapuri
reforkを無限に繰り返してもメモリ使用量の削減にはあまり意味がないことをメトリクスから理解し、4世代、計6000リクエストほど処理した段階でreforkを止めるように設定した
トレードオフの関係を理解し、メトリクスを見たうえで最適な設定ができていてすごい
ruby-jpより
pocke
:pocke: 1:05 PM
https://github.com/puma/puma/blob/master/docs/fork_worker.md
Puma の refork と近い発想かなと思ったので「非常にユニークな概念」というのに若干違和感があったのですが、pumaのそれとは結構違う発想なんですかね?
ざっと見た感じ大筋は同じことをやりたそうに見えるけど、違いがあるなら興味あります :eyes:
k0kubun
1:46 PM
同じだと思います。pumaにも既にあるという意味ではCRuby環境での唯一性はないけど、多くの処理系では普通はマルチスレッドで解決されるべき問題なので、アプリケーションサーバー全般の文脈で言うとreforkingという概念自体は比較的ユニークなものだと思います。僕はそれよりもpumaを各プロセス1スレッドで使うという発想に誰もならない(のでスレッドアンセーフなアプリにpumaを使わない)ことの方が引っかかる
k0kubun
1:52 PM
gRPCの例にもあるように、フォークアンセーフなライブラリというのはあって、それでクラッシュした時に直すパワーは必要なので、そういう (スレッドセーフティを保証するのとどっちが簡単かすらわからない) 難しさからあんまり流行らないと思うんですよね。うちが本番モノリスにいれたからにはそこで使ってるようなgemだけ使ってれば動くとは思いますが
k0kubun
2:00 PM
Railsアプリとかだとワーカー起動前にアプリのプリロードが走らせられる分、その後GC.compactやってからフォークすればreforkingとかしなくても比較的CoWフレンドリになるから、pumaに入った当時も (fork safetyを保証する苦労の割に) そんなにインパクトなくてあまり使われなかったのだと思うけど、YJITをいれるとJITで使うメモリがほとんどフォーク後に作られるので、reforkingした時のメモリ使用量のインパクトが大きくなり、pumaに入った時と違って重要性が高まっているのだと思われる