- Ruby / Rails関連
週刊Railsウォッチ: ruby/debugをChromeでリモートデバッグ、Rubyアプリの最適化ほか(20211019後編)
こんにちは、hachi8833です。発表された新型MacBook Proのノッチが...
書きました。
新型MacBook Proでは「画面の中にノッチが降りてきた」のではなく、「フロントカメラの左右部分にまで画面が広がった」ことが、発表イベントでは語られています。ただし、好き嫌いは分かれそうです。https://t.co/NDBeh09JUv— 山口健太 / Kenta Yamaguchi (@tezawaly) October 19, 2021
🔗Ruby
🔗 ruby/debugのChrome用リモートデバッグ機能
debug.gem and Chrome browser integration.
Thanks Ono-san! pic.twitter.com/3aUdH2zbEo— _ko1 (@_ko1) October 14, 2021
つっつきボイス:「BPS社内Slackに貼っていただいたツイートです」「これはいい機能👍」
「これは?」「ruby/debugの中からHTTPサーバーを起動してそこにChromeでアクセスすると、Chromeからruby/debugを制御できるという、ruby/debugの新機能です」「お〜動画でChromeの中にデバッガコンソールが見えた」「いわゆるリモートデバッグ機能そのもの」「Chrome拡張を使うのかと思ったら不要なんですね」「Chrome Devtoolsで公開されているChromeの独自機能を使っているようです」
現時点ではmasterブランチに入っています。
🔗 Rubyアプリを最適化する(Ruby Weeklyより)
つっつきボイス:「ちょっと眺めた限りではシングルスレッドで複数のIOをチェインして同時処理させる話のようですね」
参考: class Thread
(Ruby 3.0.0 リファレンスマニュアル)
「Backend#chain
を使うと、こんなふうにI/O操作をチェインできるらしい↓」
# 同記事より
Thread.current.backend.chain(
[:write, @conn, "#{len.to_s(16)}\r\n"],
[:splice, r, @conn, len],
[:write, @conn, "\r\n"]
)
「このあたりのRESPOND_FROM_IO_PROGRAM
の内側がインタプリタとかASTパーサーっぽく見える↓」
# 同記事より
# program references:
# 0 - headers
# 1 - io
# 2 - @conn
# 3 - pipe r
# 4 - pipe w
# 5 - chunk_size
RESPOND_FROM_IO_PROGRAM = [
[:write, 2, 0],
[:loop,
[:splice, 1, 4, 5],
[:break_if_ret_eq, 0],
[:store_ret, :len],
[:write_cte_chunk_size, 2, :len],
[:splice, 3, 2, :len],
[:write, 2, "\r\n"]
],
[:write, 2, "0\r\n\r\n"]
]
def respond_from_io(request, io, headers, chunk_size = 2**14)
formatted_headers = format_headers(headers, true, true)
r, w = IO.pipe
Thread.backend.submit(RESPOND_FROM_IO_PROGRAM, formatted_headers, io, @conn, r, w)
end
「お、同じ部分を今度はDSL化して読みやすくした感じですね↓」
# 同記事より
RESPOND_FROM_IO_PROGRAM = Polyphony.io_program(
:headers, :io, :conn, :pipe_r, :pipe_w, :chunk_size
) do
write :conn, :headers
io_loop do
splice :io, :pipe_w, :chunk_size
break_if_ret_eq 0
store_ret :len
write_cte_chunk_size :conn, :len
splice :pipe_r, :conn, :len
write :conn, "\r\n"
end
write :conn, "0\r\n\r\n"
end
「最後のまとめを見ると、この記事ではトップの層でRubyのデータ構造を使い、I/O操作のような単純な処理は下の層のCで操作することで並列実行しやすくしたようですね」「Rubyでもこんなふうにすると速くできるよと」「Linuxのio_uring
と似たアプローチとありますね」
本記事ではRubyアプリのパフォーマンス最適化のためにプログラムを2つの層に分離するアプローチを紹介しました。つまり、Rubyのデータ構造を用いて低レベル処理を表現するRubyのトップ層と、それらの処理を最適な形で実行するCの実装の層です。このアプローチでは、
chunked
エンコーディングによるHTTPレスポンス送信、受信データ解析、I/Oのループ処理などの複雑な処理を長時間行う場合に特に有効です。
上述のようにこのアプローチはLinuxのio_uring
で用いられているものと似ています。考え方は同じで、(I/O)操作をデータ構造で表現し、その実行を最適化された下の層(io_uring
ではカーネル、Rubyの場合はC拡張)に移行しています。
同記事より
参考: Transfer-Encoding - HTTP | MDN
参考: io_uringで高速IO処理(?) | κeenのHappy Hacκing Blog
「ところでさっきのRESPOND_FROM_IO_PROGRAM
の中身はリテラルになっていますけど↓、こうするとRubyのインタプリタが仕事しなくて済むようになってJITが効きやすくなるのかもと思いました」「たしかにリテラルですね」
# 同記事より抜粋
RESPOND_FROM_IO_PROGRAM = [
[:write, 2, 0],
[:loop,
[:splice, 1, 4, 5],
[:break_if_ret_eq, 0],
[:store_ret, :len],
[:write_cte_chunk_size, 2, :len],
[:splice, 3, 2, :len],
[:write, 2, "\r\n"]
],
[:write, 2, "0\r\n\r\n"]
]
🔗 HTTPI: RubyのHTTPクライアント向けの共通インターフェイス(Ruby Weeklyより)
つっつきボイス:「HTTPI、見たことなかった」「新しそうなライブラリですね」
# 同リポジトリより
require "httpi"
# create a request object
request = HTTPI::Request.new
request.url = "http://example.com"
# and pass it to a request method
HTTPI.get(request)
# use a specific adapter per request
HTTPI.get(request, :curb)
# or specify a global adapter to use
HTTPI.adapter = :httpclient
# and execute arbitrary requests
HTTPI.request(:custom, request)
「これは何をするものなんでしょう?」「Rubyにはこのサイトにも書かれているようなHTTPClientやNet::HTTPのようないわゆるHTTPクライアントライブラリがたくさんありますけど、それぞれのインターフェイスはまちまちなので、それらを統一して呼べるようにして、HTTPI.adapter = :httpclient
みたいにアダプタを切り替えるだけでHTTPクライアントライブラリを切り替えられるということでしょうね」「なるほど、RubyのHTTPクライアントライブラリ向けのラッパーでしたか」
「ただ、HTTPクライアントライブラリを使い分ける機会はそうそうないと思いますけど」「ライブラリをこれと決めたら普通はそのまま使いますよね」「Active Jobを経由せずにSidekiqを直接使う話(ウォッチ20211018)と似ているかも」「MySQLからPostgreSQLに移行することがめったにないのもそうですね」「ライブラリごとに機能も違ってくるので、ライブラリ間の差異を共通化レイヤで吸収するのはそれなりに大変」
「HTTPIは新しいライブラリですし、今すぐproductionで使うものでもないので、もしかすると練習用として作ってみたのかなと想像してみました: こういうのを自分でやってみると楽しく勉強できると思います」「特定のHTTPライブラリのバグを切り分けるのに使えるかもしれませんね」
🔗 その他Ruby
The Ruby Specs need your help! Fill out missing Ruby 3.0 features in the ruby/spec repository and win FABULOUS PRIZES. Ok actually no prizes... except the feeling of accomplishment and knowing you are helping out alternative Ruby implementations!https://t.co/PvYN8nXYYp
— Charles Nutter (@headius) October 5, 2021
つっつきボイス:「ruby/specリポジトリで、Ruby 3.0の新機能や機能変更のspecを書いて欲しいという募集だそうです」
「#823を見ると、specを書いて欲しい3.0の機能がちゃんとリストになっているのがいいですね」「完了のチェックボックス、この間見たときより増えてるみたいです」「これならコントリビュートしやすそう」「やってみようかな」
その後もチェック済みは着々と増えているようです: Pull requests · ruby/spec
「お、IBM720なんてエンコーディングがあるんですって(#16233)」「聞いたことないですね」
参考: MFT で使用できるコード・ページ - IBM Documentation
🔗DB
🔗 SpannerにPostgreSQL互換インターフェイスが追加(Publickeyより)
つっつきボイス:「そうそう、GoogleのSpannerにこの機能が入りましたね: Spannerはかなり高価だったんですが、最近値下がりして以前より使いやすくなりつつあるので、PostgreSQL互換のインターフェイスが使えるようになればより手を出しやすくなりそう」
参考: Cloud Spanner | Google Cloud
「AWSにはRDSやAurora PostgreSQLがありますけど、これまでGCPにはマルチAZやフェイルオーバーまですべて備えたようなRDS的なサービスというとCloud SQLしかなかったと思うので、今回の発表でSpannerがGCPでの選択肢に入ってきそうですね」「なるほど」「AWSからSpannerを使おうとするとネットワーク的に遠いという問題はありますが」「GCPからSpannerを使う方が無理がなさそうですね」「レイテンシはその方がよいでしょうね」
参考: Amazon RDS(マネージドリレーショナルデータベース)| AWS
参考: Amazon Aurora PostgreSQL の特徴 | MySQL PostgreSQL リレーショナルデータベース | アマゾン ウェブ サービス
参考: Cloud SQL ドキュメント | Google Cloud
「Spannerはスケーラビリティがすごく高くてオートスケールも強いんですが、これほどの高性能が必要な案件はなかなかないでしょうね」「あ〜」「あるとすれば、ソシャゲやワクチン予約受付サイトのようにユーザー数がいくらでも増える可能性やアクセスが短時間にものすごく集中する可能性もあって、かつランニングコストに見合うサービスかな」「なるほど」「そのぐらいの規模になるとAWSのオートスケールだとアクセス急上昇に間に合わないかも」「ソシャゲだとSpannerはちょっともったいなさそうですけどね」
「その意味では、AWSのAurora PostgreSQLは負荷に応じてオートスケールできて、しかもRDSと値段がほとんど変わらないのがいいんですよ」「たしかに値段がほぼ同じなら迷わずAurora PostgreSQLを選ぶでしょうね」「SpannerはDBインスタンスを立てるのに比べて安くないので悩ましいところ」
「まだGCPやSpannerは本格的に運用したことはありませんが、Spannerは選択肢のひとつとしておくとよさそう👍」
「ところで元記事ではSpannerがNoSQLとして紹介されていたけど、NoSQLだったかな?」「公式ブログ↓を見ると、当初はNoSQLキーバリューストアとして設計されたけどリレーショナルモデルも採用したとありますね」「なるほど、自分の中ではSpannerは無限といってもいいぐらいにスケールできるRDBという位置づけだったけど、合ってるみたいでよかった」
参考: NoSQL から新しい SQL へ : グローバルなミッションクリティカル DB へと進化を遂げた Cloud Spanner | Google Cloud Blog
🔗クラウド/コンテナ/インフラ/Serverless
🔗 AWS Lambdaバトル
Ruby 何起きてんのかなーこれ、major GC…? https://t.co/YnJMr8VrDM
— 7594591200220899443 (@shyouhei) October 13, 2021
つっつきボイス:「これは自分も見ましたけど、ベンチマークのソースコードを見るとJSONを取ってきてDynamoDBに格納しているだけで、実行環境での起動以外ではほとんどリソースを使っていないんですよ」「そんなに軽い処理なんですか?」「コードに分岐すらありません」
# aws-lambda-runtimes-performance/ruby-lambda/app.rb
require 'json'
require 'aws-sdk-dynamodb'
$client = Aws::DynamoDB::Client.new
def create(event:,context:)
body = event["body"]
book =JSON.parse(body)
id = SecureRandom.uuid
book["id"]=id
table_item = {
table_name: "book",
item: book
}
$client.put_item(table_item)
{ statusCode: 201, body: JSON.generate(book) }
end
参考: Amazon DynamoDB(マネージド NoSQL データベース)| AWS
「このベンチマークは実行環境のプロセス起動を比較しているようなものなので、ビジネスで使うサービスを運用するうえではあまり参考にならないかなと思います」「なるほど」「Rubyのグラフはメモリーリークっぽく上昇してはいますけど、自分の印象ではRuby十分速いと思いました」
「ちゃんとベンチマークするのは難しい...」「言語が違えば実装も変わりますし、特にJSONパーサーはライブラリによって速度がかなり変わります」「それもそうですね」
なお、LambdaバトルでNodeが遅い件について、AWS_NODEJS_CONNECTION_REUSE_ENABLED
がオンになっていない可能性があるのではというissueが立っている↓とBPS社内メンバーからメンションをもらいました。
🔗JavaScript
🔗 jQuery UIとjQuery Mobileが開発終了(Publickeyより)
つっつきボイス:「今回はたまたまPublickeyの記事が多めになりました」「jQuery UIとjQuery Mobileがついに」
「ツイート↓で見かけましたけど、jQueryは今でもすごく使われているんですね」「実際jQueryで十分な場合も多いですし、ライブラリの種類も豊富だし、デザイン系も含めるとjQueryを扱える人は多いですね」「なるほど」
I reported this before, but now it's a bit clearer: jQuery did indeed peak in usage halfway through 2020, and is only *now* finally in decline.
What amazing impact... peaking at *80%* penetration of the top 100K websites!
We all owe @jeresig a big debt. Write less, do more! pic.twitter.com/Ky0xoaliqO
— Mike Monster Mash Sherov (he/him) (@mikesherov) September 30, 2021
「jQueryがこれだけ人気を得た理由のひとつは、複数ブラウザで共通に利用できたことでしょうね: 今はその役割はほぼ終わったと思いますが」「そうですね」「蓄積されたライブラリは簡単にはなくならないと思います」
「jQueryは複数ブラウザで使えるJSライブラリのさきがけだったんでしょうか?」「Prototype.jsも同じぐらいの時期だったかな: 一時期はPrototype.jsが優勢だったこともありましたけど今は消えた」「Prototype.jsは2015年までメンテされてたんですね」
参考: Prototype JavaScript Framework - Wikipedia
「そういえばjQueryとPrototype.jsを両方置くと名前空間が衝突するのを思い出した↓」「そうだったかも」「どちらも$
を使うからですね」「jQuery.noConflict();
、なつかしい」
参考: prototype.jsと同時に使うには - jQuery 日本語リファレンス
🔗言語/ツール/OS/CPU
🔗 計算量とオーダー
つっつきボイス:「はてブでバズっていました」「O(m)
みたいに書くビッグオー記法以外にもΘ
やΩ
とかいろんな記法があるんですね」「私もビッグオーしか知りませんでした」「みっちり書かれてる」
「計算量やオーダーの概念はプログラマーにとって大事ですし、アルゴリズムごとにオーダーもありますけど、現実のユースケースだとデータや検索にlocality(局所性)が絡んだりして、きれいに正規分布しないことも多いですよね」「そうそう」「アルゴリズムの特徴を知っておくのは大事だけど、計算量を覚えるだけだとあまり有効でない気がします」
「具体的な計算量はググればわかるので、むしろ計算量という概念があることは知ってて欲しいですよね」「コードレビューで3重ネストがあったときに、これだと計算量がこのぐらいになるから早期脱出を入れようとか、そういうやりとりはしますね」「そうそう、丸暗記しなくてもいいので、コードに関してやりとりするときにその視点は持ってて欲しい」
「計算量やオーダーは知っていて損はしないので読んでおくといいと思います👍」
後編は以上です。
バックナンバー(2021年度第4四半期)
週刊Railsウォッチ: Ruby 3.1にYJITマージのプロポーザル、Rubyのmagic historyメソッド、JSのPartytownほか(20211012後編)
- 20211011前編 ServerTimingミドルウェア追加、paramsで数値キーを許可、Railsで多要素認証ほか
- 20211006後編 ruby/debug 1.2.0リリース、Railsにはthorが入っている、tendejitほか
- 20211004前編 Rails 7でbyebugがruby/debugに変更、GitHub Codespacesをサポートほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)