2013年頃から分散ファイルシステムとして導入され、以来何度も手に負えない障害を起こしていた(※0)GlusterFSからの脱却をついに成功させた。
やり抜けば、辛い歴史から抜け出すことができることを是非お知らせしたいと思い、投稿。

  • (※0)
    • プロセス再起動で難を逃れてばかりだった

はじめに

  • GlusterFSがどういうものなのかの説明はすみませんが大幅に省略します。
    • 大雑把に言うと、「分散ファイルシステム」です。
    • 導入当初は、「拡張性」を期待されていました。
      • 容量が足りなくなっても、ノード(サーバー)を追加すればよい、という感じ。
      • 初期の、仮想サーバー 8(4ペア × 2)台の1つのペアが崩れた時点で、この拡張性は喪失され、逆に単一障害点となっていた。他のペアも順次崩れ、複数の単一障害点を抱える状態に。。
  • 大きな欠点が、「パフォーマンスが非常に悪い」でした。
    • 1万個くらいのディレクトリがある場所で ls したら、もう返ってこない。
    • 対応するディレクトリを決め打ちで cd しないと、SSH接続からやり直しという。。
    • 容量がどれくらいか確認するのは、年始に du を tmux セッション上で流しっぱなしで丸一日、という鬼運用。(そういえば今年やるの忘れてた)
  • とはいえGlusterFS自体が悪なのではないと思っています。
    • 使い方によっては活きるシーンもあるのではないかと。(見たことありませんが)

脱却前の状態

ホスト名(仮) 容量(df -h) 備考(※1) 速度比(※2)
(GlusterFS_ALL) 485 G -
brick03 62 G 仮想(localdisk) 8
brick05 71 G 仮想(localdisk) 8
brick07 69 G 仮想(localdisk) 8
brick10 70 G 仮想サーバー 14
brick12 69 G 仮想サーバー 14
brick13 73 G 仮想サーバー 14
brick-02 75 G 物理サーバー 7
  • 上から、存在していた歴史の長い順
    • 仮想(localdisk) と 仮想サーバー の3つずつは、同時期の使用開始。
  • (※1)
    • 「仮想(localdisk)」とは、仮想環境基盤に属するが物理ホストのローカルディスクということで、物理サーバーに近い感じだと思っている。
    • 物理サーバー・仮想サーバーは、そのままの意味です。
  • (※2)
    • 速度比とは、事前検証時の rsync での転送速度の比(体感)。
      • だいたい同一であろう量を転送するのにかかる時間の比が、[物理] : [仮想(localdisk)] : [仮想] で 7:8:14 くらいだった。
      • 仮想サーバーから新サーバーへの転送にかかる時間が、物理サーバーからのそれの倍くらいだった、という感じ。

採用した方法

新サーバーへの転送まで

  • GlusterFS を通しての転送は絶望的に遅く、確実に予定していたメンテナンスの時間内では移動できない。
  • なので、GlusterFSを構成する各brickの実体サーバーそれぞれから新サーバーに転送をする方法を採用。
    • ただし、メンテナンス当日にゼロベースで転送をするのではこれも完了できなさそう。
    • そこで、メンテナンス前の週末、サービストラフィックの少ないうちに、rsync で bwlimit オプションをつけて負荷を抑えて転送を実施しておいた。
  • こうすることで、メンテナンスの当日は「最終転送」だけ行えばOKとなり、その転送量は極小(前日の増分のみ)となる。
    • これを、週末から夜毎繰り返していた。メンテナンスが水曜未明だったので、月曜深夜・火曜深夜の2回だけですが。
      • ちなみに、7台から手動でシェル実行、というのは辛いので、自動で回るようにしておきました。
        • 同じシェルを7台の同じ場所に配置して引数で実行内容を区別するようにしたのも工夫の1つ。
      • 検証中でのもう1つの工夫として、転送で問題が起きたケースで処置を早くできるようにする(問題箇所の特定を早める)意図で、転送を4つのグループに分けて、それぞれの転送にかかるだいたいの時間を把握した上で、「被らない」ように編成した。

必殺技1: rsync のデーモン化

  • これでほぼ転送の方法は固まったわけだが、さらなる高速化を調査・検証した結果、新サーバー側で rsync をデーモン化することになかなかの効果があると判明。
  • セットアップも使い方も非常に簡単。
    • 今や完全に我々の rsync の使い方のスタンダード。
  • 時間短縮の度合いは「もの凄い」というほどではないが、感覚的に10%くらいの転送時間削減はできていたような記憶。
  • 特筆できるのはネットワーク負荷が超絶軽くなった点。bwlimit の値を倍にしてもよさそうなくらいだった。(時間とリスクの関係でやらなかったのですが)

新サーバーでの「bricks統合」

  • 新サーバーへの転送は、念のため輻輳を避ける意図で、brick毎に分けて行うことにしていた。

    • コマンドで示すと、以下のような感じ。

        rsync -av --delete --bwlimit=${bw} /export/brick/data/$group_member   ${dstServer}::${module}/brickN/data/
      
  • これを、以下のように最終形態に統合する必要があった。

      rsync -a /path/to/dir_base/brickN/data/  /path/to/dir_base/data/
    

必殺技2:並列実行

  • 7つの brick があって、それぞれが云十Gなので、直列での実行では遅かろう、と予想した。

    • 初期の予定「統合」コマンド

        rsync -a /path/to/dir_base/brick03/data/ /path/to/dir_base/data/
        rsync -a /path/to/dir_base/brick05/data/ /path/to/dir_base/data/
        ・・・
        rsync -a /path/to/dir_base/brick-02/data/ /path/to/dir_base/data/
      
  • そこで、簡単に言うと以下のように並列で実行することに計画した。

    • 最終的な予定「統合」コマンド

        rsync -a /path/to/dir_base/brick03/data/ /path/to/dir_base/data/  &
        rsync -a /path/to/dir_base/brick05/data/ /path/to/dir_base/data/  &
        ・・・
        rsync -a /path/to/dir_base/brick-02/data/ /path/to/dir_base/data/ &
      

当日の過程

その日に残してた記録より。

時刻 実施事項 備考など
0:30頃 バックグラウンド処理などを止め始める
1:00 メンテナンス開始
1:10 メンテナンス状態になったことを確認取れたので
最終転送を開始
Group3 (約10分)
1:19 Group1 (約30分)
1:48 Group2 (約50分)
2:34 転送中に、/etc/fstab の書き換えなど Group4 (約40分)
3:17 最終転送が完了 Group0を忘れていた (約20分)
3:36 ファイルのパーミッションチェック・補正(※3)
4:00 ひと息ついて、bricks統合を開始
5:15頃 bricks統合7並列は負荷かけすぎだったと判明 
I/O wait が散見していたが、待つのが最善と判断
ioniceで一部を優先度下げたりした
6:00頃 bricks統合が完了
6:20頃 du -h での容量確認(380 G)を妥当と判断し、マウントしているディレクトリの入れ替えを開始 485 G 全てを移行対象とはしなかった
6:30頃 psshを駆使して(※4)、マウントしているディレクトリの入れ替え・Webサーバープロセスの再起動を完了
6:45頃 旧ファイルシステムへの接続が残っていないかの確認(※5) サービス影響のあり得る接続残はないと判断
7:05頃 成功裏に作業完了
一部転送漏れがあったのに気が付いたので転送を進めておいて経過観察
8:40頃には転送完了
8:00 バックグラウンド処理の再開などを済ませ、
予定時刻通りにメンテナンス終了
  • (※3)

    • GlusterFSの何らかの問題で発生したと見込まれる、 ---------T. というパーミッション 000 のファイルがないかのチェック。スクリプトを用意して 644 に直す準備をしていた。
  • (※4)

    • Webサーバー80台超に一斉に以下を実行

        # 旧ファイルシステムへのマウントを外す
        pssh -h /path/to/targets --timeout 1800 -l XXXXX 'umount -l /mnt/entry'
        
        # 新ファイスシステムをマウント
        pssh -h /path/to/targets --timeout 1800 -l XXXXX 'mount -t nfs ${ServerIP}:/path/to/new_fs_dir /mnt/entry'
      
  • (※5)

    • 以下のコマンドでIPアドレスを抽出し、GlusterFS構成サーバーでないものがないかの確認。

        netstat -tanp | grep -i est | grep -i gluster | awk '{print $5}' | awk -F":" '{print $1}' |sort|uniq 
      

おわりに

  • 終わってみればだが、最終転送はなんと2時間ほどで完了してしまった。rsyncデーモンの効果を驚異に感じた。
  • 一方で、bricks統合が思うように進まなかった。それでも2時間以上待ってあわてず完了を待てたのは最終転送での「貯金」が大きかった。心理的にも。
  • 工夫に工夫を重ねていい準備ができれば、確実にメンテナンスが成功するよい事例になったと思う。
  • 切り替え直後に体感できた、サービスのパフォーマンス改善、そして ls しても怖くない快感は、忘れがたい。達成感そのものだった。

その他

  • 実は、この前の週にも別のメンテナンスがあり、それは失敗な感じだった。
  • そこでかなりの「全力」で周囲に次のこのメンテナンスの支援を要請した結果、このGlusterFS脱却がほぼパーフェクトにできた。
    • となりのCTOと目の前のプロはじめ、チームには感謝しかない。
    • ひと一人の力は大したことないと痛感した話でもある。
  • メンテが成功した時の、どうってことのない500円程度の朝食は、それだけで旨さが格別だった。