3.4 读写并发
在一个时刻只能够有一个线程修改索引库。Lucene通过锁文件控制并发访问。在Lucene 2.1版本以后,控制写入的锁文件write.lock默认存储在index路径。
如果出现多余的锁文件,则有可能会抛出Lock obtain timed out异常。如果确定没有线程在修改索引,可以手工删除write.lock文件。
例如,当全文索引放在只读光盘中时,需要设置这个索引只读。只读索引的初始化设置如下:
Directory indexDir = FSDirectory.getDirectory(indexPath, NoLockFactory.getNoLockFactory());
如果一台机器用来索引的同时也用来执行搜索,就不会预热reader,这样的后果会是灾难性的。当搜索的时候,用户会突然经历长时间的延时。因为一个大的合并能花费数小时,这样就意味着突然搜索性能变差达数小时。
因为Java没有暴露底层的API,例如文件咨询信息(posix_fadvise)、内存咨询信息和对齐控制(posix_madvise),所以要使用一个小的JNI扩展来改进性能。操作系统级别的功能应该能修复这个问题。
要仅仅在合并索引的时候完全忽略所有的操作系统缓存,可以通过使用Linux特定的O_DIRECT标志实现。合并索引的性能会变差,因为操作系统不再做预读也不写缓存,每个I/O请求都会接触到硬盘。但这可能是一个很好的折中。
有些类似的应用,例如视频解码,可能不需要缓存。因此创建了一个原型Directory实现,一个DirectNIOFSDirectory的变体。LUCENE-2056使用O_DIRECT打开所有的输入和输出文件,这是通过JNI实现的。因为所有的I/O都必须用某种规则对齐,所以实现代码有点乱。
由于按顺序读,Linux倾向于赶出已经加载的页面。
这个方法工作得很好。在执行索引优化时,搜索性能没有改变。
但是,优化阶段的时间从1336秒延长到了1680秒(慢了26%)。可以通过增加缓存来减少优化所需的时间,或者创建自己的预读/写缓存模式。