RAID的小插曲·二

上次提到我在一台跑应用的机器上使用mdadm做了个RAID-0,实际使用中发现了一些效能方面的下降。
具体来说就是svctm和%util数值上升。
我当时推测可能是Chunk设置太小导致的,所以我在前两天分别调整了Chunk大小,做了新的测试。

# cat /proc/mdstat
Personalities : [raid0]
md0 : active raid0 sda1[0] sdb1[1]
      468860064 blocks super 1.2 16k chunks

# cat /proc/mdstat
Personalities : [raid0]
md0 : active raid0 sda1[0] sdb1[1]
      468860032 blocks super 1.2 32k chunks

在Chunk被设置为16k与32k的情况下,分别跑了一天应用,结果发现在小文件io的时候%util数值上升非常严重。
老实说我拿不准到底是哪方面出的问题,等下一周有时间我试试直接把Chunk大小提升到128k。

软件RAID测试·四

由于RAID-10不能实现动态扩容,我就打起了支持动态扩容的RAID-5的主意。
实际上,公司搭建存储很少在乎动态扩容这么一回事,但对于我这种穷苦老百姓来说,动态扩容还真是件很重要的事。
但是由于RAID-5的奇偶校验,可能会比较大地影响读写性能。
奇偶校验的情况比较复杂,所以我打算先在虚拟机里面简单测试下。
由于虚拟机无法模拟条带化带来的读写性能的上升,所以就以数据量来代替速度指标。
先在RAID-10上检验方法是否可行。这次的RAID-10参数如下:

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid10 sde1[3] sdd1[2] sdc1[1] sdb1[0]
      16765952 blocks super 1.2 512K chunks 2 near-copies [4/4] [UUUU]

构筑这个阵列的时候,我并没有刻意制定Chunk大小,很意外地发现程序自动指定的大小竟然高达512kB。
以下是文件系统建立好并挂载后iostat给出的值。

# iostat -md
Linux 3.11.0-12-generic (ubuntu)        03/25/2014      _x86_64_        (1 CPU)

Device:        tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda           3.99         0.08         0.00        108          6
sdb          88.50         5.71         0.01       8194         17
sdc          87.28         5.71         0.01       8188         17
sdd          87.48         5.71         0.01       8189         17
sde          87.16         5.71         0.01       8188         17
dm-0          4.00         0.07         0.00        104          6
dm-1          0.22         0.00         0.00          1          0
md127         1.86         0.00         0.02          4         23
dm-2          0.92         0.00         0.01          1         12

接下来,cd到阵列挂载的目录,使用iozone跑一跑自动参数。

iozone -aI

这里一个小插曲,可能是虚拟机虚拟的SATA总线有点不如人意,跑着跑着就跑得I/O堵塞然后整个文件系统出毛病自动转ReadOnly了。
只好先重启,清空下iostat的统计数据。

# iostat -md
Linux 3.11.0-12-generic (ubuntu)        03/25/2014      _x86_64_        (1 CPU)

Device:        tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda          78.59         1.40         0.06         89          3
sdb           8.42         0.03         0.00          2          0
sdc           3.88         0.02         0.00          0          0
sdd           4.96         0.02         0.00          1          0
sde           3.94         0.02         0.00          0          0
md127         5.62         0.02         0.00          1          0
dm-0          3.32         0.01         0.00          0          0
dm-1        117.99         1.11         0.06         70          3
dm-2          3.82         0.01         0.00          0          0

重新跑过iozone,这次指定下跑的大小。

iozone -g64M -n64M -aI

这次跑得很顺,跑完后iostat数值如下,

# iostat -md
Linux 3.11.0-12-generic (ubuntu)        03/25/2014      _x86_64_        (1 CPU)

Device:        tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda          13.13         0.23         0.01         91          3
sdb         244.03        17.15         4.10       6708       1604
sdc         222.75        14.49         4.10       5667       1604
sdd         248.87        17.12         4.75       6694       1857
sde         229.62        14.53         4.75       5682       1857
md127        89.75         9.01         8.85       3524       3461
dm-0         89.08         9.01         8.85       3523       3461
dm-1         19.61         0.19         0.01         72          3
dm-2          0.62         0.00         0.00          0          0

看到实际上数据并不是均匀写到两组RAID-1里面的,这是因为RAID-0里面数据按照指定的Chunk分条而非均匀分条。
然后发现件令人费解的事情,这个读取的数据量为什么大得有点离谱,而且在各个盘不是均匀的?不太理解这个,可能跟其他什么有关。
由于出现了意料之外的变量,这个本来就不太严谨的检测可能越发不严谨,但我还是决定继续做下去,至少写入的数据检测到是准确的。
现在,我把RAID-10拆了改成了RAID-5。

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid5 sde1[4] sdd1[2] sdc1[1] sdb1[0]
      25148928 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/4] [UUUU]

重启,清空iostat数据。

# iostat -dm
Linux 3.11.0-12-generic (ubuntu)        03/25/2014      _x86_64_        (1 CPU)

Device:        tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda          35.11         0.53         0.01         61          0
sdb           2.60         0.01         0.00          1          0
sdc           2.16         0.01         0.00          0          0
sdd           2.57         0.01         0.00          1          0
sde           2.21         0.01         0.00          0          0
md127         0.82         0.00         0.00          0          0
dm-0         29.99         0.51         0.01         57          0
dm-1          2.17         0.01         0.00          0          0

重复跑iozone的过程后,iostat数据如下。

# iostat -dm
Linux 3.11.0-12-generic (ubuntu)        03/25/2014      _x86_64_        (1 CPU)

Device:        tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda          17.72         0.27         0.00         62          1
sdb          67.69         6.00         5.17       1370       1180
sdc          76.92         5.92         6.67       1353       1523
sdd          66.82         5.65         5.84       1291       1335
sde          76.23         5.65         6.86       1291       1567
md127       151.96        15.40        15.14       3521       3461

时间太晚了,就列个数据,明天再分析。

RAID的小插曲

我用mdadm在实机环境中搭起了个两块固态硬盘的RAID-0。
使用的硬盘是两块INTEL DC 530。

# cat /proc/mdstat
Personalities : [raid0] [raid6] [raid5] [raid4]
md0 : active raid0 sda1[0] sdb1[1]
      468860064 blocks super 1.2 4k chunks

# hdparm -I /dev/sda

/dev/sda:

ATA device, with non-removable media
        Model Number:       INTEL SSDSC2BW240A4
        Serial Number:      BTDA327005BJ2403GN
        Firmware Revision:  DC02
        Transport:          Serial, ATA8-AST, SATA 1.0a, SATA II Extensions, SAT
(……)

搭好后运行了一会,我就发现了一些问题。性能参数似乎有点不太对劲。

# iostat -x 60
Linux 2.6.32-openvz-amd64 (localhost)  2014年03月25日  _x86_64_        (40 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          21.77    0.00    1.83    0.66    0.00   75.75

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda              18.27  3544.73  249.98  243.19  1072.92 14985.95    65.13     4.51    9.14    0.38   18.13   1.16  57.28
sdb              18.03  3543.52  250.24  245.94  1073.01 14992.33    64.76     4.33    8.74    0.37   17.24   1.14  56.35
sdc               0.19     0.42   57.16    0.37  7114.68     4.22   247.49     0.07    1.30    1.23   11.59   0.70   4.03
md0               0.00     0.00  536.51 7535.96  2145.90 29978.28     7.96     0.00    0.00    0.00    0.00   0.00   0.00
dm-0              0.00     0.00  530.95 7497.14  2123.64 29978.28     8.00    86.79   13.58    0.99   14.48   0.08  67.78

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          47.60    0.00    3.06    1.48    0.00   47.85

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda              26.13   158.28   42.08  515.18   272.87  2410.12     9.63    11.75   21.09    6.85   22.25   1.60  89.34
sdb              26.18   146.22   42.27  525.42   273.80  2402.85     9.43     8.53   15.03    6.12   15.75   1.53  86.73
sdc               0.00     0.12    0.00    0.13     0.00     1.07    16.00     0.00    8.38    0.00    8.38   8.00   0.11
md0               0.00     0.00  136.67 1274.13   546.67  4808.57     7.59     0.00    0.00    0.00    0.00   0.00   0.00
dm-0              0.00     0.00  136.67 1205.65   546.67  4808.57     7.98    28.05   20.89    8.09   22.35   0.74  99.64

可以看到svctm和%util还有其他几个涉及到效能的值都太高了,几乎是单盘无阵列的10倍(以上),这代表着哪里出了问题。
要说哪里会有问题,首先怀疑到的自然是整个构建RAID过程中唯一可以自行设置参数的地方:Chunk大小。
这是我创建RAID使用的命令:

mdadm --create md0 -chunk=4 --level=0 --raid-devices=2 /dev/sda1 /dev/sdb1

之所以选取4kB这个值,一是觉得固态硬盘的小文件随机读写能力很强劲,二是我机器主要跑的几个应用产生的I/O大小都集中在4-8kB。
之后,跟IRC上的老外聊了聊天,老外说我的确把Chunk设置得太小了,但他也表示,并不知道取什么值是合适的。
于是我打算今晚试试把Chunk设置成16kB,试试看。

软件RAID测试·三

上一篇的最后,忘了校验失效一块硬盘前后测试文件的md5码,补在这里。

# md5sum /home/pi.txt
af3c72e86be578c48dca28044333294a  /home/pi.txt

好的,完美无缺。
现在我又往虚拟机里面添加了块硬盘。
要做的事情是给这个阵列动态扩容。遗憾的是,mdadm目前并不支持给raid-10直接扩容,会报错。
那先把这个阵列转成RAID-0试试。

mdadm --grow /dev/md127 --raid-devices=6
mdadm: RAID10 can only be changed to RAID0

mdadm --grow /dev/md127 --level=0
mdadm: level of /dev/md127 changed to raid0

等数据重新分条完后,再转成RAID-10
这时候,出了件意料外的事情。

mdadm --grow /dev/md127 --level=10
mdadm: Need 2 spares to create working array, and only have 0.

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid0 sdg1[8] sdf1[4]
      16766976 blocks super 1.2 4k chunks

看来,RAID-10转RAID-0是简单的把用作镜像的两个盘给下掉了。
先往阵列里面添加四个Spare,再转化次试试。

mdadm --manage /dev/md127 --add /dev/sdb1
mdadm: add new device failed for /dev/sdb1 as 2: Invalid argument

报错误的参数。跑去Wiki查了下,发现如下字样。

the RAID level 1/4/5/6 array can be grown for example using this command

那就很遗憾了,目前的版本RAID-10一旦被建立起来,就无法往阵列里面加盘了。

软件RAID测试·二

一个逻辑卷组,物理卷是由四块硬盘组成的RAID-10,拿出了一部空间做了个逻辑卷,格式化成了XFS文件系统。
之后我顺手把虚拟机关掉了,没有按LinuxRaidWiki上的说法保存mdadm设置,但是当我再打开虚拟机的时候发现新建的md127安然无恙,看来在最近的某次版本变更里面,已经无需时刻保存设置了。
现在把lvol0的挂载点写到fstab里面去。先找到它的UUID。

# ls -lh /dev/mapper/
total 0
crw------- 1 root root 10, 236 Mar 24 18:08 control
lrwxrwxrwx 1 root root       7 Mar 24 18:08 ubuntu--vg-root -> ../dm-1
lrwxrwxrwx 1 root root       7 Mar 24 18:08 ubuntu--vg-swap_1 -> ../dm-2
lrwxrwxrwx 1 root root       7 Mar 24 18:08 vg0-lvol0 -> ../dm-0

可以看到,vg0-lvol0实际上是个软链。

# ls -lh /dev/disk/by-uuid/
total 0
lrwxrwxrwx 1 root root 10 Mar 24 18:08 5486a45b-5131-4f73-9710-8a0910bd91b5 -> ../../dm-2
lrwxrwxrwx 1 root root 10 Mar 24 18:08 c1f59da3-e4b9-49f4-8242-1ea9a0a7c2fe -> ../../dm-0
lrwxrwxrwx 1 root root 10 Mar 24 18:08 cdb31aba-081c-4bca-a110-37451fd5c1ac -> ../../sda1
lrwxrwxrwx 1 root root 10 Mar 24 18:08 eb44bd7c-f9bf-4123-987c-213bbe29eec0 -> ../../dm-1

其实也可以用blkid这个小程序直接查看UUID。
好,UUID拿到手,就顺手把它挂载到/home算了。略过编辑fstab过程。

# mount
(略)
/dev/mapper/vg0-lvol0 on /home type xfs (rw)

接下来,我们试试往已经建好的RAID-10里面再添加一块硬盘作为热备盘,新盘已经分好区了。

# mdadm --manage /dev/md127 --add /dev/sdf1
mdadm: added /dev/sdf1

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid10 sdf1[4](S) sdc1[1] sdb1[0] sde1[3] sdd1[2]
      16766952 blocks super 1.2 4K chunks 2 near-copies [4/4] [UUUU]

显示”sdf1[4](S)”的意思,是指sdf1是这个阵列的第5块盘,属性是Spare,就是备份盘的意思。
现在,试试往已经建好的文件系统里面写入数据。

# pi 1000000 > /home/pi.txt

# md5sum /home/pi.txt
af3c72e86be578c48dca28044333294a  /home/pi.txt

然后让阵列里面的一块盘失效看看。

# mdadm --manage /dev/md127 --fail /dev/sdb1
mdadm: set /dev/sdb1 faulty in /dev/md127

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid10 sdf1[4] sdc1[1] sdb1[0](F) sde1[3] sdd1[2]
      16766952 blocks super 1.2 4K chunks 2 near-copies [4/3] [_UUU]
      [=====>...............]  recovery = 25.2% (2117848/8383476) finish=0.6min speed=151274K/sec

可以看到sdb1这块盘已经被标记Fail,而原本被标记Spare的sdf1已经顶了上去,整个阵列正在进行重建,剩余时间0.6min。

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid10 sdf1[4] sdc1[1] sdb1[0](F) sde1[3] sdd1[2]
      16766952 blocks super 1.2 4K chunks 2 near-copies [4/4] [UUUU]

重建已经完成。由于这块被标记Fail的盘实际上没坏,我们再把它加回去,作为Spare。

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid10 sdb1[5](S) sdf1[4] sdc1[1] sde1[3] sdd1[2]
      16766952 blocks super 1.2 4K chunks 2 near-copies [4/4] [UUUU]

软件RAID测试·一

测试环境:VBox
测试发行版:Ubuntu Server 13.10
这次想要测试的是RAID-10,以及相关的东东。
首先在虚拟机里面添加4块硬盘,并且依次分好区。

# mdadm --verbose --create /dev/md127 --chunk=4 --level=10 --raid-devices=4 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1
mdadm: layout defaults to n2
mdadm: layout defaults to n2
mdadm: size set to 8383476K
mdadm: Defaulting to version 1.2 metadata
mdadm: array /dev/md/device started.

“–level=10″这个参数是指明RAID等级为10。
所谓的RAID-10就是把偶数块的硬盘两两分组,组合成数组RAID-1,在上层再把这数组RAID-1组成一个RAID-0。
我这里就是两组RAID-1,组成一个RAID-0。
“–chunk=4″这个参数是指明数据分条的大小为4KB。
设置这样的值是这样一个意思:
假如某此IO的大小是9KB,那么分条后会变成4KB+4KB+1KB这样三组数据条,分别写入到两组RAID-1阵列里面。
废话说完了检验下mdadm的状态。

# mdadm --detail --scan
ARRAY /dev/md/device metadata=1.2 name=ubuntu:device UUID=57394299:2e698d3c:b1a4d9fb:f21b67cf

# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md127 : active raid10 sde1[3] sdd1[2] sdc1[1] sdb1[0]
      16766952 blocks super 1.2 4K chunks 2 near-copies [4/4] [UUUU]

于是一个横跨四块硬盘的RAID-10阵列创建成功了。
为方便管理,将这个新建的阵列加入一个新建的卷组中。

# pvcreate /dev/md127
  Physical volume "/dev/md127" successfully created

# vgcreate vg0 /dev/md127
  Volume group "vg0" successfully created

# vgdisplay
  --- Volume group ---
  VG Name               vg0
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               15.99 GiB
  PE Size               4.00 MiB
  Total PE              4093
  Alloc PE / Size       0 / 0
  Free  PE / Size       4093 / 15.99 GiB
  VG UUID               sKRYGY-6dy6-TGI1-O4VN-OQtn-8SEQ-uOGULD

并且创建一个大小为8G的逻辑卷。

# lvcreate -L 8G vg0
  Logical volume "lvol0" created

# lvdisplay
  --- Logical volume ---
  LV Path                /dev/vg0/lvol0
  LV Name                lvol0
  VG Name                vg0
  LV UUID                hIh4m0-jITD-GMYx-3rz4-g0zW-Xc4D-6AjekD
  LV Write Access        read/write
  LV Creation host, time ubuntu, 2014-03-24 15:52:40 +0800
  LV Status              available
  # open                 0
  LV Size                8.00 GiB
  Current LE             2048
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           252:2

接下来,将这个卷格式化为XFS文件系统。

# mkfs.xfs /dev/mapper/vg0-lvol0
meta-data=/dev/mapper/vg0-lvol0  isize=256    agcount=8, agsize=262143 blks
         =                       sectsz=512   attr=2, projid32bit=0
data     =                       bsize=4096   blocks=2097144, imaxpct=25
         =                       sunit=1      swidth=2 blks
naming   =version 2              bsize=4096   ascii-ci=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

可以看到,这里面有这这样两个数据:
sunit=1,swidth=2 blks
第一个数据是stripe unit的简称,数值等于blocksize/chunksize。
第二个数据是stripe width的简称。
可以看到,这些数值都是与硬盘阵列有关系的。
在硬盘阵列上使用XFS的原因,就是它有这样一些针对性的的东西,有助于更好的使用硬盘阵列。