GitLab魔改造カンファレンスで発表してきました

2/6(Thu) に株式会社ドリコムとピクシブ株式会社の合同で GitLab 魔改造カンファレンスが行われました

会場はドリコムさんのオフィスでとてもおしゃれな感じでした

ドリコムさんから 3 人,ピクシブからも私を含めて 3 人が発表しました

私が発表した理由として,ピクシブでは一部のサーバーを除いてサーバーの root をインフラの人間しか持てません
なので GitLab など新しいツールを使うにはインフラの協力が不可欠なのですが,私が GitLab 導入を提案した一人だったので成り行きで GitLab 導入やその後の運用を適当な感じでやっていました

そんな中,魔改造カンファレンスの話が回ってきたので私が発表する感じになったのが流れです

と前置きはこれくらいにして発表ですが,発表内容は簡単に言うと『GitLab の git アクセスをしている grit が遅いし闇だから rugged に書き変えたかったけど色々あった挙句に出来なかったよ!!』という魔改造カンファレンスなのに改造を全くしないプレゼンでした

そしてこの発表をした数時間後に

と公式がツイートしていて爆笑しました

これからプルリクしていきたいですね

発表資料

内容

GitLab の気になるところ

  • 遅い
  • 特にコミットやマージリクエストの diff を取るところが遅い
  • IO が刺さっているわけではない
  • slow query も出ない
  • では一体何が原因なのか?

Git の読み込みが遅い

  • Git の読み込みが遅いと気付く
  • 調査して直せないのか考えた
  • 時間足りなくて直すフェーズまで間に合わず…
  • とりあえず出来たところまで共有

grit 特徴 #1

  • Git のオブジェクトファイルや,git のコマンドの実行結果をゴリゴリやっている
    • 子プロセスの起動したり,ファイルをパースしたり…
    • ソースコードもだいぶ闇
  • ドキュメントが貧弱
  • オブジェクト指向や ActiveRecord を少し意識したような API 設計

grit 特徴 #2

  • 本家のリポジトリは既に更新が停止していて,色々な Fork がある
    • ソースコードもあまり綺麗でなく,メンテナンスをする気がある人があまりいない印象
  • GitLab が使っているのは独自 Fork(今回使用するのはこれ)
    • 最もメンテされている grit と思われる
    • しかし GitLab 以外から使われていることは考慮されていない
  • GitHub 本家も Fork してる
    • 最近更新はない

rugged 特徴

  • libgit2 の Ruby バインディング
    • libgit2 は C 実装で事実上の git の再実装
  • GitHub も使っているらしい
  • C の API をバインディングしているだけなので git の実装がかなり生で出ている
    • git の内部の知識がないと使うのが難しい
    • コマンドラインの使い方しか知らない人には使いにくい
  • C 実装だからか,Fork は少ない(スターは多い)
  • rugged に関するドキュメントは少ない
    • libgit2 はある
  • 将来的には GitLab も使いたいらしい(本気度は不明)

grit vs rugged

gem grit rugged
implementation pure ruby C extension
service GitLab Github
speed slow high speed
document little little

grit 仕様

  • grit で diff を取るとき子プロセスを立ち上げて git のコマンドを叩く
    • かなり遅いはず
    • GitLab で時折詰まったように感じるのはここ
  • コミット一覧はログからゴリゴリやる
    • Ruby だと文字列操作や配列の末尾に要素追加などは遅い
  • grit だと大きすぎる diff を取ろうとすると例外で落ちる
    • Grit::Git.git_max_size がデフォルト 5MB でこれを大きくすると大丈夫だが,標準出力が大きくなるとかなり時間がかかる
    • GitLab なら gitlab.yml の git: max_size を変更する
    • 今回のベンチマークでは一部がこれに抵触したので変更

ベンチマーク

  • grit はメソッドによっては子プロセスを呼び出す
    • ruby 標準搭載の Benchmark.benchmark はデフォルトで子プロセスの実行時間を出力しない
    • 引数を渡して表示できるようにする
  • コミットを 100 個の詳細情報とコミット同士の diff ã‚’ 99 組取ってみる

ベンチ結果

実際にやって…

  • 見たかったが,時間足りず…
  • 今後の課題とし(ry

grit/GitLab バグ

  • GitLab 周辺の gem は gem として登録されているにも関わらず GitLab 以外から使用することを一切考慮していない
  • 単体で読み込もうとするとバグに悩まされることになる
  • 自分が遭遇したバグ紹介

[gitlab_git] GitLab から使うことしか考えていない

  • gitlab_git が GitLab で git を実際に触る部分
    • grit を使うのはここ
    • rugged を使う場合はここを大幅に書き換える必要あり
  • GitLab は ActiveSupport が読み込まれるが,gitlab_git は独立した gem なので使うなら読み込む必要
    • しかし一部しか読み込んでいなかった
    • 具体的には try を使用していた
  • プルリク出した

[grit] require できない #1

  • Gemfile から path: 指定で読み込むと require できない
    • VERSION ファイルのパスが間違えていて起動できていない
    • すでにプルリクが出ている
    • 何ヶ月も取り込まれず放置されていた
    • マージしてもらえるように催促コメントする
    • マージしてもらえた!!
    • 今回のベンチマークにはもちろんこのパッチを適用
    • Fixed issue #32 · Pull Request #35 · gitlabhq/grit

いい話

[grit] 想定外のコミット #2

  • ある commit が読み込めない
    • オブジェクトファイルが想定外の形式らしい
    • 正しい挙動が不明なため issue 登録
    • Issue #37 · gitlabhq/grit
    • git のファイルを改行などからパースをしているだけの実装なので解析結果がおかしくなることはよくありそう

[grit] 偽りのコメントアウト #3

  • コメントアウトに嘘があった
    • git.rev_list を呼ぶと method_missing になると書いてあったが,実際は include したクラスに実装があった
    • プルリクしたが反応がない
    • どれも古くからあるコードで何が想定された動きだったのかわからない
    • method_missing の方にしても動きそうだったが,テストは通らない
    • Pull Request #38 · gitlabhq/grit

URL

まとめ

  • GitLab を高速化できないのか模索したら grit ã‚’ rugged に書き換えればいいのでは?という仮説ができた
  • ベンチマークを取って比較しようとしたが grit とか GitLab 周辺の gem がバギーすぎて大変だった
  • プルリクも出したりしたが,取り込まれることはあまりない
  • ドキュメントもないのでソースコードを読む必要があって大変
  • rugged は速いが書き換えるためには rugged のメソッドをよく把握する必要があるので面倒そう