EuRuKo 2019 で発表してきました

技術部でフルタイム Ruby コミッタをしている遠藤(@mametter)です。フルタイムで Ruby を開発しています。

先日、オランダのロッテルダムで開催された EuRuKo 2019 で発表してきたので、簡単にレポートします。

EuRuKo とは

EuRuKo は、毎年ヨーロッパのどこかで開催されている Ruby のカンファレンスです。

f:id:ku-ma-me:20190709131404j:plain
EuRuKo 2019 会場

シングルセッション

世界の Ruby カンファレンスといえば、アメリカの RubyConf 、ヨーロッパの EuRuKo 、日本の RubyKaigi だと勝手に思っていますが、この中で EuRuKo の特徴というと、シングルセッションなことです*1。つまり、発表を聞く会議室は 1 つだけです。どれを聞くか迷わなくていいですね。

必然的に、発表の数は少ないです。YouTube の動画の数を見てみると、RubyConf 2018 は 70 件 、RubyKaigi 2019 は 65 件 ですが、今回の EuRuKo 2019 の発表は 15 件、LT を含めても 20 件でした。発表したい人からすると、採択されるのが最難です(たぶん採択率 1 桁)。

city pitch

また、次回の開催地が会期中に投票で決められるのも特徴です。立候補した街の人が city pitch(街の宣伝)を行い、会場の拍手喝采の大きさで決められていました。

f:id:ku-ma-me:20190709131545j:plain
EuRuKo 2020 開催に立候補した都市

オーストラリアのメルボルンが立候補してるのが話題でしたが、来年はヘルシンキになりました。

EuRuKo 2019 の様子

オランダのロッテルダムにある、ss Rotterdam っていう退役したクルーズ船が会場でした。現在は岸に固定されてホテルになってます。

f:id:ku-ma-me:20190709131400j:plain
EuRuKo 2019 の会場(ss Rotterdam)

EuRuKo 発表の傾向としては、Ruby コア開発の話よりは Ruby を使う話が中心です。そういう意味で、RubyKaigi よりは RubyConf に似ています。

その中でも印象に残った話を 3 つほど簡単に紹介します。

Functional (Future) Ruby - Yukihiro Matsumoto

matz のキーノート。動画がすでに上がっています。

ざっと内容を紹介します。まずは Ruby 3 の 3 つのゴールである Static analysis 、Performance 、Concurrency の進捗が説明されました。詳細はいろいろなところで見つかるので、主にキーワードだけ挙げておきます。

Static analysis は、公式型シグネチャフォーマットとなる予定の ruby-signature 、型シグネチャのない Ruby プログラムをゆるく型検証し型シグネチャを推定する type profiler 、型シグネチャを前提として、型シグネチャとコードの対応を検証する SorbetSteep などが登場してきたことがダイジェストで紹介されました。 Performance は、オブジェクトを並べ替えてメモリのフラグメンテーションを軽減する Object compaction によってメモリボトルネックなアプリの効率を上げ、また JIT コンパイラである MJIT や MIR によって CPU ボトルネックなアプリの実行効率を上げることが述べられました。 Concurrency については、並列実行向けには Guilds(仮称)が計画されており、大規模並行処理向けには AutoFiber(仮称)が検討されていることが触れられました。

それから、関数型プログラミングっぽい他言語からインスパイアされた検討中の機能が紹介されました。

  • ブロックの無名引数

@1 で引数を暗黙的に参照できます。

3.times { p @1 }
# 3.times {|i,| p i } と同じ

@2 だと 2 番目の引数、@3 だと 3 番目の引数を参照できます。しかし現実的には複数の引数を参照仕分けるユースケースは稀なので、引数 1 つに特化し、別の記号(@ 、Kotlin や Groovy 風の it 、Scheme の <>)などにするか検討中とのこと。他人事のように言ってますが、it を提案しているのは遠藤です(Feature #15897)。

  • パターンマッチング。

データ構造が想定パターンになっているか調べて、その要素を変数に束縛することができます。

case JSON.parse(json, symbolize_names: true)
in {name: "Alice", children: [name: "Bob", age: age]}
  p age
in _
  p "no Alice"
end

典型的には、JSON の処理に便利そうです。

  • パイプライン演算子

パイプライン演算子が試験的に Ruby に取り込まれました。

1..100
  |> map {|x| rand(x)}
  |> sort
  |> reverse
  |> take 5
  |> display

「パイプライン演算子はプライマリの引数を呼び出しにわたすもの」「Ruby ではプライマリの引数はレシーバ」ということで、実質的にメソッド呼び出し演算子(.)と同じものになっています(このへんの詳細は遠藤のブログを参照ください)。しかし非常に controversial であり、名称・記号を変更するか、キャンセルするか(まだリリース前なので互換性の問題なく取り消せる)、現在も悩んでいるとのことです。

というように、様々な意見はありつつも Ruby はまだまだ新しい機能を取り入れて進化していってます。

What causes Ruby memory bloat? - Hongli Lai

Ruby プロセスのメモリ肥大化の原因を調査した報告です。発表者の Hongli Lai は Passenger や Ruby Enterprise Edition の作者です。この発表はだいたい次のブログで発表済みだった内容ですが、今回の EuRuKo で一番テクニカルで、個人的には一番おもしろい発表でした。

www.joyfulbikeshedding.com

Ruby のメモリ肥大化と言えば、「Ruby: mallocでマルチスレッドプログラムのメモリが倍増する理由(翻訳)」という記事が有名です。端的に言えば「jemalloc を使え、もしくは環境変数 MALLOC_ARENA_MAX=2 を設定しろ」というやつで、見たことがある人も多いのではないでしょうか。しかし Hongli Lai はこの記事を疑い、再調査したところ、メモリ肥大化の本当の原因は別にあったということです。

かいつまんで説明します。Ruby がメモリを使うのは 2 種類あります。

  • (1) Ruby オブジェクトのヒープ
  • (2) Ruby オブジェクト以外のヒープ(主に文字列や配列など)

(1) については、あるアプリケーションでオブジェクトのヒープサイズを測定したところ、全使用メモリ 230 MB に対して 7 MB だったので、肥大化の原因としては無視できます。

(2) についてはちょっとややこしいのですが、malloc したメモリが一部だけ生き残って断片化が起きるという前提で、glibc の malloc はスレッドごとにメモリアリーナを確保するので問題がひどくなるというのが元記事の主張で、そのために MALLOC_ARENA_MAX=2 を設定すればアリーナの数が高々 2 に抑えられるので問題が軽減するとされています。

しかし Hongli Lai は「malloc 領域の中で断片化は本当に起きているのか?」と疑問を持ち、可視化機能付き malloc ラッパを書いて確かめたそうです(すごい)。その結果がこれ。

f:id:ku-ma-me:20190709131409j:plain
"What causes Ruby memory bloat?" Ruby プロセスのメモリ使用状況の可視化

赤い領域は使用中、灰色は free 済み(すでに使用されていない)だが OS に返却されていない領域、白は返却済みの領域です。赤い領域が飛び飛びにあるので断片化は多少起きているものの、完全に灰色のところも多いことがわかります。つまり、断片化はそれほどひどくなく、むしろ OS に領域を返却できていないことが問題です。 使用済みだが OS に返却されていないのは、こまめに返却すると実行効率が下がることがあるためだと思われます。malloc_trim という関数を使えば使用済み領域を明示的に OS に返却できる *2 ということで、Ruby にパッチをあてて再実験した結果がこちら。

f:id:ku-ma-me:20190709131803j:plain
"What causes Ruby memory bloat?" malloc_trim パッチ後のメモリ使用の様子

めでたく、白い部分が増えました。これにより、使用メモリ 230 MB だったところが 60 MB にまで減ったということです。MALLOC_ARENA_MAX=2 を指定したら 53 MB なので、効果としてはほぼ同じとのこと。

また、Fullstaq Ruby という Ruby のディストリビューションを始めたということが発表されていました。今回の調査結果を含むということです。

The Past, Present, and Future of Rails at GitHub - Eileen M. Uchitelle

GitHub で働く Rails コミッターである Eileen の発表。Rails わかんないのでさらっと紹介です。

なんと、GitHub では、Rails をフォークして使っていたそうです。

f:id:ku-ma-me:20190709131553j:plain
"The Past, Present, and Future of Rails at GitHub" GitHub は Rails をフォークしていた

しかし、先端の Rails にどんどん置いてかれて開発もメンテナンスも辛くなり、採用やセキュリティ対応も厳しくなってきたので、がんばってフォークを卒業した、ということでした。

f:id:ku-ma-me:20190709131558j:plain
"The Past, Present, and Future of Rails at GitHub" GitHub は Rails のフォークをやめた

ということで、「フォークをしても良いことないよ」「ちゃんと Rails の最新版を使っていこうね」ということが何度も語られていました。

がんばってフォークを卒業するまでに相当がんばったのではないかと思われるのですが、あんまりその辺の苦労は語られていなかったのが若干心残りです。しかし、Eileen は Rails 6 に GitHub で必要な機能(Multi-DB とか)を入れまくった人なので、その背景が想像される感じで面白かったです。独自フォークを無くすためには、フォークを公式にすればいいわけです。*3

A Plan towards Ruby 3 Types - Yusuke Endoh

ついでに自分の発表です。発表資料はこちら。

発表内容は大筋で Ruby 3 の静的解析の計画と、その中で自分が作っている型プロファイラの進捗報告でした。おおよそは RubyKaigi と同じなので、クックパッド開発者ブログで書いた遠藤の過去記事をご覧ください。

進捗としては、解析速度に難があった(型プロファイラ自身のプロファイルに 10 分、optcarrot に 3 分)だったので、解析アプローチを大幅に見直して、精度を少し犠牲にしつつ高速化をしたところ、それぞれ 2.5 秒・6 秒になった、というところです。とはいえまだまだ未実装な機能だらけなので、引き続きがんばってます。

f:id:ku-ma-me:20190709131550j:plain
発表のときに壇上から撮った会場の様子

おまけ:発表者の特典

前述のとおり EuRuKo は採択率が非常に低いのですが、そのためか発表者のおもてなしがなんかすごかったです。

  • 旅費・宿泊費支給(いろいろあって遠藤は旅費をクックパッドに、宿泊費を EuRuKo に出してもらいました)
  • 空港からの送迎
  • 水上タクシーでの周辺観光
  • 現地の Rails Girls イベントへの招待
  • スピーカディナーへの招待(発表者と運営だけが参加できるディナー)
  • スピーカラウンジ(発表準備したり、議論したり、ゲームで遊んだりできるスペース)
  • 記念品(会場だった ss Rotterdam の模型)

f:id:ku-ma-me:20190709133117j:plain
EuRuKo 2019 発表者記念品と名札

まとめ

EuRuKo 2019 のダイジェスト紹介でした。

ちなみに今回の日本人参加者は matz と自分の 2 名だけでした(たぶん)。海外の Ruby カンファレンスと言うとアメリカの RubyConf が注目されがちですが、EuRuKo も行ってみるといいのではないでしょうか。来年はフィンランドのヘルシンキです。

f:id:ku-ma-me:20190709133255j:plain
EuRuKo 2019 エンディングの様子

*1:ちなみに歴史は RubyConf(2001 年)、EuRuKo(2003 年)、RubyKaigi(2006 年)の順で、最近の規模は RubyKaigi(1000 人程度)、 RubyConf(800 人程度)、EuRuKo(600 人程度)です。

*2:ドキュメントによると「ヒープの一番上の未使用メモリーの解放を試みる」となっていますが、Hongli Lai がソースを読んだ限りだと、一番上に限らず未使用領域を返却していくらしいです。

*3:手前味噌ですが oneshot coverage もクックパッドの Ruby フォークを本家に整理して再実装した感じです。

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/