ZooKeeperによる分散システム管理

最近作っているdistributed-git-serverではクラスタの状態管理にMySQLを使っているのですが、ロックをRDBで実装したり、ハートビートやノードの状態管理などを自前で実装する必要があり、だいぶ面倒だなぁと感じていました。ZooKeeperを使えばこのような課題をうまく処理することができるかもしれないと思い、この本を読んでみています。

ZooKeeperによる分散システム管理

ZooKeeperによる分散システム管理

個人的にはこれまであまり縁がなかったのですが、ZooKeeperは元々米Yahooで開発されたもので、Hadoop関連プロダクトやSolr、Kafkaなど様々な分散ミドルウェアクラスタの状態管理などの用途に利用されています。ざっくり言えば通知機能を持った高可用なディレクトリインデックスサービスのようなもので、これをうまく利用することで分散ミドルウェアにおける様々な課題を解決できる基盤となるソフトウェアです。

この書籍は基本的にはZooKeeperを使って分散ミドルウェアを開発する開発者向けに書かれており、ノードの管理、マスタの選出、タスクのキューイングなど分散ミドルウェアにおける一般的な課題について、ZooKeeperの機能をどのように利用すれば解決できるかが解説されています。また、ZooKeeperの内部構造についても説明されているのでZooKeeperを使ったミドルウェアを利用する場合にも役に立つと思いますし、分散ミドルウェアを開発している、もしくは興味のある人であればZooKeeperを使わないにしても同じような仕組みを実装することになるであろうと思われるので参考になる部分があるのではないでしょうか。

スケーラブルで冗長性のあるGitサーバをどう作るか?

GitBucketでの長年の課題の1つがGitリポジトリのスケールアウトと冗長化でした。Gitリポジトリを格納するストレージに分散ファイルシステムを使うというのは1つの解決策になりますが、分散ファイルシステムの運用はなかなか大変です。もっと手軽に使い始めて徐々にスケールできる方法はないものかと考えていたのですが、1つ思いついたアイデアを試すために実験的にコードを書き始めてみました。

github.com

基本的なアイデアは普通のGitサーバを複数台用意しておき、リポジトリを分散配置するというものです。例によってScalaとJGitを使って実装されています。

f:id:takezoe:20180114032907p:plain

Gitクライアントからのリクエスト(pushやfetch)はフロントコントローラーでルーティングされ、リポジトリの配置されたノードにプロキシされます。リポジトリは全く同じものが複数ノードに存在するので1ノードが落ちても動作を継続することができます。落ちたノードが復旧すると生存しているノードと同期して自ノードのリポジトリを最新化します。

コントローラーは各ノードのディスク使用率を把握しており、新しくリポジトリを作成したり、リポジトリの再配置を行う際はディスク使用率を参照してどのノードに作成するかを決定します。1リポジトリで1ノードのディスクを食い尽くしてしまうような巨大なリポジトリがあると厳しいですが、理論上はディスクが足りなくなってきたら新しいノードを足していくだけでOKということになります。

ちなみに後から知ったのですが、このアプローチはGitHub社のDGit(現在はSpokesに改名されているようです)と似ています。以下のブログに色々と情報が書かれているので参考になります。

githubengineering.com

githubengineering.com

上記のブログからではわからない点として、WebブラウザからのGit操作(ブラウザでファイルを編集したり、プルリクエストをマージしたり等)をどのように実現しているのか?という点があります。

GitBucketではファイルシステム上のbareリポジトリを直接操作しているのですが、この方法ではリモートリポジトリを冗長化するのでそういうわけにはいかなくなります。上記のブログからはSpokesでも同じようにgitクライアントからのリクエストのレベルでプロキシしているように見えるので、Webアプリケーションがローカルリポジトリを持っていてそこをいじってからSpokesにpushしているのかなぁと推測されますが、実際どうなっているのか気になるところです。

Scala向けの高速ビルドツールBloopについて

少し前にScala CenterからBloopというビルドツールがアナウンスされました。

github.com

実際に動かしてみたわけではないのですが、READMEやソースコードなどからどのようなものかは大体掴めるので簡単にまとめておきます。興味のある方は是非試してみて欲しいです。

Bloopはビルドツールと言ってもsbtを置き換えるものではありません(そもそもBloop自身はビルドツールを名乗っていません)。簡単に言えばnailgunでサーバを立ち上げてzincでインクリメンタルコンパイルするためのツールで、コーディング中のコンパイル確認用途に通常のビルドツールの代わりに使用することでコーディング→コンパイル確認のラウンドトリップを高速化することを狙っているようです。特にsbt以外のビルドツールを使っている場合にビルドツール側の対応を待たなくても最新のzincが使える点がメリットとして挙げられています。

なので、基本的には既存のビルドツールを使用しつつ、コーディング中はBloopを使うというスタイルになります。

なお、Bloop自体はソースディレクトリやコンパイルに必要なクラスパスなど必要最低限の設定で動作します。既存のビルドツール用の設定からこれらの情報を抽出して使用することが想定されているようですが、現状ではsbt用のプラグインしかないようです。

肝心のコンパイル速度ですが、以下のアナウンス時のブログ記事に、いくつかの中〜大規模Scalaプロジェクトをsbtでコンパイルした場合とBloopを使った場合のコンパイル時間の比較結果が掲載されています。

http://www.scala-lang.org/blog/2017/11/30/bloop-release.html

Sparkは1.4倍とBloopを使う恩恵が大きそうですが、sbtやScala本体だと1.1倍程度と微妙なところです。ただし、これはクリーンビルドの場合なので、本来Bloopのユースケースとして想定されているであろう部分ビルドの場合はまた変わってくるでしょうし、GradleやMavenでビルドしている場合はもっと大きな効果が見込めるのではないかと思います。

とはいえ、コンパイルがsbtプラグインに依存している場合は当然Bloopだけではビルドすることができないので結構使いどころが限られそうな感じがありますし、そもそもScalaをsbt以外のビルドツールでビルドしているのも割とレアケースなのではという気もします(何か理由があってsbtを使えないケースだとするとBloopも使えない場合が多そう)。また、Scala製大規模ソフトウェアのビルドの高速化に本気で取り組むのであればPantsなどの選択肢もあります。

ちょっと立ち位置が微妙な気がしなくもないのですが、手軽に導入できそうではあるのでとりあえず試してみるのはありかもしれません。

The Type Astronaut's Guide to Shapeless

先日Scala eXchangeに参加して、海外での予想以上のShapelessの人気ぶりを目の当たりにしたのでちょっと勉強してみようと思い、Underscore社が提供している「The Type Astronaut's Guide to Shapeless」という本を読んでみました。

Underscore社のWebサイトからは電子版を無料でダウンロードできますし、ペーパー版も有料でオーダーできます。また、ペーパー版はAmazonなどでも購入できます。

The Type Astronaut's Guide to Shapeless

The Type Astronaut's Guide to Shapeless

  • 作者:Gurnell, Dave
  • 発売日: 2017/05/04
  • メディア: ペーパーバック

ちなみにこの本はオープンソースで原稿自体はGitHubで公開されています。

github.com

Shapelessはケースクラスやシールドトレイトを使った列挙型で表現される代数的データ型に対してHListと型クラスを使ってジェネリックなプログラミングを可能にするライブラリで、うまく使いこなせばJavaではランタイムリフレクションを使わざるを得ないような処理をタイプセーフに記述することができる非常に便利なライブラリです。

この本は実用的な例を題材にShapelessの基本的な使い方を説明していくというものなのですが、分量も100ページ程度と少なめですし、英語も平易かつコードも多めなので読みやすいです。Scalaに関する知識がそれなりにないと理解が難しいとは思いますが、Shapelessでこういう書き方をするのは何故なのか?ということが順を追って説明されているのでShapelessがどういうものかを押さえるには良いガイドだと思います。

ただ、Shapelessの機能やShapelessを使ったコードの書き方自体がScalaの制約から来ている部分が多く、読んでいて結構つらみを感じました。とはいえDependent TypesなどIdrisにも通じる部分もあり、個人的には興味深く読み進めることができました。面白いライブラリなので使う使わないは別として是非一度触れてみて欲しいです。

2017年の振り返り

2017年もいろいろありました。今年も恒例の振り返りをしてみたいと思います。

f:id:takezoe:20171222150416j:plain

仕事関係

今年はサービスから離れてしまったのであまり自分でがっつり開発するという感じではなく、他のチームのサポート的な感じだったのですが、技術的な部分以外で悩むことが多かったような気がします。ただ、やはりサービスの運用から離れたことで以前と比べると時間的には余裕ができたかなと思います(今年は終電で帰ることもほぼなかったw)。

後述の執筆活動やOSS活動とも絡むのですが、業務に関連するものとしては、会社の若者たちと本を出したり、Apache PredictinIOのコミッタになれたのは目に見える結果としてよかったです。あと、社内ではType-Driven Development with Idrisの読書会に参加していました(4月からやってるのですが、まだ読み終わる気配がない…)。

takezoe.hatenablog.com

来年は仕事でも新しいことをやりそうな感じなので、またちょっと違う感じになるかもしれません。

イベント関係

今年はScala関係のイベントに多く登壇させていただきました。特に年末にはリヨンで開催されたScalaIO、ロンドンで開催されたScala eXchangeと海外でのカンファレンスでそれぞれショートセッション、ライトニングトークですが発表の機会をいただきました。

ScalaMatsuriではScala Warriorの発表をさせていただきました。ScalaIOで「この時の発表を見たよ!」という方がいらっしゃって驚きました。

takezoe.hatenablog.com

Scala福岡ではApache PredictionIOの紹介をさせていただきました。福岡に行くのは中学生ぶりくらいだったのですが、博多駅がすごい近代化されていて驚きました。

takezoe.hatenablog.com

Scala関西サミットは気合いの日帰り参加。GitBucketでスポンサーもさせていただきました。

takezoe.hatenablog.com

ScalaIOでは初めてのフランス訪問だったのですが、滞在中に駅が何度も封鎖されていてびびりました。GitBucketのユーザさんが何人かいらしてお話しすることができました。

takezoe.hatenablog.com

Scala eXchangeではGitBucketの紹介をさせていただきました。JGitに関して質問してくださった方がいたのですが、うまく答えられなかったかも。ロンドンでは愛するアーセナルの本拠地エミレーツスタジアムのツアーに参加してきました。

takezoe.hatenablog.com

takezoe.hatenablog.com

Scala関西で今年は終わりかなーと思っていたところに立て続けにScalaIOとScala eXchangeのCFPが採択され、11月、12月と連続してのヨーロッパ渡航だったのでちょっと体力的にしんどかったです。英語力に関しては相変わらず改善の必要性を感じました。

執筆活動

昨年から会社の若者達と執筆していたクローリングハックという本を出すことができました。途中でいろいろあって1年くらいかかってしまいました。体力的な問題から書籍の執筆は年々厳しくなっていきますね…。

takezoe.hatenablog.com

また、今年は久しぶりにSoftware Designさんで記事を書かせていただきました。Git特集の一部でGitHub、BitBucket、GitLab、GitBucketを比較するというものです。

takezoe.hatenablog.com

あと、実作業としては何もしていないのですが、Akka in Actionの翻訳版の企画に関わらせていただきました。数年前から翻訳できないかと検討していた本なので形にしていただくことができてよかったです。

takezoe.hatenablog.com

OSS活動

今年はかなりアクティブに活動できたかなと思います。大きなところでは前述の通り、Apache PredictionIOのコミッタになりました。プロジェクト自体もIncubatorを卒業してトップレベルプロジェクトになることができました。多少なりとも貢献できたのではないかと思います。

takezoe.hatenablog.com

takezoe.hatenablog.com

Scalatraの開発もかなり進めることができました。Webサイトをhugo + GitHub Pagesへの移行をはじめ、magnolia-kさんがコミッタになっていただき、約1年ぶりのメジャーバージョンアップであるScalatra 2.6を無事リリースすることができました。新しいバリデーションフレームワークの追加や、各所に手を入れて不要そうな機能の整理、パフォーマンスの改善などを行っています。

takezoe.hatenablog.com

takezoe.hatenablog.com

GitBucketも引き続き月一回のリリースを継続しています。CIプラグインなど新しいプラグインもいくつか作ることができました。aadrianさんkounoikeさんにコミッタになっていただいたり、Scala関西サミットではスポンサーをさせていただいたり、ScalaIOでは海外のGitBucketユーザさんと会話をしたり、Scala eXchangeでGitBucketの発表をさせていただいたりなど、開発以外の部分でもいろんな活動ができたかなと思います。

その他では、AlpakkaにElasticsearchコネクタをコントリビュートしたり、elasticsearch-hadoopScala部分のコードを直したり、PlayでZipkinを使うためのplay-zipkin-tracingというライブラリを同僚から引き継いでOSS化したりしていました。play-zipkin-tracingではZipkinの開発者であるAdrianさんとのやり取りもあって刺激になりました。

takezoe.hatenablog.com

takezoe.hatenablog.com

まとめ

今年は仕事が一段落したこともあり、個人の活動に時間を使うことができたかなと思います。PredictionIOはもうちょっと普及させていきたいところではありますが、機械学習周りやSpark周りなど知識不足を感じるのでその辺は勉強しないといけないかもしれません。インフラ周りも自分で触る機会が増えそうなのでキャッチアップしていかないといけないですね。また、意図的に増やしている面もありますが、英語を使う機会も増えてきているのでこちらの勉強も引き続きやっていきたいと思います。

教養としてのScala勉強会に参加しました

会社の若者たちがScalaの勉強会を開催していたので私もお呼ばれして参加してきました。

d-cube.connpass.com

私は「頑張りすぎないScala」という発表をさせていただきました。

www.slideshare.net

これはScala関西で発表させていただいた「Non-Functional Programming in Scala」の内容をベースにしたものなのですが、Scala関西ではすでにScalaをやられている方を想定してお話しさせていただいたのに対し、今回はこれからScalaを始める方向けに修正しています。また、Scalaをどのように使うべきかという問題に関しては最近いろいろと考える機会があり、その結果も反映したものになっています。

若者たちがScalaをどのように学習したか(参考になった教材や勉強法など)、これからScalaを始める際に知っておいた方がよいことなどの発表もあり、これからScalaを始める人だけでなく、逆にScalaを教える際の参考にもなりそうです。最近のScala界隈の話題は高度化しすぎているきらいがあるので、こういう初心者向けのScala勉強会ももっと増えていくといいなと思います。

ところでちょうどManningから新しいScalaの入門書の出版がアナウンスされました。こちらはオブジェクト指向プログラミングから入って関数型プログラミングのエッセンスを学ぶ、という流れになっているようです。

www.manning.com

アーリーアクセスが始まったばかりなので完成までまだしばらく時間がかかるのではないかとは思いますが、現状では洋書でもなかなか良いScalaの入門書が存在しない状況なのでこの本には期待したいところです。

GitBucket 4.20.0をリリースしました

Scalaで実装されたオープンソースのGitサーバ、GitBucket 4.20.0をリリースしました。

https://github.com/takezoe/gitbucket/releases/tag/4.20.0

プルリクエストのマージ時にSquashもしくはRebaseが可能に

プルリクエストをマージする際に以下の3つのオプションからマージ方法を選択できるようになりました。

  • Merge commit: マージコミットを作成してマージします(従来通りのマージ)
  • Squash: コミットは1つにまとめられてベースブランチに追加されます
  • Rebase: マージコミットを作成せずにベースブランチにrebaseします

f:id:takezoe:20171222145441p:plain

クイックプルリクエス

リポジトリにプルリクエスト可能なブランチがある場合、リポジトリビューアの上部にプルリクエストを作成するためのボタンが表示されるようになりました。このボタンを使うとワンクリックでプルリクエエスト作成画面に遷移することができます。

f:id:takezoe:20171222145420p:plain

パッチファイルのダウンロード

差分ビューに表示している差分をパッチファイルとしてダウンロードするためのPatchボタンが追加されました。

f:id:takezoe:20171222145405p:plain

差分が巨大な場合、GitBucketはブラウザ上で差分のグラフィカル表示を行わないようになっていますが、その場合でもこのボタンでダウンロードしたパッチファイルを参照することで差分全体を確認することができます。

リポジトリの作成、フォークが非同期に

これまでのGitBucketでは特に巨大なリポジトリをフォークする際、リクエストのタイムアウトが発生してしまうことがありましたが、これを避けるため、今回のバージョンからリポジトリの作成、フォークを非同期で行うようにしました。

f:id:takezoe:20171222145519p:plain

既存のgitリポジトリからのリポジトリ作成

リポジトリの作成時に既存のgitリポジトリのURLを指定し、そのリポジトリの内容をコピーして作成できるようになりました。すべてのブランチ、タグも新しいリポジトリにコピーされます。

f:id:takezoe:20171222145553p:plain

サイドバーがオーバーフローした場合の表示の改善

リポジトリ名が長い場合、これまではサイドバーからはみ出て表示されてしまっていましたが、省略して表示するようになりました。

f:id:takezoe:20171222145613p:plain

WebフックでCreateEventをサポート

WebフックでCreateEventのサポートが追加れました。

プルリクエストでコンフリクトしたファイルの表示

プルリクエストがコンフリクトして自動マージできない場合、プルリクエストのステータス領域にコンフリクトしたファイルの一覧が表示されるようになりました。

f:id:takezoe:20171222145626p:plain

今回のバージョンではこの他にも様々な改善やバグフィックスを行っています。詳細についてはIssueの一覧をご覧ください。