BLOG

Linuxで分散型ブロックストレージを構築する part1

hdd

皆さんの使われているパソコンやサーバーは購入してからどれくらい経っていますでしょうか?

リース契約なども考慮して、通常3年~5年の保守契約で組まれるサーバーが多いですが、
最近ではマルチコアによって1台辺りの性能が大きく向上、OSサポート期間も以前に比べて長くなっており、
メーカー側も最大7年程度までの保守を選択肢として出すようになりました。

弊社で運用する機器で5年以上の選手は少ないですが、
写真販売サービス「フォトラボ」では、動的に写真を生成表示をする部分で、
6~7年ほど前のサーバーを4台構成で組んで運用しています。

5年前は今から5世代前のXeon 5400番台(デスクトップではCore2 Quadの第二世代)が出始めた頃で、
まだまだ現役で利用している方も多いかと思いますが、
サーバーの場合、生産終了によって部品の供給終了や、保守満了で修理サービスの提供終了に伴い、
交換部品を失ったサーバー機器の更新は必然となってくるのですが、
古くなった旧世代機器が全く利用できなくなったわけではないので、当然別用途として再利用が可能です。
そんな機器を安定稼働・拡張可能なストレージとして検証したのが、この分散型ブロックストレージです。

 

■ 要件
今回構築するこの分散型ブロックストレージの要件として以下を必須要件にしたいと思います。

・故障頻度を考慮した耐障害性 (RAID6相当)
・旧世代のハードウェアを利用しつつ、新世代に太刀打ちできるような速度性能 (パフォーマンス)
・故障時の影響を最小限に抑える (ホットスペア領域を分散するDynamic Disk Pool相当
・拡張による性能向上の選択肢も残す (パフォーマンス)
・柔軟な拡張性 (リニア拡張)

なかなか無茶な要件に見えますが、最近のストレージではこれらの機能は当たり前ですので、
作るからには最新のストレージ機器と同性能は求めたい所です。
ただし消費電力はどう頑張っても太刀打ちできませんので目をつむる事とします。

 

■ 用意する機器
最低限以下の機器が必要となります。
これからpart1で説明する内容はこの半分の台数、従って必要最低数は5台となります。

・ストレージサービス 2台 (LANポートを4つ以上、できれば8ポート推奨、CPUは4コア以上推奨)
・ストレージノード 8台 (LANポートが2つ、サーバー1台辺りのハードディスクは2TB)

 

■ 概要
冒頭で要件に出した内容を少し整理してみましょう。

・故障頻度を考慮した耐障害性 (RAID6相当)
RAID6相当でピンと来た方もいると思いますが、linuxのソフトウェアRAIDを使用します。
またpart1では扱いませんが、DRBDと組み合わせて、ストレージサービス自体も冗長とする方法も実装します。

・旧世代のハードウェアを利用しつつ、新世代に太刀打ちできるような速度性能 (パフォーマンス)
・拡張による性能向上の選択肢も残す (パフォーマンス)
パフォーマンスはどうしても機器依存が大きいですが、
5年前の機器であればS-ATAの直接接続で100MB/sは出ますので、この数字をベースとし、
ストレージサービスとの接続はLANケーブル経由、つまりiSCSI接続とします。

最低2ポート必要と記載したのは冗長性を持たせるため、パフォーマンス向上のためですが、
物理インターフェースをまとめるbondingは速度改善に繋がりませんのでここではbondingは行わず、
dm-multipathを利用してパフォーマンスを引き出します。

・故障時の影響を最小限に抑える (ホットスペア領域を分散するDynamic Disk Pool相当
※この機能の実装はpart1では扱いません※
ダイナミックディスクプールはストレージ製品で2011年頃から話題になってきた機能です。
近年ハードディスクの大容量化が著しく、単体で4TBのディスクも登場しています。
これを12本や24本と搭載してしまうとRAID6でもリビルドに数日を要するケースがあり、問題となっています。
ストレージプールに丸々ディスクを割り当てるのではなく、
ディスク1本を細かく区切ってプールに割り当てる事で、より効率よく利用し、リビルド時間を短縮する機能です。

・柔軟な拡張性 (リニア拡張)
NoSQLでも当然の機能ですが、増設する事で容量を増やすのは当たり前になってきていますので、
ここではLVMを使って後から増設できるようにします。

以上を整理すると見えてくる構成は、以下となります。
・ストレージサービス側 (iscsi-initiator+dm-multipath+mdadm+LVM+DRBD+Heartbeat)
・ストレージノード側 (iscsi-target)

 

■ ストレージノードの構築
iscsi-targetとなるストレージノードを4台分構築します。
ここでは192.168.10.1~192.168.10.4と192.168.20.1~192.168.20.4をターゲットに、
192.168.10.100と192.168.20.100をイニシエーターとします。

・ファイアウォールの解放
iSCSIではTCP:3260を利用しますので、解放します。

・構成&前提パッケージのインストール
容量配分は2TBのうちOS領域で100GBを、残りの1.8TBをiSCSI用とします。
/dev/sda1領域は/boot、/dev/sda2はswap、/dev/sda3は/とし、/dev/sda4をiSCSI公開用とします。

yum -y install scsi-target-utils

・iSCSI-targetの設定

vi /etc/tgt/targets.conf
--------------------------------------------------
<target iqn.2013-06.com.example.iscsi1:target0>
    backing-store /dev/sda4
    initiator-address 192.168.10.100
    initiator-address 192.168.20.100
</target>

・iSCSI-targetの起動

/etc/init.d/tgtd start

上記作業を4台分行います。

 

■ ストレージサービスの構築
続いてストレージサービス側の設定です。

・前提パッケージのインストール
まずはデバイスを認識させるため、iSCSIイニシエーターとマルチパスのインストールです。

yum -y install iscsi-initiator-utils device-mapper-multipath

・iSCSIターゲットの登録

iscsiadm -m discovery -t sendtargets -p 192.168.10.1
iscsiadm -m discovery -t sendtargets -p 192.168.10.2
iscsiadm -m discovery -t sendtargets -p 192.168.10.3
iscsiadm -m discovery -t sendtargets -p 192.168.10.4
iscsiadm -m discovery -t sendtargets -p 192.168.20.1
iscsiadm -m discovery -t sendtargets -p 192.168.20.2
iscsiadm -m discovery -t sendtargets -p 192.168.20.3
iscsiadm -m discovery -t sendtargets -p 192.168.20.4

・iSCSIターゲットのログイン
設定を反映させるため、iscsiを起動します。

/etc/init.d/iscsi start
iscsi を起動中:                                            [  OK  ]

OKと出た事を確認してください。
もしNGが出た場合には設定が間違っている恐れがありますので設定を見直しましょう。

・multipathdの設定
続いてmultipathdの設定を行います。設定を行うに当たってwwidを取得する必要があります。
wwidを取得するには/dev/disk/by-idから追加されたデバイス名を探し、scsi_idコマンドからwwidを特定します。

ls -alt /dev/disk/by-id
scsi-1IET_00010001 -> ../../sdc
scsi_id --whitelisted --device=/dev/sdc
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

取得されたwwidをメモし、multipath.confに追加します。これを4台分行います。

vi /etc/multipath.conf
--------------------------------------------------
blacklist {
  devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
  devnode "^(hd|xvd|vd)[a-z]*"
  wwid    *
}

blacklist_exceptions {
  wwid "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

defaults {
  user_friendly_names no
}

multipaths {
  multipath {
    wwid           "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    alias          iscsi1-1.example.com
    path_grouping_policy multibus
    path_checker   readsector0
    path_selector  "round-robin 0"
    failback       manual
    rr_weight      priorities
    no_path_retry  5
  }
  multipath {
    wwid           "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    alias          iscsi2-1.example.com
    path_grouping_policy multibus
    path_checker   readsector0
    path_selector  "round-robin 0"
    failback       manual
    rr_weight      priorities
    no_path_retry  5
  }
  multipath {
    wwid           "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    alias          iscsi3-1.example.com
    path_grouping_policy multibus
    path_checker   readsector0
    path_selector  "round-robin 0"
    failback       manual
    rr_weight      priorities
    no_path_retry  5
  }
  multipath {
    wwid           "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    alias          iscsi4-1.example.com
    path_grouping_policy multibus
    path_checker   readsector0
    path_selector  "round-robin 0"
    failback       manual
    rr_weight      priorities
    no_path_retry  5
  }
}

・multipathdの起動、動作確認

iscsi1-1.example.com (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) dm-0 IET,VIRTUAL-DISK
size=900G features='0' hwhandler='0' wp=rw
  `- 3:0:0:0 sdb 8:16 active ready running
|-+- policy='round-robin 0' prio=1 status=enabled
  `- 4:0:0:0 sdc 8:32 active ready running
iscsi2-1.example.com (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) dm-1 IET,VIRTUAL-DISK
size=900G features='0' hwhandler='0' wp=rw
  `- 3:0:0:0 sdd 8:16 active ready running
|-+- policy='round-robin 0' prio=1 status=enabled
  `- 4:0:0:0 sde 8:32 active ready running
iscsi3-1.example.com (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) dm-2 IET,VIRTUAL-DISK
size=900G features='0' hwhandler='0' wp=rw
  `- 3:0:0:0 sdf 8:16 active ready running
|-+- policy='round-robin 0' prio=1 status=enabled
  `- 4:0:0:0 sdg 8:32 active ready running
iscsi4-1.example.com (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) dm-3 IET,VIRTUAL-DISK
size=900G features='0' hwhandler='0' wp=rw
  `- 3:0:0:0 sdh 8:16 active ready running
|-+- policy='round-robin 0' prio=1 status=enabled
  `- 4:0:0:0 sdi 8:32 active ready running

・デバイスの確認
更にls -l /dev/mapperを実行するとaliasで指定した名前のデバイスが表示されます。

lrwxrwxrwx 1 root root      7  6月 15 16:51 2013 iscsi1-1.example.com -> ../dm-0
lrwxrwxrwx 1 root root      7  6月 15 16:51 2013 iscsi2-1.example.com -> ../dm-1
lrwxrwxrwx 1 root root      7  6月 15 16:51 2013 iscsi3-1.example.com -> ../dm-2
lrwxrwxrwx 1 root root      7  6月 15 16:51 2013 iscsi4-1.example.com -> ../dm-3

・パーティションの作成
以下を4台分行います。

fdisk /dev/mapper/iscsi1-1.example.com

警告: DOS互換モードは廃止予定です。このモード (コマンド 'c') を止めることを
      強く推奨します。 and change display units to
         sectors (command 'u').
コマンド (m でヘルプ): n
コマンドアクション
   e   拡張
   p   基本パーティション (1-4)
p
パーティション番号 (1-4): 1
最初 シリンダ (1-117487, 初期値 1): 
初期値 1 を使います
Last シリンダ, +シリンダ数 or +size{K,M,G} (1-117487, 初期値 117487): 
初期値 117487 を使います

コマンド (m でヘルプ): w
パーティションテーブルは変更されました!

ioctl() を呼び出してパーティションテーブルを再読込みします。

警告: パーティションテーブルの再読込みがエラー 22 で失敗しました: 無効な引数です。
カーネルはまだ古いテーブルを使っています。新しいテーブルは
次回リブート時か、partprobe(8)またはkpartx(8)を実行した後に
使えるようになるでしょう
ディスクを同期しています。

このままではパーティションの反映がすぐに行われないので、警告の通りkpartxを実行します。

kpartx -a /dev/mapper/iscsi1-1.example.com
kpartx -a /dev/mapper/iscsi2-1.example.com
kpartx -a /dev/mapper/iscsi3-1.example.com
kpartx -a /dev/mapper/iscsi4-1.example.com

もし以下のようにエラーが出る場合には一度再起動し、パーティションが作成されているか確認してみてください。

device-mapper: create ioctl on iscsi1-1.example.com1 failed: Device or resource busy
create/reload failed on iscsi1-1.example.com1

・ソフトウェアRAIDの作成
ここでは4台のハードディスクが認識していますので、この4台をRAID6で組む事とします。
RAID6とはディスク本数N-2台の容量が利用でき、最低4台のハードディスクを必要とします。
以下のコマンドを実行してください。

mdadm -v --create /dev/md0 --level=raid6 --raid-devices=4 /dev/mapper/iscsi{1..4}-1.example.comp1

実行直後よりリビルドが開始します。リビルド状況を確認するには以下のコマンドを実行すると良いです。

watch mdadm --misc --detail /dev/md0

・LVMパーティションにする
最後にパーティションをLVMで固めます。
LVMパーティションにせずmd0をフォーマットして利用する事はできますが、
LVMにする事で容量拡張が柔軟になります。

物理ボリュームの作成
pvcreate /dev/md0

物理ボリュームの確認
pvdisplay /dev/md0

ボリュームグループ(vg1)の作成
vgcreate vg1 /dev/md0
ボリュームグループの確認
vgdisplay

ボリュームグループ(vg1)から論理ボリューム(udv1)を3.2TB分作成
lvcreate -L 3200G -n udv1 vg1

論理ボリュームの確認
lvdisplay

・ボリュームグループ(vg1)から作成した論理ボリューム(udv1)のフォーマット
最後にフォーマットを行い、フォーマットが完了したらマウントします。

mkfs.ext4 /dev/vg1/udv1
mkdir -p /home/distributed_volume
mount -t /home/distributed_volume

iSCSIデバイスですので、再起動後も自動マウントするためには前提サービスの起動と、
マウントオプションに_netdevが必要です。

 

以上によりiSCSI経由で認識したストレージ4台を使って分散保存するブロックストレージの構築ができました。
RAID6構成ですので、最大2台までストレージノードが故障しても継続運用ができますし、
multipathによりネットワークも冗長化され、1Gbps×2の速度でリンクされています。

WS000118
以前この方法でサーバーを13台用意してマウントを行いパフォーマンスの比較を行いましたが、
ストレージの参加ディスク本数を増やしたところパフォーマンスの改善が見られました。

続くpart2では同じ構成をもう1台構築し、DRBDでミラーリングを行う方法、
またストレージを無停止で追加し、容量を増やす方法について紹介します。ご期待ください。

Tweet about this on TwitterShare on FacebookShare on Google+