众所周知,文件系统中的journal
device主要有两个目的:
1.保证数据的一致性;
2.缩短写响应时间
要保证数据的一致性,当然避免不了和磁盘write
cache的交互,这体现在两个层次:
1.文件系统中对journal
device的写
充分利用journal
device的写速度快的特点,写操作先到journal
device设备,一次写到journal
device的事务包括要写的data和下次取它才需要的最少的meta
data。如何确保这些数据彻底落到journal
device上,有两种处理方式:
a.完全disable
disk write cache,这样保证每次对journal
device的写都已经返回;
b.利用disk
write cache flush机制,在用作journal
device的设备上的每次写在隔一段时间就flash
write cache,或者在
2. 文件系统对物理磁盘的写
对于最终落到存储设备上的写,因为有journal
device背书,可以异步也可以同步写,但要求保证对于每次写事务:写返回之前肯定能确保数据落到磁盘,而不会在write
cache里。考虑到和journal
device的配合,一般流程包括两个线程:
2.1落盘线程
a.从journal
device读取还未了落盘的写请求记录;
a.执行真正磁盘写;
b.调用对于磁盘设备的flushwrte cache操作;
c.对于已经完全落盘的操作,从journal
device中去掉对应的记录
d.返回
至此,一次彻底落盘的写才算完成。
2.2写提交线程
a.打包写请求中的data和metadata
(包括offset,起始地址等),生成对journal
device写的原始数据
b.从journal
device上寻找合适的空间,记录上面的写请求,也就上把上面的原始数据写入;
c.如果journal
device的写缓存没有关闭,刷journal
device的写缓存,确保数据落到journal
device物理存储设备上;
d.向上层返回写请求
至此,一次写请求返回。
根据上面分析,写响应时间是从写请求发出到写提交线程中的步骤d完成的时间。由于通常日志设备比普通磁盘的读写速度快很多,因此它能大大缩短写响应时间。但如果journal
device上的写请求由于没有及时下发,被撑满了,那么它就基本上只有执行落盘线程的路径了,可也遇见此时写响应时间会急剧增加很多。
综合考虑到写提交线程和落盘线程的配合,可以看到在有文件系统journal
device背书的情况下,落盘线程可以从同步写变成异步写,只要最终保证写请求能够按照先来后到的顺序落盘即可,这样理论上能够增加IO吞吐量。但是实际要达到这一效果,需要journal
device和磁盘的紧密协同才行。
3.刷写缓存的操作和关闭写缓存的方法
可以参考下面对SCSI/sas盘的刷写缓存的操作:
static
int flushSCSIwc(int fd) {
struct
sg_io_hdr io_hdr;
unsigned
char sense_b[32];
unsigned
char cmdp[10];
memset(&io_hdr,
0, sizeof(struct sg_io_hdr));
memset(sense_b,
0, sizeof(sense_b));
memset(cmdp,
0, sizeof(cmdp));
io_hdr.interface_id
= ‘S‘;
io_hdr.dxfer_direction
= SG_DXFER_NONE;
cmdp[0]
= 0x35;
cmdp[1]
= 0x00;
cmdp[2]
= 0x00;
cmdp[3]
= 0x00;
cmdp[4]
= 0x00;
cmdp[5]
= 0x00;
cmdp[6]
= 0x00;
cmdp[7]
= 0x00;
cmdp[8]
= 0x00;
cmdp[9]
= 0x00;
io_hdr.cmdp
= cmdp;
io_hdr.cmd_len
= sizeof(cmdp);
io_hdr.sbp
= sense_b;
io_hdr.mx_sb_len
= sizeof(sense_b);
io_hdr.timeout
= 60000;
if(ioctl(fd,
SG_IO, &io_hdr) == -1)
if(io_hdr.status
!= 0)
return
EIO;
return
0;
}
而关闭写缓存的办法也很简单:
hdparm
-W1 /dev/sdq
当然也可以用MegaCLI或者lsitutil等工具来控制。