kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

Thunderbird

Mozilla Thunderbird 最小化附加组建

在工具->附加组建中
1、搜索minimize,安装firetray
2、firetray 首选项->邮件->邮件通知类型 选第二个:显示新邮件图示
不想最小化到托盘: firetray 首选项->视窗 去掉第二个勾选

Mozilla Thunderbird 导入导出邮件

一种Mozilla Thunderbird的扩展ImportExportTools。
https://addons.mozilla.org/zh-CN/thunderbird/addon/importexporttools/

安装流程 (本地安装)
1
2
3
4
5
1 进入Mozilla Thunderbird
2 点击菜单栏的“工具”->“附加软件”
3 从附加组件搜索框旁边的选项按钮中,选择“从文件安装附加组件...”选项
4 选择本地文件(ImportExportTools-X.X.xpi)位置 安装
5 安装完成 重启Mozilla Thunderbird
如何用呢
1
2
3
4
5
1 进入Mozilla Thunderbird
2 右键“收件箱”
3 “导入/导出”
4 “汇出此资料夹所以的邮件” 进行选择格式
5 汇出完成 查看本地文件夹

如何知道文件被那个进程写

一个文件正在被进程写 我想查看这个进程 文件一直在增大 找不到谁在写 使用lsof也没找到

这个问题挺有普遍性的,解决方法应该很多,这里我给大家提个比较直观的方法。

linux下每个文件都会在某个块设备上存放,当然也都有相应的inode, 那么透过vfs.write我们就可以知道谁在不停的写入特定的设备上的inode。

幸运的是systemtap的安装包里带了inodewatch.stp,位于/usr/local/share/doc/systemtap/examples/io目录下,就是用来这个用途的。

我们来看下代码:

$ cat inodewatch.stp

1
2
3
4
5
6
7
8
9
10
#! /usr/bin/env stap
 
probe vfs.write, vfs.read
{
	# dev and ino are defined by vfs.write and vfs.read
	if (dev == MKDEV($1,$2) # major/minor device
		&& ino == $3)
	printf ("%s(%d) %s 0x%x/%u\n",
		execname(), pid(), probefunc(), dev, ino)
}

这个脚本的使用方法如下: stap inodewatch.stp major minor ino

下面我们构造个场景: dd不停的写入一个文件,查出这个文件的ino, 以及它所在设备的major, minor, 运行stap脚本就可以得到答案。

场景交代好了,我们来演示下:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ pwd
/home/chuba
$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
...
/dev/sdb1            1621245336 825209568 713681236  54% /home
...
$ ls -al /dev/sdb1
brw-rw---- 1 root disk 8, 17 Oct 24 11:22 /dev/sdb1 
$ rm -f test.dat && dd if=/dev/zero of=test.dat
^C9912890+0 records in
9912890+0 records out
5075399680 bytes (5.1 GB) copied, 26.8189 s, 189 MB/s

这个终端模拟文件的不停写入,同时在另外一个终端查验谁干的。这里我们已经知道设备的major/minor为8/17

1
2
3
4
5
6
7
8
9
10
$ stat -c '%i' test.dat
25337884
$ sudo stap /usr/local/share/doc/systemtap/examples/io/inodewatch.stp 8 17 25337884
dd(740) vfs_write 0x800011/25337884
dd(740) vfs_write 0x800011/25337884
dd(740) vfs_write 0x800011/25337884
dd(740) vfs_write 0x800011/25337884
dd(740) vfs_write 0x800011/25337884
dd(740) vfs_write 0x800011/25337884
...

看到了吧,dd是罪魁祸首,pid是740

通过blktrace, debugfs分析磁盘IO

如何通过blktrace+debugfs找到发生IO的文件,然后再结合自己的应用程序,分析出这些IO到底是 谁产生的,最终目的当然是尽量减少不必要的IO干扰,提高程序的性能。

blktrace是Jens Axobe写的一个跟踪IO请求的工具,Linux系统发起的IO请求都可以通过blktrace捕获并分析,关于这个工具的介绍请自行google之,这里推荐我们部门的褚霸同学的blog,里面有好几篇文章分别介绍了blktrace, blkparse以及blkiomon等工具的使用。

debugfs是ext2, ext3, ext4文件系统提供的文件系统访问工具,通过它我们可以不通过mount文件系统而直接访问文件系统的内容,它是e2fsprogs的一部分,默认应该都是安装的,详细的说明可以通过man debugfs得到。

下面我来演示一下如何通过这两个工具的配合来找到磁盘IO的源头。

先看一个简单的例子:
在一个终端会输入如下命令:

1
while [ 1 ];do dd if=/dev/zero of=test_file bs=4k count=20 seek=$RANDOM oflag=sync;done

随机的在test_file里面写数据造成较大的IO压力,现在看看如何通过blktrace和debugfs抓到它。

1、通过iostat观察到有很大的磁盘压力

1
2
Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
sdb               0.00  2759.00    0.00 3515.50     0.00 50196.00    14.28     0.90    0.26   0.24  85.70

2、我们看到sdb压力很大,这时候就需要通过blktrace抓取对应盘的数据
blktrace /dev/sdb 有IO压力的时候一会儿就可以了,通过ctrl+c停止抓取。
blktrace是需要debugfs支持的,如果系统提示debugfs没有mount,需要先mount上
mount -t debugfs none /sys/kernel/debug 再执行blktrace命令

3、将blktrace抓出来的二进制文件转成文本格式。
blkparse sdb.blktrace.* > 1.log
或blktrace -d /dev/sda -o - |blkparse -i - > 1.log

4、开始分析日志

1
2
3
4
5
6
7
  grep ‘ A ‘ 1.log|head -n 5

8,16   0       39     0.001242727  2872  A  WS 420143 + 8 <- (8,17) 420080
8,16   0       52     0.001361766  2872  A  WS 420151 + 8 <- (8,17) 420088
8,16   0       65     0.001440210  2872  A  WS 420159 + 8 <- (8,17) 420096
8,16   0       78     0.001518207  2872  A  WS 420167 + 8 <- (8,17) 420104
8,16   0       91     0.001596083  2872  A  WS 420175 + 8 <- (8,17) 420112

为啥要grep ‘ A ‘呢?因为这条信息是上层一个读写请求进入到Linux IO协议栈的第一步,只有在这里我们可以看到清晰的请求原始信息。比如

1
8,16   0       39     0.001242727  2872  A  WS 420143 + 8 <- (8,17) 420080

这条说明是设备(8,17)也就是sdb1上产生的扇区为420080的写请求(读请求的话会在WS对应的位置出现‘R’),长度是8,它被映射到(8,16)上位置为420143。这个IO请求的完整生命周期是这样的:

1
2
3
4
5
 8,16   0       39     0.001242727  2872  A  WS 420143 + 8 <- (8,17) 420080
 8,16   0       41     0.001244984  2872  G  WS 420143 + 8 [dd]
 8,16   0       43     0.001246609  2872  I  WS 420143 + 8 [dd]
 8,16   0       45     0.001255064  2872  D  WS 420143 + 8 [dd]
 8,16   0       46     0.001325168     0  C  WS 420143 + 8 [0]

可以看到从’ A ‘的下一条开始都是以整个设备的扇区号为标识的,不方便我们找到对应的分区。

5、下面就开始通过debugfs来分析这条读写请求的来源了。 (8, 17)是sdb1, 420080是扇区号(IO层的基本单位是扇区sector,大小是512bytes),而文件系统层是通过块block来管理的,一般的 ext3,ext4的块block大小是4096[1],由此可得这个请求对应到文件系统的块block号是420080/8=52510, debugfs提供了命令icheck可以通过block号找到它对应的文件的inode。

1
2
3
4
#debugfs -R ‘icheck 52510′ /dev/sdb1
debugfs 1.43-WIP (1-Aug-2012)
Block Inode number
52510 12

6、通过inode number找到对应的文件名,很幸运,debugfs又提供了另外一条命令ncheck可以找到inode对应的文件名[2]。

1
2
3
4
#debugfs -R ‘ncheck 12′ /dev/sdb1
debugfs 1.43-WIP (1-Aug-2012)
Inode Pathname
12 //test_file

大家可以看到,我们现在已经成功找到了test_file这个文件啦,至此块设备层和文件系统层的分析工作已经结束了,下面就可以结合应用看看为啥会对这个文件有如此频繁的读写操作了!

[1] 块大小实际上也能够通过debugfs来得到。

1
debugfs -R ‘stats’ /dev/sdb1|grep “Block size”

[2] 有的同学找到的inode number是8,然后却无法找到对应的文件名。这是因为8是ext3/4文件系统中的日志文件的inode,它是隐藏文件,所以无法找到,可以再试试其他的block号哦!

根据inode你就可以找到对应的文件是什么了
find / -inum your_inode