Chienomi

誤家庭のLinuxで大規模ストレージを取り扱う

storage

  • TOP
  • Old Archives
  • 誤家庭のLinuxで大規模ストレージを取り扱う

ストレージ規模がどんどん大きくなる当システム。次期再編成のためのメモである。 なお、話を一般化するために特殊な箇所は変更してあり、このまま適用できるわけではない。

前提

メインとなるホスト(Host Master A)と冗長ホスト(Host Master B)から60TBに及ぶ巨大なストレージを取り扱えるようにする。

バックアップとしてサーバー(Host Slave)を用いてデータの冗長化を行う。

基本的には無停止が可能なようにするが、HAのような完全無停止を要求するわけではない。

機材

安価に拡張可能なストレージ群を構築するには、NetGear ReadyNAS RN316が良いようだ。 これにNetGear ReadyNAS EDA500を追加することで10万円以内で筐体を用意することができる。ディスクとあわせると、20台60TBで約40万円が必要だ(2017年6月現在)。

バックアップは実際には現在はサーバーによる内蔵とAoEの組み合わせ、とするが、将来的には同様の方法をとるのが望ましいだろう。

構成

NetGearで用意したディスクを、NetGearの機能でRAID5化し(つまり有効ディスク数は18となる)、これをiSCSIで提供する。

iSCSIディスクはHost Master Anyがイニシエータとなり、これをLUKSデバイスとして暗号化/復号化し、その上にbtrfsを構築して利用する。

2台ひと組と考えることで、-m1 -d1オプションを使って無停止性を確保することができる。 だが、実際は一般の利用ではディスク故障を除いたデータが損失するファイルシステム事故は割と少ないので、-m1 -d0あるいは-m1 -dsingle構成にしたほうが良いと考えられる。 -m1 -d1とした場合、ディスク30台を使用して使える容量は9台分となる。

バックアップも基本的には同様に構築する。異なるグループのiSCSIを用意し、btrfsボリュームを作成する。

構築

接続

iSCSIによる通信でほぼネットワークはあふれることになるため、ネットワークは分離することにする。

上流側は主にはクライアントユースになる、と考えれば、上流側をUSBアダプタとすることでホストの切り替えを容易にすることが考えられる。

Host Master AをHost Masterと考えた場合、Host Master A及びHost Slaveが2つのNICを持っている状態 となる。 このとき、両者が所属するネットワーク(サブネット1)はホストネットワークであり、下流側はストレージのみを接続する、という形態にすることでiSCSIの通信を混在することを避けられる。

Host Master Bを使用する場合はHost Master AからUSB NICを取り外し、Host Master Aに接続されていたUSB NICにHost Master Bにささっている(サブネット1の)ケーブルを接続し、Host Master B内蔵NICにはHost Master Aに接続されていたサブネット2のケーブルを接続すれば良い。

NASの用意

NASのディスクを各NAS上でRAID5で構成する。

2台ひと組にしておけば、btrfsは-d1であってもディスクを使い切ってくれる。 -dsingleにする場合は、NAS内のディスクは容量を揃える必要があるが、NASの合計容量を揃える必要はなくなる。

全ディスクを連結してRAID5を作ってしまうと、ディスク容量の制約が厳しくなるので、この方法のほうが良いだろう。 性能面でも、暗号化とRAIDの組み合わせはかなり重いので、速度を考えればハードウェアRAIDのほうが望ましい。

RAID5を構成したディスク上にLUNを作る。 グループはMasterとSlaveで異なるものにしたほうが良いが、Master NASはサブネット2、Slave NASはサブネット3に置かれるため、実際に混在することはない。

ホストのセットアップ

iSCSIイニシエータとして利用するため、iSCSIイニシエータutilのインストールと、iscsiサービスの起動が必要になる。

利用方法については、archwiki参照のこと。

全てのiSCSIターゲットにログインした上、これをluksFormatする。 ディスクは増えていくことになるので、キーファイルを使ったほうがスクリプトにする際に良いだろう。

# cryptsetup luksFormat /dev/sdb /path/to/keyfile

そしてオープンする

# cryptsetup luksOpen --keyfile-/path/to/keyfile /dev/sdb Crypt1
# cryptsetup luksOpen --keyfile-/path/to/keyfile /dev/sdc Crypt2

btrfsファイルシステムの作成

# mkfs.btrfs -L MasterBtrfs -m1 -dsingle /dev/mapper/Crypt[12]

追加で、サブボリュームの作成や、fstabの編集などを行っておく。

iSCSIターゲットの探索とログイン、ディスクの復号化とマウントの一連の流れはスクリプトにしておいたほうが良いだろう。

利用

まずNASを起動し、次にホストを起動する。そして、スクリプトによってマウントする。 セットアップが終われば非常にシンプルである(ただし、スクリプトにしていないと打つコマンドの量は多い。それはそれでセキュアだが)

スクリプトをsystemdユニットにしておくのは良い考えだが、コケる可能性の高いユニットなので、enableにはしないほうが良いだろう。

NFSとファイル配置

NFS v4を提供する。Manjaro Linuxでの手順である。

まず、btrfsのマウントポイントは/mnt/masterであるとする。 しかし、実際には特定ユーザーのデータが配置されるのであり、~foo/.masterfsがマウントポイントである。

そこで、これを反映できるようにするため、スクリプトの先頭で次のようにしておく

mount --bind /mnt/master /mnt/master
mount --make-rshared /mnt/master
mount --bind /mnt/master ~foo/.masterfs

これにより、ふたつのマウントポイントを意識せずに共有することができるようになる。

さらに、ここではNFSのマウントポイントも別に用意する。

mount --bind /mnt/master /srv/nfs4/masterfs
mount --make-slave /srv/nfs4/masterfs

ここまではスクリプトに含めると良いだろう。

NFSパッケージのインストール。

# pacman -S nfs-utils

/etc/exportsの設定

/srv/nfs4/masterfs 192.168.1.0/24(rw,no_subtree_check,nohide)

v2, v3の無効化(/etc/conf.d/nfs-server.conf)

NFSD_OPTS="-N 2 -N 3"

起動。マウントを手動で行っているため、enableは非推奨。

# systemctl start nfs-server

他ホスト(サブネット1のホスト)からマウントするためには、次のようにする。

# mount -t nfs -o vers=4 masterhost1:/masterfs /mnt/masterfs

-t nfs4とする必要がある場合、サーバー側パスにエクスポートルートを含める必要がある場合があるという。

CIFS

Arch系ディストリビューションにおけるSambaのセットアップ手順はArchwikiが参考になるだろう。

Linuxを中心に使っているユーザーにとっては、常時マウントするわけではないから、ファイルマネージャでのusershareシェアで十分かもしれない。

ただし、AndroidユーザーにとってはCIFSで構築したほうがメディアファイルの再生も容易になる。

DLNA

メディアファイルを広く再生する方法として有効なDLNA。

DLNA対応のプレイヤーがあり、それによって大画面で見られるといった場合には役立つだろう。

主にHost Masterを使い、Host Masterにログインすることが前提であるならばRygelで良いと思う。 そうでない場合は、ReadyMedia(minidlnaパッケージ)を利用することが推奨されているようだ。

Archのminidlnaはminidlnaユーザー, minidlnaグループで動作する。 そのため、ライブラリはこのユーザーでアクセス可能でなくてはいけない。

また、面倒を避けるためには、/etc/minidlna.confinotifynoにしておくのが良いだろう。

あるいはユーザーで実行したい場合は

$ install -Dm644 /etc/minidlna.conf ~/.config/minidlna/minidlna.conf
$ vim ~/.config/minidlna/minidlna.conf
$ minidlnad -f ~/.config/minidlna/minidlna.conf -P ~/.config/minidlna/minidlna.pid

のようにする。

DAAP

iTunesを使用しているユーザーにとっては軽快に動作する音楽ストリーミング方法。 forked-daapdが推奨されているが、AURにしか存在しない。

forked-daapdをインストールし、libraryセクションのdirectoriesを設定、当該ディレクトリをdaapd実行ユーザー(デフォルトでdaapd:daapd)がアクセス可能な状態にして

# systemctl start forked-daapd

で動作する。

LinuxではAmarokあるいはRhythemboxで再生できる。 Androidスマートフォンでは、DAAP Media Playerなどがあるようだ。

2008年頃に流行したDAAPだが、既にだいぶ廃れている印象はある。

ストレージとの分離

ユーザーデータ(dotfileなど)にも容量の大きなものがあるため、ストレージに退避したいと考えるかもしれないが、割とそれはリスキーである。

dotfileの場合、ファイルシステムをまたぐと動作しないもの、シンボリックリンクをこえられないものがあったりする。 また、ログイン時においてはストレージから切り離された状態にある可能性もあり、またストレージがダウンする可能性もあると考えなくてはいけない。

つまり、ストレージが切り離されても動作する状態を保ったほうが良い、ということである。

また、作業中のファイルなどは、ストレージとは別にシステム側にもあったほうが良い。ストレージが切り離された時に作業不能になる度合いを軽減するためである。

さらに、xdgディレクトリはシンボリックリンクが切れているとログイン時に変更されてしまう。 そのため、データが大きい~/Pictures~/Videoなどは、単純なディレクトリとして、その下にシンボリックリンクを配置したほうが良い。

運用の一例としてだが、次のようなストレージ構成だとする

sda      Internal SSD      System
sda1     Internal SSD      System, /
sda2     Internal SSD      System, Swap
sdb      iSCSI 1GbE        Data, Btrfs
sdc      iSCSI 1GbE        Data, Btrfs

次のようなマウント結果となる

/dev/mapper/luks-xxxxxxxxxxxxxxxxx on / type ext4 (rw,relatime,data=ordered)
/home/foo/.storage on type btrfs (rw,noatime,compress=lzo,space_cache,subvolid=258,subvol=/master)

ストレージへ同期されるべきものとして以下のように構成する

WorkSpace
+ Documents
+ Dotfiles

製作中のメディアファイルはDocumentsではなく~/.storage/user/art/以下に配置し、Documentsは文書ファイルのみを配置することで軽量なディレクトリにすることができる。

次のようなスクリプトを作っておく

#!/bin/zsh

WS=$HOME/WorkSpace

update() {
  rsync -avH "$@"
}

sync() {
  rsync -avH --delete "$@"
}

gitup() {
  (
      cd "$1"
        git add .
        git commit -m "Synced at $(date +%y%m%d)"
        git push
    )
}

hgup() {
  (
      cd "$1"
        hg add .
        hg commit -m "Synced at $(date +%y%m%d)"
        hg push
    )
}

gitup $WS/Documents
for i in $WS/Dotfiles/*
do
  hgup $i
done
sync ~/Pictures ~/.storage/XDG/
sync ~/Videos ~/.storage/XDG/
sync ~/Mail ~/.storage/
slave系

これでmaster系は54TB(3TB * 20 disks)ものスペースを一台に集約し、そのファイルを他のホストでアクセスするようにすることができた。 NFS/CIFS/DLNA/DAAPでアクセスできるため、ファイルの取り扱いは非常に良いはずだ。

加えてRAID5によりディスク故障やディスク破壊にも対応する。

だが、これでも壊れる可能性はある。誤消去や誤った更新・上書き、NASの故障、Btrfsの修復不能なクラッシュにどう対応するのだろうか?

ここでRAIDとバックアップは違う、という基本に立ち戻る必要がある。 つまり、このように堅牢なシステムを作っても、あるいはBtrfsクラッシュに備えてRAID5 NASにBtrfs RAID1を組み合わせたとしても、バックアップは別途必要なのである。

基本的にバックアップはメインストレージと同等の設備が必要になる。 もしメインストレージをBtrfs RAID1としているのであれば、バックアップにおける無停止性はそれほど重要ではないため、その場合はメインストレージの半分で済むということになる。

つまりおおよそシンメトリカルな2つのストレージ群とホストが編成されることになる。 ただし、slave系のコントローラホストはサーバーであり、処理性能よりも省電力性や静音性が重要となるだろう。 とはいえ、あまりにも処理性能をおざなりにすると、SSHの処理でもたついて時間がかかることになる。

現状で当環境においてはProLiant MicroServerを使用しているが、どちらかといえばラップトップのほうが適性があるとされている。 標準でコンソールを備え、無停電電源装置を内蔵した状態になるからだ。しかも省電力で静音性も高い。 メインホストからみた速度向上のためにはメモリは多目であったほうがいいだろう。

構築、ストレージへの接続、Btrfsの作成は同様である。

バックアップはBtrfsのsend/receive機能を使うことができる。 差分バックアップも用意で、本当に変更されたものだけを転送するため、非常に効率が良い。

次のようなスクリプトを用意する。

#!/bin/zsh

notify-send "BtrSnapSync: Woke"

if ! btrfs subvolume snapshot -r /mnt/master /mnt/master/snapshots/snapshot-new
then
  print "BtrSnapSync: **CRITICAL** Failed to create new snapshot"
  exit 2
fi

sync

notify-send "BtrSnapSync: Snapshot."

if [[ -e /mnt/master/snapshots/snapshot-old ]]
then
  if btrfs send -v -p /mnt/master/snapshots/snapshot-old /mnt/master/snapshots/snapshot-new/
  then
    notify-send "Send Snapshot."
    btrfs subvolume delete /mnt/master/snapshots/snapshot-old
    mv /mnt/master/snapshots/snapshot-new /mnt/master/snapshots/snapshot-old
    notify-send "Deleted old Snapshot."
  else
    notify-send "Failed to send Snapshot"
    btrfs subvolume delete /mnt/master/snapshots/snapshot-new
  fi
else
  if btrfs send -v /mnt/master/snapshot-new
  then
    notify-send "Send Snapshot."
    mv /mnt/master/snapshots/snapshot-new /mnt/master/snapshots/snapshot-old
    notify-send "Deleted old Snapshot."
  else
    notify-send "Failed to send Snapshot"
    btrfs subvolume delete /mnt/master/snapshots/snapshot-new
  fi
fi

また、slave側は次のようなスクリプトを用意する。

#!/bin/sh
btrfs receive /MirrorRoot && mv /MirrorRoot/snapshot-new /MirrorRooot/snapshot`date +%y%m%d%H%M`

あとは次のようにすることで転送する。

$ btrfssend.zsh | ssh -i /root/.ssh/btrfssnapsync root@slave.local /usr/local/sbin/btrfsreceiver.sh

暗号化を行わず処理を軽減するには、まずslave側で次のように実行する(OpenBSD Netcatを使用している)

# nc -l 12358 | btrfsreceiver.sh

続いてmaster側。ここではbashを使っている。

$ btrfssend.zsh > /dev/tcp/slave.local/12358

暗号化の必要がないとしても、危険だと考えられるため、SSHの利用が推奨される。