ASMLibに関する検証 その6

投稿日: 2009年4月08日

<ASMLibに関する検証 その6>
ペンネーム: ソラ

今回も引き続き、ASMLib Kernel Driver(以下、ASMLib)に関する検証を行いま
す。

■前回のおさらい
前回は、ASMLibのメリット「I/O処理の効率がよくなる」について、ディスク
からの読み込みと書き込みに関連する処理を、SELECT文(ディスクからの読み
込み)とINSERT文(ディスクへの書き込み)の場合での効果を実行時間で測定し
ました。
検証の結果、ASMLibを使用することで、ディスクへの書き込み(INSERT文)が少
し高速化することがわかりました。
それでは、なぜ高速化するのか検証していきたいと思います。

■■■■■概要■■■■■
1.調査項目
2.インスタンスのOPEN時にDBWRが発行するシステムコール
3.INSERT文実行時のDBWRが発行するシステムコール
4.ASMLibに関する検証のまとめ

■検証環境
Red Hat Enterprise Linux Server release 5
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0

1.調査項目
高速化した理由について、まずは、RAWデバイスとASMLibを使用している場合
での違いから探します。
INSERT文のようなデータをディスクに書き込む処理と関連性の高いバックグラ
ウンド・プロセスはDBWRとLGWRです。
本検証では、以下の2つの状況でDBWRプロセスが発行しているシステムコール
の違いに着目して調査します。

状況1:インスタンスのOPEN時(データファイルのオープン時)
状況2:INSERT文実行時

2.インスタンスのOPEN時にDBWRが発行するシステムコール
以下、straceコマンドを使用して、インスタンスのOPEN時にDBWRが発行したシ
ステムコールを確認した結果、大きく違いが見られた部分です。

RAWデバイスの場合
open("/dev/raw/raw1", O_RDWR|O_SYNC)    = 19
fcntl(19, F_SETFD, FD_CLOEXEC)          = 0

ASMLibの場合
open("/opt/oracle/extapi/64/asm/orcl/1/libasm.so", O_RDONLY) = 19
read(19, "177ELF2113>1 21
                                                   "..., 832) = 832
fstat(19, {st_mode=S_IFREG|0755, st_size=18176, ...}) = 0
mmap(NULL, 2113432, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE,
                                              19, 0) = 0x2ac1aca92000
mprotect(0x2ac1aca96000, 2093056, PROT_NONE) = 0
mmap(0x2ac1acc95000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED
                         |MAP_DENYWRITE, 19, 0x3000) = 0x2ac1acc95000
close(19)                               = 0
open("/dev/oracleasm/.check_iid", O_RDWR) = 19
write(19, "MSA233023", 24) = 24
read(19, "MSA233023", 24) = 24
close(19)                               = 0 000019>
open("/dev/oracleasm/iid/0000000000000013", O_RDWR|O_CREAT, 0770) = 19
fcntl(19, F_GETFD)                      = 0
fcntl(19, F_SETFD, FD_CLOEXEC)          = 0

大きく違う部分としては以下の2点です。
1.libasm.soのopenの有無
2.データファイルのopenシステムコール発行時のO_SYNCオプション

1つめのlibasm.soは、ASMLibをインストールした際に配置されるファイル
です。
そのため、ASMLibの動作に必要なライブラリを使用可能にしているだけのため
ASMLibを使用する環境としては当然の動作です。

2つめについて、O_SYNCオプションを使用している場合は同期モードでデータ
ファイルのopenすることになります。
また、オプションを使用していない場合では非同期モードでファイルをopenす
ることになります。

つまり、ASMLibの場合は非同期モードでファイルをopenしているために高速化
しているということなのでしょうか?
実際にその仮説が正しいのか判断するために、まずはOSのシステムコールだけ
で考えた場合、同期モードと非同期モードではどのくらい違いが出てくるのか
を知る必要があります。
ということで、実際に確認します。
以下、確認に使用したスクリプトです。

<同期モード確認用スクリプト>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define BUF_SIZE 0x500000
int main(int argc, char **argv)
{
char buf[BUF_SIZE + 1];
int count = 0;
int fd;
int i;

if (argc != 2) {
printf("Usage: $ ./sync 100(write count)n");
return -1;
}
count = atoi(argv[1]);
if (count < 1) {
printf("Usage: $ ./sync 100(write count)n");
return -1;
}
fd = open("file1", O_CREAT | O_WRONLY | O_SYNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
printf("failed to open:errno=%dn", errno);
return -1;
}
memset(buf, 1, BUF_SIZE);
buf[BUF_SIZE] = '';
for (i = 0; i < count; i++) {
write(fd, buf, BUF_SIZE);
}
close(fd);
return 0;
}

<非同期モード確認用スクリプト>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define BUF_SIZE 0x500000
int main(int argc, char **argv)
{
char buf[BUF_SIZE + 1];
int count = 0;
int fd;
int i;

if (argc != 2) {
printf("Usage: $ ./sync 100(write count)n");
return -1;
}
count = atoi(argv[1]);
if (count < 1) {
printf("Usage: $ ./sync 100(write count)n");
return -1;
}
fd = open("file2", O_CREAT | O_WRONLY , S_IRUSR | S_IWUSR);
if (fd == -1) {
printf("failed to open:errno=%dn", errno);
return -1;
}
memset(buf, 1, BUF_SIZE);
buf[BUF_SIZE] = '';
for (i = 0; i < count; i++) {
write(fd, buf, BUF_SIZE);
}
close(fd);
return 0;
}

以下は上記スクリプトの第一引数に20を渡し、それぞれ5MBの書き込みを
行った際の実行時間です。

<同期モード>
real    0m2.886s
user    0m0.000s
sys     0m0.268s

<非同期モード>
real    0m0.361s
user    0m0.001s
sys     0m0.360s

上記のように同期モードと非同期モードでは2秒以上差が出る結果になりました。
前回のINSERT文での検証ではこれ以上の書き込みを行っているにも関わらず、
実行時間に差が上記ほど見られないことから、単純にファイルのopenの仕方が
同期モードか、非同期モードであるかという説明では納得しにくいことがわか
ります。

3.INSERT文実行時のDBWRが発行するシステムコール
それでは次に、INSERT文実行時のシステムコールを確認します。
straceコマンドを使用して確認した結果、発行されているシステムコール自体
に違いが見られたので結果の一部を抜粋します。

======================straceコマンドの結果============================
RAWデバイスを使用している場合
io_submit(47418402635776, 6, {
{0x2b207560e1a0, 0, 1, 0, 19},
{0x2b207560d7a0, 0, 1, 0, 19}, {0x2b207560d1a0, 0, 1, 0, 19},
{0x2b207560d9a0, 0, 1, 0, 19}, {0x2b207560dfa0, 0, 1, 0, 19},
{0x2b207560d3a0, 0, 1, 0, 19}}) = 6
io_getevents(47418402635776, 4, 128, {
{0x2b207560e1a0, 0x2b207560e1a0, 212992, 0},
{0x2b207560d3a0, 0x2b207560d3a0, 8192, 0},
{0x2b207560dfa0, 0x2b207560dfa0, 8192, 0},
{0x2b207560d1a0, 0x2b207560d1a0, 344064, 0}},
{600, 0}) = 4
times(NULL)                             = 500725677
io_submit(47418402635776, 8, {
{0x2b207560d1a0, 0, 1, 0, 19},
{0x2b207560dfa0, 0, 1, 0, 19},
{0x2b207560d3a0, 0, 1, 0, 19},
{0x2b207560e1a0, 0, 1, 0, 19},
{0x2b207560dda0, 0, 1, 0, 19},
{0x2b207560c5a0, 0, 1, 0, 19},
{0x2b207560c7a0, 0, 1, 0, 19},
{0x2b207560e5a0, 0, 1, 0, 19}}) = 8
io_getevents(47418402635776, 10, 128, {
{0x2b207560dda0, 0x2b207560dda0, 212992, 0},
{0x2b207560c7a0, 0x2b207560c7a0, 212992, 0},
{0x2b207560d7a0, 0x2b207560d7a0, 704512, 0},
{0x2b207560d9a0, 0x2b207560d9a0, 704512, 0},
{0x2b207560c5a0, 0x2b207560c5a0, 835584, 0},
{0x2b207560e1a0, 0x2b207560e1a0, 704512, 0},
{0x2b207560e5a0, 0x2b207560e5a0, 835584, 0},
{0x2b207560d3a0, 0x2b207560d3a0, 8192, 0},
{0x2b207560d1a0, 0x2b207560d1a0, 8192, 0},
{0x2b207560dfa0, 0x2b207560dfa0, 8192, 0}},
{600, 0}) = 10

ASMLibを使用している場合
read(19, "MSA