GitLabのバックアップ方式をLVMスナップショット方式に変えたら以前より爆速になった

Adways Advent Calendar 2019 2日目の記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2019


 

どうも。
最近焚火がしたくてしたくてしたくてしたくてたまらなくて、休みにデイキャンしに行こうと考えているインフラの戸田です。
冬のキャンプをする際は、たとえデイキャンだとしてもしっかりと寒さ対策をしていきましょう。(誰目線なんだ

では本題にいきます。
数ヶ月前にGitLabのバックアップ方式を公式のスクリプトで行う(tarを実行している)方式からLVMスナップショットでバックアップする方式に変更致しました。
その際に、検証の内容と結果を紹介する内容になります。

経緯

  • バックアップの時間が10時間かかるようになってきた
  • 公式のスクリプトだと差分バックアップが取れない
  • バックアップコマンド実行時し、tarファイル生成中に対象ファイルの差分が発生し、tarコマンドがフェイルする

といった経緯があり、バックアップ方法の変更をしようということになりました。

構成について

弊社のGitLabとバックアップサーバの構成になっています。

f:id:AdwaysEngineerBlog:20191203124502p:plain

  1. baculaをバックアップサーバとして使っており、毎朝3時にバックアップが開始される
  2. 開始されたらsudo gitlab-rake gitlab:backup:createのコマンドを実行
  3. コマンドが終わり次第、バックアップファイルとして作成されたtarファイルをBaculaサーバに転送

これが弊社で行っているバックアップ方式になります。

検討した内容

メリット デメリット
ディスク容量追加 すぐできる GitLab backupとBaculaのbackupはもっと遅くなる リストアももっと遅くなる
LVMSnapshot Baculaバックアップは速くなる
リストアも転送だけですむので速くなる
LVM Snapshotからのバックアップ / リストアの確立が必要
GitLab backupは今までのようには取れない
DRBD GitLabのActive / Standby化 が可能。
障害時の復旧時間が短くなる
DRBDがスプリットブレインするとつらい。とても。
DRBDと上モノでmaster / slave が逆になったときとてもつらい
AWSに転送 容量問題とは無縁 AWSとの回線速度が懸念
Registry / ArtifactsをS3に バックアップ対象が240GB → 40GBに artifactsとregistryの復元は不可能

そもそも、AWSに引っ越しをしようや!という話をありましたが、今回は見送ることにしました。
厳正な話し合いの上、今回選ばれたのは、LVMSnapshotでした。(パチパチ

試したこと

ローカル、テスト環境、本番環境でバックアップの取得とリストア試験を行いました。
これからそれぞれで行ったテスト内容を書いていきます。

ローカルでの検証

LVMスナップショットするためのコマンドは検証するとなった瞬間に爆速で用意して頂いたので、こちらを使うことになりました。

LVMスナップショットをコマンド gitlablvmbackup

#!/bin/sh
set -eux
TARGET_LV_PATH="${TARGET_LV_PATH:-/dev/VG00/LV00}"
SNAPSHOT_LV_NAME="${SNAPSHOT_LV_NAME:-LVSnap}"
SNAPSHOT_LV_PATH="${SNAPSHOT_LV_PATH:-$(dirname "${TARGET_LV_PATH}")/"${SNAPSHOT_LV_NAME}"}"
SNAPSHOT_MOUNT_POINT="${SNAPSHOT_MOUNT_POINT:-/mnt/${SNAPSHOT_LV_NAME}}"

before () {
  find /var/opt/gitlab/backups/ -maxdepth 1 -type f -name "*_gitlab_backup.tar" -exec rm {} \;
  # only DB
  gitlab-rake gitlab:backup:create  SKIP=uploads,repositories,builds,artifacts,lfs,registry,pages
  mkdir -p "${SNAPSHOT_MOUNT_POINT}"
  lvcreate --snapshot --size=50G --name "${SNAPSHOT_LV_NAME}" "${TARGET_LV_PATH}"
  mount -t auto "${SNAPSHOT_LV_PATH}" "${SNAPSHOT_MOUNT_POINT}"
}

after () {
  umount "${SNAPSHOT_MOUNT_POINT}"
  lvremove "${SNAPSHOT_LV_PATH}" --force
}

"$1"

こちらのコマンドを使っています。

ローカルの環境について

  • Vagrantで実行
  • 50GBのIDEセカンダリスレーブでディスクを追加
  • LVMにて領域を拡張する
  • 本番のデータは一切使わない

バックアップ取得とリストア試験

スナップショット領域からのバックアップには下記が候補としてあがりました。

  1. 一気に全ファイルをrsyncで取得する
  2. backupのrakeタスクと同様の処理を実施する

2は処理を眺めたところ、同様の処理をシェルなどで実装することは厳しいと感じたため、1を採用する方針になりました。
検証時は下記コマンドで行いました。

# LVMスナップショットを実行
$ ./gitlablvmbackup before

# rsync でバックアップの取得
$ sudo rsync -av --no-specials --no-devices /mnt/LVSnap/var/opt/gitlab /vagrant/
$ ls /vagrant/gitlab/
alertmanager  bootstrapped  gitaly     gitlab-monitor  gitlab-rails  gitlab-workhorse  nginx          postgres-exporter  prometheus              redis     trusted-certs-directory-hash
backups       git-data      gitlab-ci  gitlab-pages    gitlab-shell  logrotate         node-exporter  postgresql         public_attributes.json  registry

# gitlabの停止
$ sudo gitlab-ctl stop
$ sudo rm -rf /var/opt/gitlab
$ sudo rsync -av --no-specials --no-devices /vagrant/gitlab /var/opt/

rsyncでリストアをしたところ、uid/gidが保持されていないため、起動に失敗しました。。。
そのため、スナップショット領域のファイルをtarで固める方式に変更することにしました。 下記コマンドで検証を行いました。

$ cd /mnt/LVSnap/var/opt
 
# specialファイルを除外したいので、それ用のファイルを作成する
$ sudo find gitlab -type s -print > /tmp/sockets-to-exclude
 
# tarで固める。
$ sudo tar cpf  /vagrant/gitlab-lvm-backup.tar -X /tmp/sockets-to-exclude gitlab

無事tarファイルができたので、リストアをします。

# GitLabを停止し、ファイルを削除
$ sudo gitlab-ctl stop
$ sudo rm -rf /var/opt/gitlab

# リストア
$ sudo tar xfp /vagrant/gitlab-lvm-backup.tar -C /var/opt

その結果、tarファイルを解凍することで、リストアをすることができました。

テスト環境での検証

次にテスト環境で試したことになります。

テスト環境について

  • 仮想環境で動いている
  • 50GBのディスクを追加済み LVMにて領域を拡張済み
  • 本番のデータを使う

バックアップ取得とリストア試験

テスト環境で同様の手順を試そうとした結果、下記エラーが出ました。

lvm[37888]: WARNING: Snapshot VG00-LVSnap is now 80.28% full.
lvm[37888]: WARNING: Snapshot VG00-LVSnap is now 86.15% full.
gitlab-test-001 lvm[37888]: WARNING: Snapshot VG00-LVSnap is now 92.01% full.
gitlab-test-001 lvm[37888]: WARNING: Snapshot VG00-LVSnap is now 95.08% full.
gitlab-test-001 lvm[37888]: WARNING: Snapshot VG00-LVSnap changed state to: Invalid and should be removed.
lvm[37888]: Unmounting invalid snapshot VG00-LVSnap from /mnt/LVSnap.

/var/opt/gitlab配下にtarでファイル作っていたので、snapshotが増え続けてエラーになりました。
対応方法としては、shapshotを取った領域をそのままバックアップサーバに転送する方式です。
tarではなくなる分転送量は増えますが、転送時間は現状よりも早くなる計算結果になりました。

そのため、baculaでLVMスナップショット領域を取得する方式に変更し、再度試験を行うことになりました。

項目 説明
baculaからのリストア 手順省略... /bacula-restores 以下にリストア対象のファイルが作成される
gitlabの停止 sudo gitlab-ctl stop
リストア sudo rm -rf /var/opt/gitlab/* 
cd /bacula-restores/mnt/LVSnap/var/opt/gitlab
sudo mv gitlab/ /var/opt
gitlab-secretの退避 sudo cp /etc/gitlab/gitlab-secrets.json <検証する日付>-lvm-resotre/
gitlabの起動 sudo gitlab-ctl start

テスト環境ではバックアップ取得もリストアもうまくいきました!
次は本番環境でもバックアップ取得とリストア試験をしないといけません。

本番でのリストア試験

実際に行った手順書ですがテスト環境と手順は一緒のため、省略します。

念のため、LVMバックアップ方式のリストアがうまくいかなかった際のリストア手順は作成しました。

項目 手順
baculaからのファイルをリストア 手順省略... /bacula-restores 以下にリストア対象のファイルが作成される
gitlabの停止 sudo gitlab-ctl stop
リストア sudo gitlab-rake gitlab:backup:restore BACKUP=<リストアしたtarファイル> force=yes
sudo gitlab-rake gitlab:check SANITIZE=true

結果はバックアップもリストアも無事成功しました!(パチパチ

その後、無事このバックアップ方式は導入され、今日も元気にバックアップをしております(?)

結果

このような問題点であげていたものがなんと!!

  • バックアップの時間が10時間かかるようになってきた
  • 公式のスクリプトだと差分バックアップが取れない
  • バックアップコマンド実行時し、tarファイル生成中に対象ファイルの差分が発生し、tarコマンドがフェイルする

問題点はすべて改善できました(パチパチ

  • バックアップの時間が10時間かかるようになってきた
    • バックアップに掛かる時間は、なんと3時間になりました。
  • 公式のスクリプトだと差分バックアップが取れない
    • 差分バックも行えるようになりました。こちらは8分で終わるようになりました。
  • バックアップコマンド実行時し、tarファイル生成中に対象ファイルの差分が発生し、tarコマンドがフェイルする
    • snapshotのため、そんなことは起きません!

感想

爆速と煽りましたが、フルバックアップ10時間以上が常に3時間でおわり、差分バックアップは10分以内で終わるので、かなり早くなったのではないでしょうか。
現在は、何の問題もなく動いているので、バックアップ失敗におびえることなく、熟睡できるようになりました。


 

次は奥村さんの記事です。

http://blog.engineer.adways.net/entry/advent_calendar_2019/03