Places: Adding Message-Passing Parallelism to Racket を読んだ

はじめに

ruby3で導入されるRactorという機構があり、そこの提案の中で

This model is similar to Racket's Place abstraction.

という記載があったのでRacketのPlaceを探してみると、Place自体はRacketの公式ドキュメント に記述を見つけることができました。

更に追ってみるとこれらの源流になっている気配がする2011年のDLS(Dynamic Languages Symposium)で Places: Adding Message-Passing Parallelism to Racket という論文が見つかったので、こちらについてかいつまんで紹介したいと思います。(RubyやRacketの話はせず、この論文の話のみを行います。RubyやRacketにある機能がこの論文と同じモデルなのか等は特に調査していません。)

自分が面白いなと思ったところだけを紹介するので、気になった人はぜひ論文を読んでみてください。

論文について

Racketにmesage passingベースの並列性サポートである Place を実装する提案です。
メッセージパッシングベースの並列性サポートというと色々あるわけですが、この提案ではsequentialな処理を前提とした巨大なランタイムシステムに、後入れで並列性を(無理なく)入れるところに工夫があるようです。*1

従来型の手法としてはUnixのforkをつかう物が上げられますが、この手法だとタスク間の通信がbyte streamに制限されてしまうため抽象化の難しさや通信効率の低下などの問題が生じることがあります。

PlaceではOSによるサポートではなくランタイムによるサポートを実現することで、上記のような問題を回避しようとしています。

Placeの概要

Racketのランタイムを起動すると、まず単一のinitial placeが作成されます。 そこから追加のplaceを作成したり、メッセージを送信したりすることで並列性を実現します。

Placeは基本的には独立したRacket virtual machineであり*2GCなどもPlaceごとに実行されます。*3

メッセージはplace channelを経由してやりとりされます。place channelにはlistやpairなどの構造化されたデータを送ることができます。またplace channel自体を送信することもできるので、直接の親子関係にないplace同士も直接やりとりさせることができます。

place channelで送れる値は基本的にimmutable(一部atomicなデータのvectorなど例外あり)です*4が、この制約があるとthunkなども送れなくなります。*5

Thread等の場合は開始用のコードをthunkで指定したりできるのですが、Placeではそれができないので、Placeを新しく作成する場合は module pathで指定し、そこでexportされたmain関数を実行することでPlaceの開始処理を行います。*6

(このあとAPIの話とマクロを利用した抽象化がありますがカットするので気になる方は論文を読んでください)

実装について

Placeがない状態のRacket virtual machineは単一のgarbage collectorとOS threadから成り立ちます。 Racketにはthreadのサポートがありますが、これは並行性のサポートであり並列性でのサポートではないそうです。(concurrentなタスクに分割することはできるが、マルチコアで同時に実行させてパフォーマンスを上げるものではない)

PlaceありのRacketではOSのスレッドを複数使い、Racket virtual machineを稼働させます。 並列実行でのパフォーマンスを向上させるために、Placeは可能な限り独立・疎結合になっており、メモリ領域も分離させることで局所参照性を最大化させています。この分離があることで、PlaceごとにGCが可能になるといった点もあります。*7 PlaceごとのGCに加えて、全Placeで共有されているmaster GCというのもあり、こちらはグローバルで共有されているオブジェクトを管理しているようです。

global変数とthread local変数

Racketは10年半開発されてきており、コードベースにはたくさんのグローバル変数があります。 これがスレッド導入の障壁であり、Place導入のためにはこれの解決が必須になります。

残念ながらすごく手軽に解決する方法はなさそうで、grep とCIL解析を使用して、Racket 実装内の 719 個のグローバル変数を監査しタグ付けし、以下のように分類していったようです。

  • READ_ONLY: 読み取り専用のシングルトン・オブジェクト(scheme_true, scheme_falseなど)
  • SHARED_OK: 共有が許可されているもの
  • THREAD_LOCAL_DECL: Placeごとに局所化が必要なもの

グローバル変数を局所化させるにあたって、大きく移動させるとランタイムシステムへの修正が大きくなりすぎる*8のでOSがサポートしているスレッドローカル変数を使用してplaceローカルな変数を作ったそうです。

thread local storageの操作には pthread_get_specific()より _threadlocal とか _declspec(thread) などのコンパイラが提供しているアノテーションを使ったほうが高速らしいのですが、OSによっては(macやwinなど)ではうまく動作しないようです。 windowsではコンパイラの提供するスレッドローカルのサポートがありますが、windows XPではDLL内では使えないようです*9 macはこの論文が書かれた時点では上記のようなコンパイラのサポートが提供されていないようです。 論文ではプリプロセッサを定義して、OSごとにスレッドローカル変数へのアクセス方法を切り替えるような工夫を行っています。

GC

racketの起動時にmaster GCはリードオンリーなグローバル変数やシンボルテーブル、解決済みのモジュールpathテーブルなどを割り当てます。 上記が終わったあと、initial placeはmaster GCから切り離され、自身専用のGCインスタンスを作成することになります。 このブートストラップフェーズのあとはmaster GCは通信チャンネルや共有される値の割当などごく少量のことしか行いません。

PlaceでのGCはplaceのローカルヒープを独立して回収するか、master GCと協力してglobalなオブジェクトを回収する(=グローバルコレクション)かに二分されます。 グローバルコレクションではすべてのPlaceが一時停止しますが、基本的にmaster GCからの割当はプログラムの初期化時にほぼ全てが終わるため、大体の状況ではプログラムの処理中で発生することはあまりないそうです。*10

グローバルコレクションを開始する際にはmaster GCがすべてのPlaceに対してmutationを停止し、収集を開始するようにシグナルを送ります。 すべてのPlaceがオブジェクトにマーク付けを行ったあと、master GCが不要なオブジェクトを回収します。 PlaceのローカルGCの場合はフラグメンテーションを防ぐためにオブジェクトを移動させますが、一方でmaster GCの場合は移動させません。*11

channel

前述のplaceローカルでのGCを成立させるためにチャンネルを介したメッセージングではデータをコピーして行います。 placeチャンネルはこのプロセスを新しいメモリをorphanアロケータに要求することで開始します。 orphanアロケータはすべての割当をどのGCによっても管理されていないメモリーブロックに対して行います。

次に、placeチャンネルはメッセージ全体をorphanアロケータに割り当てられたメモリーにコピーします。 コピーが完了したあと、メッセージにはオブジェクトの参照とmaster GCによって管理されている共有オブジェクトのみが含まれることになります。 その後、送信元のplaceはこの新しいメッセージとorphanアロケータによって割り当てられたメモリー送信先のplaceへ送信します。

メッセージを受信したplaceチャンネルは、孤立したメモリーページをnursery generationとして採用し、ユーザープログラムにメッセージを返します。 nursery generationを経ても生き残ったメッセージコンテンツはplaceローカルなメモリーに再配置されます。(長さが1024byte以下の場合はnursery generationをスキップして直接ローカルアロケータにコピーするという最適化が入っているそうです。) このプロセスにより、送信側・受信側でアロケーションの調整なく非同期メッセージングが可能になります。*12

lock

上記の工夫で爆速racketが完成!と行きたいところですが、racketのGCでは mprotect() *13 がたくさん呼ばれており、これがボトルネックになることがあるようでした。

mprotectはOSのページテーブルロックを取得するため、通常のsequentialなracketで問題にならなかったmprotect()呼び出しが、placeありのracketでは並列にGCが走りlock contentionが高まり、ロック待ちでボトルネックになるという構造のようです。 この構造を回避するために、racket allocatorで大きなブロックを確保するようにすることでブロック数を削減し、結果的にmprotectの呼び出し回数を劇的に減らすようにしたそうです。

まとめ

実装には2年位かかったそうです。が、不具合などはかなり少なく実装できたそうです。 著者らが以前にランタイムシステムにconcurrencyサポートを実装した際は、数ヶ月の追加テストを行い多数のレースコンディションを発見したそう*14なので、sequentialが前提になっている巨大なランタイムに後からこのようなサポートを追加する場合はplaceのような実装方法を取ると良さそうですね。

ところでErlangはメッセージに流れるオブジェクト用のアロケーションだけ静的解析で検出して(軽量)プロセス用ヒープじゃなくて共有用ヒープにメモリ確保する。*15って書いてあったんですが、これは初耳でした。おもしろいですね。

ということで以上です。

*1:巨大なランタイムにlockを適切に入れていく作業はかなり大変なのは想像に難くない・・

*2:初期段階ではリードオンリーなコードやJITによって生成されたコードなどをplace間で共有することはないらしいですが、長期的にはやりたいとのこと

*3:こういうのがあると、全VMが止まるstop the worldとかを回避できたりするのでよいですね

*4:shared memoryなのでmutableなデータだとdata raceが発生する可能性があるので、この辺は大事ですね。

*5:thunkについては https://www.fos.kuis.kyoto-u.ac.jp/~igarashi/class/isle4-05w/text/eopl014.html などを参照

*6:なかなか豪快な作り方っぽさを感じますね。racket virtual machineの起動オーバーヘッドがどのくらいかはあまりわからないんですが、後述するmaster GCなどでの仮定などからも、起動時にまとめてplaceを作っておいて順次処理させるといった使い方が想定されていそうです。そもそもこれってconcurrentをサポートしたいと言うよりは、マルチコアなハードウェアを活かしたparallelな機構を備えたいという動機(concurrentサポート自体はすでにある)らしいので、そう考えるとplaceをたくさん動的に立てたいというシチュエーションは無いのだと思います。Erlangのようにたくさん(軽量)プロセスを立てて、たくさんメッセージを送り合うのとは思想が違うはず。

*7:(軽量)Process/ActorごとにGCというのはErlangとかPonyとかもそういう感じですね。

*8:大きな修正を入れないというのがPlace導入の最大の肝なのでここは重要

*9:vista以降なら使えるけど32bit racketはwindows xpで動作する必要があるなど歴史を感じる部分がありますね

*10:逆に言うと、そういう仕組みであることを理解して使わないとすごいことになりそう

*11:master GCが稀なのとコンパクションが不要になる程度の荒い粒度で管理されているそうなので必要なさそうですね

*12:普通に自分のplaceのGCが管理してるメモリー領域のポインタ渡すとlocal placeでGCが起きたときに死んだり、それをlockで回避しようとすると泥沼なので、それとは別などこにも所属してない領域にメモリを確保してそこでやりとりするって感じですね。

*13: mprotect()は、同一プロセス内のメモリ保護機能で、一時的にheapの特定領域をread onlyなどにすることができます。GC中にいじられないように保護してるんですかね?

*14:バグの質も異なるらしく、lockベースの実装では競合状態による見つけにくいタイミングバグ、placeのような実装では壊れた参照によるバグ(GCのタイミングでだいたい見つかる)ですぐ治るものだったそうです。

*15:The Erlang implementation employs static analysis to try to determine which allocations will eventually flow to a message send and therefore should be allocated in the shared heap.

ぼんくらITエンジニアでもYouTubeとスタサプでTOEIC 900点突破できたので勉強法をまとめていく

2020/2にbefore 600点台(正確な値は紛失)から始めて2020/9に目標(900点以上)を達成しました₍₍ (ง´・_・`)ว ⁾⁾

英語学習は最初の入門のところが割と難しいなと思ったので、やったことをまとめておきます。(なお、この記事は頑張ったから自慢したい気持ちが90%、他の人に参考になったらなという気持ちが10%で提供されています。)

ちなみに英語指導経験があるとか、すごいペラペラになったとかそういう感じではないので、近くに英語に詳しい人がいる場合はそちらの人の言うことに従うのがおすすめです。(あくまで素人がやったことが書いてあるだけ)

基本的にリスニングについてのみ書きます。

はじめに

ある日突然英語やるかーと思い立ち、勢いでスタサプTOEIC https://eigosapuri.jp/toeic/ のパーソナルコーチプランに登録しました。 コーチングプランでなにやるかについては「スタディサプリ TOEIC コーチングプラン まとめ」あたりでググると出てきます。

あとはコーチの言うとおりにやっていけば自然と目標達成できる感じなんですが、その前にちょっとやっておいたほうが良いかなと思うことがあります。

英語の音について学習する

そもそも英語って日本語と音が違うんですよみたいなことは耳にタコができるレベルで聞いたことあったけど、実際どう違うのか?を体感する機会にはあまり恵まれてこなかったので、同じ境遇の人はまずそこから勉強するのがおすすめです。

スタサプTOEICは問題量・シャドーイングのやりやすさ・動画講義の質などの点でかなりよく出来ているんですが、音声変化や母音・子音についてのコンテンツは(筆者がやっていた時代は)豊富ではないので、そこを補ってあげるとディクテーション、シャドーイング*1の効率が段違いになります。

このあたりをまず意識すると、とりあえず音声をシャドーイングしてるけど「どこに注目していいのかわからなくてただ読んでるだけ」といった状態になり時間を浪費してしまうのを防げると思います。

音声変化・ストレス編

順番でいうと子音や母音のほうが先だとは思うんですが、とりあえず登る山を見るというところで「ニック式英会話」をおすすめします。

www.youtube.com

最初に言ってる英語については「一切わからん!」って感じだと思う*2んですが、一通り解説を聞くと「まあ・・わからんでもない!」くらいにはなると思います。このあたりで、そもそも「音が変化するという知識がないから聞き取れない」という問題をまず乗り越えておき、スタサプTOEICで「変化してる音を捉えきれるようにする」ような練習を積むのがおすすめです。

とはいえ、いきなり動画を全部みても脳に入ってこないと思うので、最初はニック式英会話の↑のシリーズを5回分見るくらいがいいんじゃないかと思います。

次にストレスについてです。

ストレスってなに??って状態だったんですが、僕は「サマー先生と英会話 ! 【プライムイングリッシュ】」の下記の動画を見てイメージを掴みました。

www.youtube.com

機能語・非機能語でストレスのかかりかたが違ったりとか、弱形発音があって短く言われるぞとか、知らないと聞き取りできないというか聞き取る練習をするぞ!という気持ちになることすら不可能なので、この辺の前提知識は身につけておくとよいと思います。

ストレスのかかり方から生まれる英語のリズムみたいな観点でいうと「英語発音専門ドクターDイングリッシュ」の下記動画もおすすめです。*3

www.youtube.com

弱形発音についての動画もあります。

www.youtube.com

いきなり動画をたくさん貼ってしまいましたが、この辺の知識を得るだけでリスニング能力を上げる下地はかなり出来てくるのではないかなと思います。

なお動画だけだと全体像があいまいになるかもしれないので「英語 音声変化」など適当なワードでググってみるといくつか解説サイトがあるので、動画をある程度みたぞ!と思ったら仕上げに見てみましょう。

子音・母音編

appleのaは”あ”じゃないぞみたいなのは聞いたことがあるとおもいますが、実際そこをちゃんと勉強したことがなかったのでそちらも勉強しました。 これに関しては英語耳が良いのでぜひ読んでみてください。*4

英語耳[改訂・新CD版] 発音ができるとリスニングができる | 松澤喜好 |本 | 通販 | Amazon

英語耳知らずにシャドーイングしてた時間返してってくらい良いです。

ちなみにyoutubeでも検索するとかなり色々あります。(本のほうが網羅的に出来るので本の補完として見るのがいいかなと思いました。)

例えば「あいうえおフォニックス」は解説が丁寧なのでおすすめです。

www.youtube.com

また、「がくちゃん GACKT official YouTube」の動画も勉強になりました。

www.youtube.com

ちなみに、この辺の基本は忘れがちだったりするので、それぞれチャンネル登録してアップされた動画を継続的に見ると良いです。

英語の学習方法について学習する

スタサプTOEICではディクテーションやシャドーイングなどを行うようになっているのですが、こいつが曲者で、最初のうちは「別に繰り返そうと思えばできるけど・・・で・・・?」みたいな気持ちになりがちです。(僕はなりました)

で、これの対策としてもyoutubeを漁ると色々出てきます。

特に僕の中でわかりやすかったのが「Yumi's English Boot Camp」のこちら

www.youtube.com

動画中で言っている「英語を聞く時間を増やすだけでは足りなくて、集中して聞く・聞き取れない部分を分析する」というのがポイントです。 シャドーイングでは、聞き取れない原因になっている課題を発見する => そこを聞き取れるようにする というループがポイントなので、ただ漫然と繰り返し聞いても課題を発見できず、上達までに時間がかかる(はず)です。*5*6

長々と書いてきましたが、英語学習が自転車のペダルをこぐってイメージなら、英語の音や学習方法について学ぶのは自転車のギアを上げる作業なので、ギアを上げずにこぎ続けたり、まったくこがずにギアだけ上げようとするといったことがないようにするのを心がけると良いと思います。(伝われ)

スタサプTOEICについて

さてここまではスタサプ以外の解説が95%なんですが、実際に費やした時間としてはスタサプが95%でその他5%という感じです。

基本的にはコンテンツ通り、動画講義をみる・問題をやる・ひたすらシャドーイング*7という流れになっています。 どのくらいのペースで何をやるか?については「スタサプ パーソナルコーチプラン スケジュール」あたりで検索すると他の人の体験記などが得られるので、それを参考にすると良いと思います。

その他の使い勝手や内容とかはググってもらうとして、僕が気をつけていたところを紹介します。

時間

コーチングプランであればコーチと相談で変わってくると思いますが、僕は一日3時間やりました。

初期は平日2時間,土日で5.5時間ずつやってたんですが、土日がきつすぎて集中力が0になっていたので、朝5:30に起きて毎日3時間やることにしました。(仕事の後だと集中力がなくなってるし、早起きしてやると頑張ってる感が出てモチベーションにつながるタイプだった。)*8

実際にやる時間は、いつまでに何点になっていたいか?をベースに決めると良いと思います。 諸説あると思いますがスタサプ的には毎日3時間を2ヶ月で100点アップペースとしていて、世の中的にも200時間で100点とか言われたりしているようです。 *9また、英語がある程度話せるようになるまで1000時間などの話もあります。なぜ1,000時間の英語学習が必要なのか|【公式】TORAIZ[トライズ] - コーチング英会話スクール

こう考えると、例えば

  • ある程度話せるようになりたいから1000時間が目標。そこまで時間かけたくないから一日30分 => 2000日 = 5.5年後
  • 来年までにTOEICを300点あげたいから600時間が目標。 => 一日2時間だと300日, 3時間だと200日なので一日2時間でよさそう

など当たりをつけられるようになると思います。 とはいえ集中してやるのが前提になるので、一日10時間とかはかなりモチベーションが高くないと難しいと思いますし、個々人の学習能力や年齢*10などにもかなり依存するので本当にざっくりです。ここでは時間が短すぎると効果でるのが10年後とかになってしまうかもといったところだけ抑えてもらうと良いのかなと思います。

スタサプの学習目標の選択肢には1日30分ってのは無い*11んですが、そのくらいの時間でも意味はある気がします(逆に集中できて効率良さそう)。 ただし、英語や英語学習の前提知識(音声変化やシャドーイングのやり方)などを抑えないまま時間を投資すると、ただ早口でカタカナ英語を話してる人状態になり、全然リスニング能力が上がらないということも考えられる*12ので、そこまでモチベ高くないんだけどちょろちょろはやりたいなって人でもこの辺は抑えるようにしたほうが良いと思います。

とはいえ大学受験のおつりで一ヶ月位で普通に高得点とれたよーみたいな報告も見かけるので、この辺は本当に人それぞれかもしれません。

深さが大事

シャドーイング・オーバーラッピングは 遅いスピード で深く分析するのがおすすめです。*13 僕の場合は最初の方は速いスピードで出来たぜやったーみたいな感じでやってたんですが、それだと「実際は聞き取れてないけど文脈で埋めてるところ」とか「弱形発音で短く言われてるんだけど、元から速いから気づけ無い」などの問題が出てくるのでゆっっっっっっくりやるのがよかったです。勢いで飛ばさないの大事。

分析はどのくらいやればいいんだってところですが、僕は1文30分(設問ではなくピリオド単位での1文)以上出来ると実り多い学習になったなと感じることが多かったです。とはいえ自分でそこまで深く分析するのはかなり集中力が必要で、そんなものは無いときのほうが多いので、動画でネタを仕入れて課題を見つけやすい状態に保つのを心がけていました。

パーソナルコーチプランにすべきかどうか

以下の理由でお金に余裕があればやってみても良いと個人的には思いました。*14

  • 毎日2時間とか3時間とか英語の時間とるのは慣れないと結構大変
  • 特に最初のうちは、成功体験が無いのでモチベーションが維持しづらい
  • 毎日、このくらい勉強しましたーとか、シャドーイングしてるけど全然うまくなった感じがしないんだけど・・・みたいな自慢(?)とか愚痴(?)とかを言える人がいるのが割とやる理由になった。多分日報を送るコーチがいなかったら途中でやめてたと思う。
  • 英語を将来的に活かす場合は、(職種にもよるが)投資対効果はかなり高い部類と思われるのでパーソナルコーチプランくらいはペイするはず(と自分に言い聞かせることが可能)

終わり

ということで以上です。

勢いで書いたけどこの記事意味あるのかな🙄 って正直思ってますが、おすすめの英語動画リンク集としては意味あるかなと思ったのでそのまま投下します。

素人が書いた勉強論はあんま信用ならないですが、動画あげてる人はだいたいプロなんで動画の方は積極的に見ていくと良いと思います🙏

TOEICの次は英検一級を受験予定ですが、過去問を解いたらリスニングで余裕で落ちたので先は長そうです(◞‸◟) *15

なおこの記事はFOLIO Advent Calendar 2020 6日目として書かれました。

*1:スタサプTOEICで出てくる勉強法

*2:聞き取れるぜって人はたぶんTOEICのリスニングは余裕だと思う

*3:ちなみに挙げてる動画に出てくる人はドクターDではないです。ドクターDの動画も参考になるものが多いです

*4:ただ、母音編はそこまでわかり易くない(と感じた)ので、ひとまず子音だけ抑えてもよいかもしれません

*5:センスの化身みたいな人は別

*6:ちなみにたくさん聞いて、よく使われるフレーズを覚えるといった目的では有効だと思うので、英語を垂れ流すのに意味がないわけではないと思います。ただリスニング能力を上げるのであれば集中と分析を重視したほうがよいだろうとは言えると思います(実体験ベースではある)

*7:ディクテーションはやってたけどシャドーイングの方が効果は感じた。いくつかブログ等を見る限りこのへんは人による感じがします。

*8:ちなみにこの意識の高さはTOEIC目標達成の翌日から消え去りました・・・

*9:500->600点と800->900点は違うでしょみたいな指摘もあるようですが、学習方法をちゃんと調整できているかなどに大きく依存するとは思うのでざっくりでいいと思います。

*10:やっぱ若い方がリスニング伸びやすいとかはあるらしい

*11:カスタム目標にはある

*12:全く上がらないってことは流石にないと思いますが

*13:出典は忘れたけど何かの動画で見た

*14:でもまあ人それぞれだよね

*15:英検一級といえば単語がゲキヤバなんですが、そっちについては血反吐を吐きつつなんとか8割くらいは取れるようになりました。

Inside Fintech Meetup ~ Finatext × Kyash × FOLIO ~で発表しました

speakerdeck.com

Inside Fintech Meetup ~ Finatext × Kyash × FOLIO ~ - connpass という勉強会で発表しました。

ここ1年弱くらいずっとやってたので話すネタはいくつかあったんですが、Scala的な部分は趣旨じゃなさそうだしロボアドの仕組みを説明してもいいけどリプレースの話もしたいし・・・と、割とトピック選びの時点で難産でした。 最終的にはイベントストーミングにしたんですが、弊社イベントストーミングの話するの3回目くらいな気がしますね・・・🙄

とはいえ理解が難しい部分、知識差がある部分をどうカバーしていくか?っていうのは重要なテーマだと思うし、イベントストーミングは要件定義ではなくチームビルディングにも使えるんだぜってのは個人的には結構面白いかなと思ってたので発表できてよかったかなーと思っています。

ところで2020/09/25(金)にFOLIOでcats-effect,fs2,doobie使って証券システム作ってみた (仮)っていう発表があるので、 Scala的なところが聞きたい人はこちらもぜひご参加ください(宣伝)

scala-tokyo.connpass.com

pdfを翻訳機に書けやすくするchrome拡張を作った

FOLIO Advent Calendar 2019 - Qiita 13日目の代打です。

chrome拡張を作った

pdfを翻訳機に書けやすくするchrome拡張を作りました。

GitHub - matsu-chara/pdf-translate-replacer

需要あるのかわかりませんがwebstoreにも公開しました*1

chrome.google.com

なにこれ

pdfをgoogle翻訳にコピペすると文末ではなく、pdfの行末で改行が入ってしまうため翻訳ミスが発生します。 このクローム拡張を使うと、文末の . を元に改行を適宜いれた形に整形しなおしてくれます。*2

こういった整形ツールは集中力がなくなった時やとりあえず外観を知りたいときなどに非常に便利です。 最初に日本語でざっと読んでから、次に英語を読むようにするとスルスル頭に入ってくるようになります。*3

一方で自分が読む分野の論文だと e.g.section 1.2.3 などが多く、false-positiveな改行が挿入されてしまう問題がありました。 そこで、自分が読む論文に合わせたオリジナルのreplacerを作りたい!という気持ちになったので作りました。*4

↓みたいにreplaceしてるだけなので使いにくいところがあったらPRするなりforkするなりしてお使いください。 https://github.com/matsu-chara/pdf-translate-replacer/blob/master/script.js#L23

前作った同じようなやつをコピペして中身変えただけなので作業時間は15分です。 ちなみにチキンマカロニグラタンを食べながら作りました。(行儀)

どうやって使うの

以下で整形されます。

  1. インストールすると っていうアイコンが出てくる
  2. 翻訳したいテキストをpdfからコピー
  3. Google 翻訳 に行って翻訳欄にペースト
  4. っていうアイコンをクリック

以上です。

*1:というか変換ルールが完全に自分用なので、forkして自分好みにルールを変えて使ったほうが良さそう

*2:そういえば整形してるんだからreplacerじゃなくてformatterだよなって今思いました(時既に遅し)))

ちなみに、同様の現象に対する先行事例として以下が開発されています。

どちらも大変お世話になっていました。ありがとうございます。((これらの力がなかったら40pくらいある https://15721.courses.cs.cmu.edu/spring2016/papers/whatgoesaround-stonebraker.pdf とか多分挫折してました。ちなみにこれはデータモデリングについての35年分の歴史を辿り、そこから得られる教訓についてまとめた論文でとてもおもしろいです。

*3:ちなみにかっこが含まれているときなどに文の肯定・否定がひっくり返ることがたまにあるので原文も読むようにしたほうが良いです。

*4:調べてないですが、おそらくクローム拡張に既に同じようなやつある気がします

ScaleCheck: A Single-Machine Approach for Discovering Scalability Bugs in Large Distributed Systemsを読んだ

FOLIO Advent Calendar 2019 - Qiita 18日目です。 前日は krrrrさんの RustでもServer::Starterでhot deployをする - decadence でした。

毎年この時期にしかFASTを読めていない まっちゃら (@matsu_chara) | Twitterです(´・_・`)

今回はFAST '19からScaleCheck: A Single-Machine Approach for Discovering Scalability Bugs in Large Distributed Systems | USENIXを読んだときの勉強メモです。 自分が面白いと思ったところを中心にしたり、個人的に調べた内容が入っていたりするので正確かつ完全な情報は上記論文や関連文献等を直接読んでいただければと思います。

ざっくり

大規模ストレージシステムに関する新しい種類のバグである Scalability bugs を検出するScaleCheckという手法が提案されています。 Scalability bugsとはノードが数台〜数十台程度では顕在化せず、数百台以上の大規模クラスタになって初めて顕在化するようなバグのことを指しています。

ScaleCheckはこのScalability bugsを実際に数千台規模のクラスタを組むのではなく、1台のマシン上で上記のような問題を潜在的に抱えているかどうかを確認する方法を提供します。 論文ではScaleCheckの提案のみならず、実際に1台のマシンのみを用いてCassandra,Riak等のシステムに適用し、10個の既知のバグ+4個の新しいバグを検出することに成功したことも述べられています。

背景

大規模サービスを運営する企業で運用されているクラスタは、そのノード数も巨大になりがちで論文では以下のような例が挙げられています。*1

  • Netflix runs tens of 500-node Cassandra clusters [34]
  • Apple deploys a total of 100,000 Cassandra nodes [2]
  • Yahoo! revealed the largest Hadoop/HDFS cluster with 4500 nodes [35]
  • Cloudera’s customers deploy Spark on 1000 nodes [24, 27].

本論文はこのような巨大クラスタを運用する際に顕在化するクリティカルなバグをscalability bugsと呼称し、cloud-scale時代に発生するようになった新世代のバグであると呼んでいます。

実際に巨大なクラスタで発生するバグとしては以下のような実例が挙げられています。

f:id:matsu_chara:20191214180153p:plain:w600

https://www.usenix.org/sites/default/files/conference/protected-files/fast19_slides_stuardo.pdf#page=3 より

これを見るとたしかに100, 1000ノード単位で顕在化するバグが存在するようです。

例えばcassandraの内部処理でノード数依存でO(N3)の処理があり、計算に0.1~4sec程度時間が必要になった事例が挙げられています。 こういったことがあると、gossipプロトコルで最新のノード情報を取得するまでに時間がかかりすぎ、あるNodeが故障<->復旧の各状態を高速に繰り返すflappingと呼ばれる問題を引き起こします。 こういった問題はノード数が少ないと影響がでにくいため、クラスターが大きくなった時に初めて顕在化する問題だとされています。

このような問題を見つけるために実際に巨大なクラスタを組んで検証するのはハードルが高いため、 1台のマシンでその問題を検知するためのScaleCheckの提案につながったというわけです。

Scale Dependent Loops

Scalability bugsを検出するためには、Scalability bugsの原因は何なのか?を考える必要があります。

本論文ではまず Scale Dependent Loops が挙げられています。 これはノード数に依存するようなデータ構造のループのことです。

ScaleCheckのSFindでは、メモリ消費の増加傾向からこのループ構造を検出します。

実際には上記以外にもファイル、パーティション、テーブルなど様々な軸で、スナップショット、マイグレーションなど様々なワークロードについて問題を検出するようです。

large-scale testing (in one machine)

巨大なクラスタを使ってテストを行えば当然Scalability bugsを検出できると思われますが、一方で様々なハードルがあるため1台のマシンでテストを行えるようにしたいところです。 しかし実際にそれを行うためには下記のような様々な困難を解決する必要があります。

f:id:matsu_chara:20191214183113p:plain:w450

https://www.usenix.org/sites/default/files/conference/protected-files/fast19_slides_stuardo.pdf#page=11 より

STestでは上記をSPC+GEDA+PILというテクニックで解決し、1台での大規模テストを行えるようにしています。 詳しく説明すると長くなりすぎるため下記では要素のみの紹介とし、具体的な解説は論文に譲りますので興味がある方はそちらを御覧ください。

ナイーブに1台に複数プロセスを立てるのだと50ノード程度しか立たないため今回の目的には向かないようです。 そこでSingle Process Cluster(SPC)として1プロセスに複数ノードを立てる(つまりスレッドでノードを管理する)手法が導入されています。

しかし単純なSPCを行うと、イベントキューやワーカープールがノードごとに作られるためリソースを多大に消費します。(120ノード程度とのこと)

これらを節約するためにGlobal Event Driven Architecture(GEDA)を導入します。 GEDAはグローバルなイベントハンドラを用意し、ノードごとの通信をグローバルイベントキューへのキューイングとして表現します。 また各ノードはグローバルなキューからイベントを取得し処理を行うだけです。

f:id:matsu_chara:20191214191203p:plain:w450

https://www.usenix.org/sites/default/files/conference/protected-files/fast19_slides_stuardo.pdf#page=24 より

上記だけでも大規模テストができるとのことですが、 これだけだと特にCPU-intensiveなタスクの際に結果が正確でないケースがあるため、CPU intensiveな計算をsleepに置き換えるProcessing Illusion(PIL)というテクニックを導入しています。

PILは画像を見ると何をしたいかがわかりやすいと思います。

f:id:matsu_chara:20191214192513p:plain:w450

https://www.usenix.org/sites/default/files/conference/protected-files/fast19_slides_stuardo.pdf#page=28 より

検証

実際にいくつかのミドルウェアで検証を行い、既知のバグや新しいバグを検知しているようです。

新種のバグとしては以下の物が挙げられています。

Cassandraのdecomission時の不安定性 *2

f:id:matsu_chara:20191214190109p:plain:w450

HDFSのsnapshot diff size, metasave

f:id:matsu_chara:20191214190237p:plain:w450

感想

問題設定として様々なミドルウェアに潜む巨大なクラスタで発生するバグを包括的に捉えるのは興味深く感じました。 実はScalability Bugsという問題設定はHotOS'17 Scalability Bugs: When 100-Node Testing is Not Enough において提案されています。 同一の著者グループによる研究のようなので、より深く問題を理解するためにはこちらもみておくと良いでしょう。

ScaleCheckは任意のミドルウェアにすぐ適用できるフレームワークではなく、ミドルウェア側の実装修正が必要になっています。 しかし各ミドルウェアに対して179 ~ 918 LOCレベルなので、そこまで大きな変更を加えずに対応することが可能そうです。

リアルワールドの問題を実際に発生させられるように大規模クラスタを模倣できる開発環境を作るという取り組みを論文中ではlarge-scale testingを民主化すると表現しているのですが、巨大企業に所属していなくても大規模ミドルウェアの開発に貢献しやすくなるという点で意義深いと思いました。*3

FASTあたりの論文を読むと堅牢な分散システムが崩壊していくのはよく見られる(?)*4のですが、実運用では細かいところを追いきれずある程度信用してしまっている側面もあるかと思います。 どのようなミドルウェアファイルシステムでも完璧に障害が起きないようにするのは非常に難しい(はずな)ので、どのような問題が起きうるのか?を研究を通して学んでいくだけでも、(実際にそのテクニックや技術を使うことがなくても)実運用に役立つ視点や、考え方を得られるのではないかなと思っています。って結びの言葉を書いてたら去年も同じようなことを書いていました。成長...

Replicated State Machinesでのストレージ故障からのリカバリー - だいたいよくわからないブログ

ところで、社内からそもそもgossip部分がスケールしないのはアーキテクチャ的に見えてるしループ改善してもすぐ帯域やCPUで限界が来そう*5という指摘がありました。そういった部分をどう乗り越えるかは論文の対象外ではありますが、現実の厳しさを感じつつこの記事を終わりたいと思います。

*1:1クラスタじゃないと思いますが10万のcassandraって何に使ってるのか気になりますね

*2:筆者はCassandraに詳しくないため前提や最新バージョンでの修正状況などを把握できていません。ご了承ください

*3:colocation factor=50のnaive packingでもEC2 10台程度で500ノード建てられるので、そちらでもみたいなところはありますが、ソロコントリビューターでも気軽に貢献できることを目指すとなるともう少しハードルを下げたいと思うので。

*4:当社比というか、自分がいろいろな前提を理解していないだけ...

*5:>This model works well for a system that contains couple of hundreds of nodes https://www.allthingsdistributed.com/2007/10/amazons_dynamo.html より