LVMでディスクを追加
LVM は公式ドキュメントがどこにあるのかわからない。
とりあえずこれを読んでみる。
http://tldp.org/HOWTO/LVM-HOWTO/commontask.html
- pvcreate で /dev/xvdb を全部 PV とする。
HOWTO では推奨されてないが、Linux 以外からパーティションを認識できなくなる、という問題であって、今回の環境では Linux以外で管理するつもりがないので問題無しとする。
[root@ikura ~]# LANG=C date; pvcreate /dev/xvdb; LANG=C date Wed Sep 16 21:50:31 JST 2009 Physical volume "/dev/xvdb" successfully created Wed Sep 16 21:50:31 JST 2009 [root@ikura ~]#
オンラインでディスクの追加できるのか?
まあ、バックアップ取ってるし試してみるか。
[root@ikura ~]# vgscan --verbose Wiping cache of LVM-capable devices Wiping internal VG cache Reading all physical volumes. This may take a while... Finding all volume groups Finding volume group "VolGroup00" Found volume group "VolGroup00" using metadata type lvm2 [root@ikura ~]# [root@ikura ~]# vgextend VolGroup00 /dev/xvdb Volume group "VolGroup00" successfully extended [root@ikura ~]#
うげ、成功した。意味わからん。
いや、PV - VG - LV という関係だから、 VG にディスクを追加するのは問題ないかも。
[root@ikura ~]# df -h Filesystem サイズ 使用 残り 使用% マウント位置 /dev/mapper/VolGroup00-LogVol00 3.3G 2.6G 528M 84% / /dev/xvda1 99M 43M 52M 45% /boot tmpfs 129M 0 129M 0% /dev/shm [root@ikura ~]#
df は変化無し。
VG にディスクを追加した。次に LV を拡張すればいいはず。
これはオンラインでできるのか?
いや、原点回帰。現在の状況を整理しよう。
[root@ikura ~]# pvscan PV /dev/xvda2 VG VolGroup00 lvm2 [3.88 GB / 0 free] PV /dev/xvdb VG VolGroup00 lvm2 [3.97 GB / 3.97 GB free] Total: 2 [7.84 GB] / in use: 2 [7.84 GB] / in no VG: 0 [0 ] [root@ikura ~]# pvdisplay --- Physical volume --- PV Name /dev/xvda2 VG Name VolGroup00 PV Size 3.90 GB / not usable 24.72 MB Allocatable yes (but full) PE Size (KByte) 32768 Total PE 124 Free PE 0 Allocated PE 124 PV UUID SVwvda-AetG-AJdi-qtz0-vnS9-sdh7-prptlk --- Physical volume --- PV Name /dev/xvdb VG Name VolGroup00 PV Size 4.00 GB / not usable 32.00 MB Allocatable yes PE Size (KByte) 32768 Total PE 127 Free PE 127 Allocated PE 0 PV UUID 4013gs-R1mw-zlIM-OFdc-sTUC-Fz2g-IGXdr3 [root@ikura ~]#
PV として /dev/xvdb を認識できている。
これは pvcreate /dev/xvdb で PV として追加できた、ということかもしれない。
[root@ikura ~]# vgscan Reading all physical volumes. This may take a while... Found volume group "VolGroup00" using metadata type lvm2 [root@ikura ~]# vgdisplay --- Volume group --- VG Name VolGroup00 System ID Format lvm2 Metadata Areas 2 Metadata Sequence No 4 VG Access read/write VG Status resizable MAX LV 0 Cur LV 2 Open LV 2 Max PV 0 Cur PV 2 Act PV 2 VG Size 7.84 GB PE Size 32.00 MB Total PE 251 Alloc PE / Size 124 / 3.88 GB Free PE / Size 127 / 3.97 GB VG UUID jjBm64-Yd3Y-Ml2V-2RAt-4HoV-CzCT-2sVjLA [root@ikura ~]#
うーん、わからん。 vgdisplay の出力に 3.88, 3.97 という値が見るが、これは VG として追加されているからなのか?vgextend の結果、ここに追加されたのだろうか。
えい。
[root@ikura ~]# lvextend -L+3900M /dev/VolGroup00/LogVol00 Rounding up size to full physical extent 3.81 GB Extending logical volume LogVol00 to 7.16 GB Logical volume LogVol00 successfully resized [root@ikura ~]#
あれ、追加できた。気持ち悪い。
[root@ikura ~]# df -h Filesystem サイズ 使用 残り 使用% マウント位置 /dev/mapper/VolGroup00-LogVol00 3.3G 2.6G 528M 84% / /dev/xvda1 99M 43M 52M 45% /boot tmpfs 129M 0 129M 0% /dev/shm [root@ikura ~]#
df の出力は同じまま。
resize2fs でリサイズすればいいのかな。
次。single user mode で起動。
resize2fs を試みる。
だめだ。resize2fs をしたい / に resize2fs が入っているので、シングルユーザモードにしても無駄。
今は bootable なメディアが無いし、LVM で HDD を増強するのはめんどい。
bootable なメディアが手に入る迄本件保留とする。
DOM-U ikura にディスクイメージを追加。
- ディスクイメージを作る。
特に意味はないが、既存のイメージファイルと合わせることにする。
[root@gohan ~]# ls -l /var/lib/xen/images/ikura.img
- rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
ぴったり 4GB だ。これに 4GB を追加する。
[root@gohan ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/VolGroup00-LogVol00 36G 15G 19G 44% / /dev/sda1 99M 43M 52M 45% /boot tmpfs 1.8G 0 1.8G 0% /dev/shm none 1.8G 128K 1.8G 1% /var/lib/xenstored [root@gohan ~]#
空き容量は十分だ。
4GB のディスクイメージを作る。
[root@gohan ~]# dd if=/dev/zero bs=1024 count=`echo '4 * 1024 * 1024' | bc` > /var/lib/xen/images/ikura-2.img 4194304+0 records in 4194304+0 records out 4294967296 bytes (4.3 GB) copied, 222.965 seconds, 19.3 MB/s [root@gohan ~]# ls -l /var/lib/xen/images/ikura*.img
- rw-r--r-- 1 root root 4294967296 Sep 16 21:10 /var/lib/xen/images/ikura-2.img
- rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
あ!1byte ちがうwww
追記で帳尻合わせをする。
[root@gohan ~]# dd if=/dev/zero bs=1 count=1 >> /var/lib/xen/images/ikura-2.img 1+0 records in 1+0 records out 1 byte (1 B) copied, 6.7e-05 seconds, 14.9 kB/s [root@gohan ~]# ls -l /var/lib/xen/images/ikura*.img
- rw-r--r-- 1 root root 4294967297 Sep 16 21:12 /var/lib/xen/images/ikura-2.img
- rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
- ikura にログインして shutdown する。
[root@gohan images]# xm list Name ID Mem(MiB) VCPUs State Time(s) Domain-0 0 3464 1 r----- 13936.5 ikura 2 255 1 ------ 27053.3 [root@gohan images]#
うん。よし。
- /etc/xen/ikura の編集
加えた変更は次だけ。
[root@gohan ~]# diff /etc/xen/ikura_2009-09-16 /etc/xen/ikura 11c11 < disk = [ "tap:aio:/var/lib/xen/images/ikura.img,xvda,w" ]
-
- -
- ikura のバックアップ
ikura 作業で事故がないようにバックアップを取得しておく。
[root@gohan ~]# LANG=C date; gzip < /var/lib/xen/images/ikura.img > /var/lib/xen/images/ikura.img_`date +%F`; LANG=C date Wed Sep 16 21:19:03 JST 2009 Wed Sep 16 21:31:17 JST 2009 [root@gohan ~]# ls -l /var/lib/xen/images/ikura*
- rw-r--r-- 1 root root 4294967297 Sep 16 21:12 /var/lib/xen/images/ikura-2.img
- rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
- rw-r--r-- 1 root root 1062451270 Sep 16 21:31 /var/lib/xen/images/ikura.img_2009-09-16
手順が逆になったが、 ikura-2.img のパーミッションを ikura.img に合わせておこう。多分、合わせた方が良いものだと思う。
- ikura 起動
[root@gohan ~]# xm create ikura Using config file "/etc/xen/ikura". Error: VM name 'ikura' already in use by domain 2 [root@gohan ~]#
あれ。動かない。
フォーラム見ると同様の事例があり、DOM-0側サーバの再起動でことなきをえた、らしい。でもまだ諦めない。xend を再起動してみる。
[root@gohan ~]# service xend status xend is running [root@gohan ~]# service xend stop Stopping xend: [ OK ] [root@gohan ~]# service xend status xend is stopped [root@gohan ~]# service xend start Starting xend: [ OK ] [root@gohan ~]# service xend status xend is running [root@gohan ~]# xm create -c ikura
動いた!
認識してるだろうか。どうたしかめればいいか。
[root@ikura ~]$ dmesg | grep -2 xvdb Registering block device major 202 xvda: xvda1 xvda2 xvdb: unknown partition table device-mapper: uevent: version 1.0.3 device-mapper: ioctl: 4.11.5-ioctl (2007-12-12) initialised: dm-devel@redhat.com [root@ikura ~]$
おっけーっぽい。
Xen ディスク追加方法を模索
/etc/xend/ikura に設定ファイルを見つけた。他人事のように言っているのは、しばらく触ってなくて手探りで探しているから。
ちなみに、ファイル名が ikura なのは disk full で困っている DOM-U のホスト名が ikura だからだ。
xen の設定はホスト名に合わせてある。なお、DOM-0 のホスト名は gohan だ。
disk
List of block devices to export to the domain e.g. disk = [ 'phy:hda1,sda1,r' ] exports physical device /dev/hda1 to the domain as /dev/sda1 with read-only access. Exporting a disk read-write which is currently mounted is dangerous - if you are certain you wish to do this, you can specify w! as the mode.http://tx.downloads.xensource.com/downloads/docs/user/#SECTION03210000000000000000公式マニュアルを見ると設定ファイルに disk をリストして記載する。リストといってるんだから、複数指定できるだろう。
今の記載は次のようになっている。これを複数にしたい。disk = [ "tap:aio:/var/lib/xen/images/ikura.img,xvda,w" ]既存のイメージファイル自体を大きくする(ができるかどうかは別として)、あるいは、新たなイメージファイルを作ってリストに追加してあげればいいだろう。
イメージファイル自体を変更する方法として
http://www.vinacis.net/content/view/32/32/
http://www.kelvinism.com/howtos/resize-xen-image/
に記載があるとおり、 dd で作ったファイルを追記書き込みする方法があるらしいが、
今回は DOM-U の ikura に OS インストール済みだし、ディスクの容量を後から変更する行為自体が微妙そうなのと、 ikura は LVM を使っていることから software raid でディスク追加ができそう、とのことで新たなイメージファイルを追加することで話を進める。LVM で raid 組んだこと無いから、面白そうだし。
対策を考える
プライオリティが高いのは disk full の解決だ。
disk full になったマシンをどうするか。
- サーバを捨てる。
- 新しく別のマシンを用意して、プログラム/データを移行する。
- Xen にディスク容量をなんとかして増やす。
いろいろデータが詰まってて、捨てるには持った無い。新しい Xen ゲストOSをするなりすれば、ディスク容量を簡単に大きい物を用意できる。でも、移行なんて考えたらめんどくさくてやってらんない。
ディスクの容量を増やしたい。
今の Xen のゲストOSのイメージファイルは /var/lib/xen/images にある。
このファイルをそのまま大きくすることができるか、あるいは、別のイメージを作って Xen のゲストOS にディスクを1コ追加するようなことができればいい。
ソートされた複数のCSVファイルを結合するスクリプト
問題
CSVファイルが複数存在する。各ファイルは異なる列データが保存されているが、どのファイルもCSV左端列でソートされている。これらを左端列でソートされた1つのCSVファイルにまとめたい。まとめるプログラムを作れ。
なお、CSVファイルは数万行を想定し、メモリ消費を考慮したプログラムを書くこと。
CSVデータ
data1.txt
#id,data11,data12 1,data111,data121 2,data112,data122 3,data113,data123 4,data114,data124 5,data115,data125 6,data116,data126 7,data117,data127
data2.txt
#id,data21,data22 0,data210,data220 1,data211,data221 4,data214,data224 5,data215,data225 6,data216,data226 7,data217,data227 8,data218,data228 9,data219,data229
data3.txt
#id,data31,data32 0,data310,data320 1,data311,data321 2,data312,data322 5,data315,data325 6,data316,data326 7,data317,data327 8,data318,data328 9,data319,data329
期待する出力例
※カンマだとわかりにくいので、タブ文字で出力してみた。
id data11 data12 data21 data22 data31 data32 0 data210 data220 data310 data320 1 data111 data121 data211 data221 data311 data321 2 data112 data122 data312 data322 3 data113 data123 4 data114 data124 data214 data224 5 data115 data125 data215 data225 data315 data325 6 data116 data126 data216 data226 data316 data326 7 data117 data127 data217 data227 data317 data327 8 data218 data228 data318 data328 9 data219 data229 data319 data329
回答例
Linux のメモリ管理動作確認のために作成したCコード
メモリを消費するためのプログラム。好きな量のメモリをmalloc/freeで割当/解放するだけ。 watch -d cat /proc/meminfo と合わせて使うことを想定。本当は swap させるまでメモリを使いたいんだけど、このプログラムじゃダメかも。割り当てるだけじゃだめなの?なんで?
#include <stdio.h> #include <stdlib.h> #include <string.h> struct list { unsigned char *buf; unsigned int buflen; struct list *next; }; void print_help(void) { puts("size_and_unit - allocate memory [b/k/m] (ex. 10m, 5k, 300b)"); puts("list - show memory size and index for freeing"); puts("free index - allocate memory [b/k/m]"); puts("help - print this message"); puts("quit - exit"); } void chomp(char *p) { while (*p != '\n' && *p != '\0') *p++; *p = '\0'; } void print_list(struct list *p) { int total = 0; int index = 0; while (p) { printf("index:%d, buflen:%d\n", index++, p->buflen); total += p->buflen; p = p->next; } printf("total:%d\n", total); } void print_alloc(struct list **head, int size) { if (*head == NULL) { if ((*head = malloc(sizeof(struct list))) == NULL) perror("malloc"); if (((*head)->buf = malloc(size)) == NULL) perror("malloc"); (*head)->buflen = size; (*head)->next = NULL; } else { struct list *p = *head; while (p->next != NULL) p = p->next; if ((p->next = malloc(sizeof(struct list))) == NULL) perror("malloc"); p = p->next; if ((p->buf = malloc(size)) == NULL) perror("malloc"); p->buflen = size; p->next = NULL; } printf("alloc %d bytes\n", size); } void print_free(struct list **head, int pos) { if (pos == 0) { struct list *next = (*head)->next; free((*head)->buf); free(*head); *head = next; } else { struct list *p = *head; int index = 0; while (p) { if (index + 1 == pos) { struct list *next = p->next->next; free(p->next->buf); free(p->next); p->next = next; break; } p = p->next; } } printf("free index#%d\n", pos); } int main(void) { char line[1024]; struct list *head = NULL; while (fgets(line, sizeof line, stdin)) { int size, unit, pos; chomp(line); if (!strcmp(line, "")) { ; } else if (!strcmp(line, "list")) { print_list(head); } else if (!strcmp(line, "help")) { print_help(); } else if (sscanf(line, "free %d", &pos) == 1) { print_free(&head, pos); } else if (sscanf(line, "%d%c", &size, &unit) == 2) { char *units = "bkm", *p; if ((p = strchr(units, unit)) != NULL) { int n = ((char *)p - units); while (n-- > 0) size *= 1024; printf("size=%d\n", size); print_alloc(&head, size); } else { printf("illeal unit given: %c", unit); } } else if (!strcmp(line, "quit")) { break; } else { printf("failed to parse: %s\n", line); } } return 0; } /* vim:set ts=4 sw=4 sts et nu ai: */