基于文件系统的生产者和消费者问题
周末的时候和team讨论了下如何用最简单的方式,提高数据文件的单位时间传输吞吐量。下面是一个简单的应用场景:
一个目录(DIR1),有很多Producer向这个目录里面放文件,同时有很多的Consumer负责从这个目录里面消费这些文件,插入数据库或者做其他的操作,然后删除或者移走这些文件。
假设条件:
- 一个文件中转目录DIR1,这个目录位于一个网络存储上
- 一个生产者,每一秒钟向DIR1里面放一个文件
- 若干个消费者,假设有8个,其实是8个不同的服务器,都可以访问DIR1,多台服务器可以起负载均衡的作用,任何一台或者几台出问题,整个数据流不会中断
- 解析一个文件大约需要2-14秒
- 最后一点:位于网络存储上的目录DIR1,我们认为它是不会出问题的,它不是这里的问题核心
这个场景很普遍,很多公司大概都会用到,尤其是那么比较老的系统(Legacy System),下面是两种方案:
方案一
Consumer循环扫描DIR1,一旦发现有文件,循环解析这些文件,这里有8台服务器,也就是说有8个Consumer一起这样做。代码如下:
public void run() {
System.out.println("Created consumer:" + threadName);
while (true) {
File file = new File(Constant.STAGING_FOLDER);
File files[] = file.listFiles();
for (int i = 0; i < files.length; ++i) {
File f = files[i];
parse(Constant.STAGING_FOLDER + "/" + f.getName());
}
Commons.sleep();
}
}
看起来很简单,可是上面的代码效率非常的差,多个Consumer有很大的几率拿到相同的文件,当某个Consumer尝试去解析一个文件时,却发现这个文件已经被别的Consumer解析过了,并且文件也都删除或者移走了。这样浪费的很多的CPU时间。
可以用下面的方案来替代:
方案二
public void run() {
System.out.println("Created consumer:" + threadName);
while (true) {
File file = new File(Constant.STAGING_FOLDER);
File files[] = file.listFiles();
int nCapacity = files.length > Constant.CAPACITY ? Constant.CAPACITY
: files.length;
System.out.println(this.threadName + " found " + nCapacity
+ " files");
for (int i = 0; i < nCapacity; ++i) {
File f = files[i];
f.renameTo(new File(Constant.TMP_FOLDER + "/" + f.getName()));
}
for (int i = 0; i < nCapacity; ++i) {
parse(Constant.TMP_FOLDER + "/" + files[i].getName());
}
Commons.sleep();
}
}
它和方案一的不同之处在于:它每次扫描完目录后,最多只取前若干个文件,这里是10个。并且,它不急于去处理文件,而是把文件马上移动到一个临时工作目录,其他的的操作都是相同的。
对于这个方案,有个附加条件:这个临时工作目录tmp,一定要和staging目录在同一个文件系统(filesystem),这样的话,mv操作就只是修改一下inode,几乎瞬间完成。
比较(Benchmarking)
为了测试两中方案的效率差别,我写了一个模拟程序(http://googlestop.com/download/SimConsumer.7z),它有7个class:
- App.java - 程序入口
- Commons.java - 共享的函数
- Constant.java – 配置参数
- Producer.java - 生产者,每隔一秒向目录staging里丢一个文件
- AbstractConsumer.java – 抽象消费者,定义消费者的一些基本属性和行为
- Consumer1.java - 具体消费者,实现方案一
- Consumer2.java - 具体消费者,实现方案二
在App.java中,你可以指定调用Consumer1还是Consumer2。
对于前者(Consumer1),staging目录下的文件数目不停的增长,并且如log显示,有很多冲突:一个Consumer准备处理的文件已经被其他的Consumer处理完了,造成了很多无效的操作,由于消费速度更不上生产速度,DIR1被撑爆只是时间的问题。
对于后者(Consumer2),staging目录下的文件几乎马上就会被移动到tmp目录下,大部分时间,文件数都为0。而tmp目录下,在程序稳定后大概保存在20多个文件左右,保持一个动态的平衡。用这种方式,你也会看到很多冲突,但是只会发生在程序刚开始,原因是,刚开始的时候,8个线程几乎是同时去访问staging目录,势必拿到很多相同的文件,待到稳定后,就很少有冲突发生了。
这两种方案都是最基本的,没有借助于第三方工具完成的,成本是最低的,其实还有一些其他的方案,可能会借助一些服务来实现,比如消息分发、数据库等。有时间的话,我继续补充。
OneNote Anyway with Windows Live Sync and Drop Box
如果你是个Microsoft OneNote的用户,并且可能会在多台电脑上记录笔记,那么一定会遇到如何同步这些笔记的问题,标题中的两个服务可以为我们解决这个问题。一个是Drop Box,官网为:www.dropbox.com ,这个网站在中国大陆目前无法访问(原因大概是中国政府不希望网民使用它来分享信息,任何有利于信息自由流动和传播的服务都难逃此运)。另外一个是Microsoft出品的Live Sync。
方法极其简单:在需要同步的两台电脑上,安装DropBox或者Live Sync,然后将OneNote的目录设置在需要同步的目录里面即可。
对于Drop Box,你需要在hosts文件中添加如下项目:
# 下面的IP不保证长期有效
174.36.30.67 dropbox.com
174.36.30.71 www.dropbox.com
75.101.129.115 dl.dropbox.com
75.101.159.151 dl-web.dropbox.com
174.36.30.67 forums.dropbox.com
对于Live Sync,你要注意的是,如果你的两个系统都是Windows 7或者Vista,建议你安装最新版本的Windows Live Sync,如果其中有一个是Windows XP,那么你只能选择针对XP的老版本的Live Sync。
我会继续介绍一些提高工作效率的方法,即使方法简单的如这篇文章一样,总会有人用的到。
关键字:One Note、同步、笔记、Sync
两个周末
上个周末,为了测试一下体力,跑了一个迷你马拉松,大概10多公里的路程,连跑带走,中间还看了一会模型飞机表演。
这个周末,代表公司参加了,2010软件工程技术、产业与人才培养论坛,论坛的名子起的很响亮,大概也就百十来人的规模
上图是来自CMU的John T Grasso(现已离开CMU,他在SEPG的推广上作出了很大的贡献),在做开篇演讲《Methodology in Software Engineering Education》期间还有一些来自IT界著名和非著名人士做了些专题报告。整个论坛类似于TED,但是比TED更有倾向性,就是软件工程、产业、教育等。
中午吃饭的时候,遇到个老先生,据他说是从美国回来,之前在Bell Labs,刚回国4个月,开了家公司,马上就搞定了3个单子,主要做的是视觉识别类的软件以及产业化,大概是用在Test Handler上的一些技术,据他说前途一片光明,佩服。
Mikado Spiel
傍晚去欧尚买盆栽植物,偶然在体育用品货架上发现个怪怪的盒子,里面装了很多小棍子,似乎听别人说过有种棍子游戏,我没有玩过,遂买回来玩玩。
详见说明:
http://de.wikipedia.org/wiki/Mikado_(Spiel)
http://baike.baidu.com/view/718078.htm
Email Lost In Outlook 2010 and Recovery Method
Several weeks ago, I upgraded my Outlook to Outlook 2010 Beta, and previously I wrote a macro to move all emails with my name in the recipient list to a local PST folder(folder: OnlyToMe) automatically. So there’s no backup in enterprise vault.
This morning, when I try to check email in my Outlook, there’s no email in this folder(OnlyToMe), but there’s a number indicating 4 new emails:
OnlyToMe(4)
This is the most important folder for me, the folder size is around 500M(for Y2010 only), below is how I recover it:
Sub Recover()
Set OutApp = CreateObject("Outlook.Application")
Set NmSpace = OutApp.GetNamespace("MAPI")
Set F = NmSpace.Folders("Default").Folders("OnlyToMe")
Set T = NmSpace.Folders("HR").Folders("Temp")
For intX = F.Items.Count To 1 Step -1
Set objMessage = F.Items.Item(intX)
objMessage.Move T
Next
Set OutApp = Nothing
Set NmSpace = Nothing
Set F = Nothing
Set T = Nothing
End Sub
Above VBA will move all mail items from the weird folder to a newly created folder. I believe I’m not the only one who got this problem, if you’re the lucky guy, try this method. Don’t forget to re-create a new PST, it’s likely something wrong with the PST.
Outlook 2010 is still a beta release, using it in a production environment is not a good practice. if you like the new features of 2010, you’d better backup your PST regularly.
Config PL/SQL Developer without installing Oracle client
- download instant client package http://download.oracle.com/otn/nt/instantclient/112010/instantclient-basic-win32-11.2.0.1.0.zip
- extract it to C:\Oracle\instantclient_11_2
- add C:\Oracle\instantclient_11_2 to %PATH%
- set %LD_LIBRARY_PATH%, %SQLPATH% and %TNS_ADMIN% as C:\Oracle\instantclient_11_2
- set OCI Library as “C:\Oracle\instantclient_11_2\oci.dll” in PL/SQL Developer (Tools->Preferences->Connection)
- done
I verified it on Windows 7, it works.



