轉至http://blog.csdn.net/duck_genuine/article/details/8006134html
FileSwitchDirectory實現原理與應用 java
FileSwitchDirectory是lucene的另外一種Directory實現類,從名字個就能夠理解爲文件切換的Directory實現,web
的確是針對lucene的不一樣的索引文件使用不一樣的Directory .藉助FileSwitchDirectory整合不一樣的Directory實現類的優勢於一身。緩存
好比MMapDirectory,藉助內存映射文件方式提升性能,但又要減小內存切換的可能 ,當索引太大的時候,內存映射也須要不斷地切換,這樣優勢也可能變缺點,而以前的NIOFSDirectory實現java NIO的方式提升高併發性能,但又因高併發也會致使IO過多的影響,因此此次能夠藉助FileSwitchDirectory發揮他們兩的優勢。併發
MMapDirectory與NIOFSDirectory的實現差異。app
NIOFSDirectory----只是使用了直接內存讀取文件緩存方式 ide
@Override
protected void newBuffer(byte[] newBuffer) {
super.newBuffer(newBuffer);
byteBuf = ByteBuffer.wrap(newBuffer);
}高併發
MMapDirectory------使用MMap技術映射文件,默認會映射1G的內存(64位)或者256m(32位系統))oop
MMapDiretory就是將文件映射到內存中。。使用的是MMap技術
this.buffers[bufNr] = rafc.map(MapMode.READ_ONLY, bufferStart, bufSize);性能
首先將索引目錄裏佔比例比較小的文件使用MMapDirectory,這樣幾乎能夠所有映射到內存裏了。。而佔有大比例的文檔存儲文件交因爲NIOFSDirectory方式讀取。
這個結合不錯呀。。
FileSwitchDirectory實現代碼解析
FileSwitchDirectory的代碼很簡單,由於能夠理解爲它就是一個Dao的入口也是個控制器,因此它並無具體的文件操縱實現。
先了解它的構造是:
- public FileSwitchDirectory(Set<String> primaryExtensions, Directory primaryDir, Directory secondaryDir, boolean doClose) {
- this.primaryExtensions = primaryExtensions;
- this.primaryDir = primaryDir;
- this.secondaryDir = secondaryDir;
- this.doClose = doClose;
- this.lockFactory = primaryDir.getLockFactory();
- }
首先是文件後綴的集合參數
主要的Directory
次要的Directory
是否關閉的時候調用
因此都是調用對應的Directory得到IndexInput 與IndexOuput
- @Override
- public IndexInput openInput(String name) throws IOException {
- return getDirectory(name).openInput(name);
- }
- @Override
- public IndexOutput createOutput(String name) throws IOException {
- return getDirectory(name).createOutput(name);
- }
經過文件名字取到對應的Directory
- private Directory getDirectory(String name) {
- String ext = getExtension(name);
- if (primaryExtensions.contains(ext)) {
- return primaryDir;
- } else {
- return secondaryDir;
- }
- }
solr使用的DirectoryFactory實現
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class MMapDirectoryFactoryExt extends DirectoryFactory {
-
- private Set<String> nonMappedFiles = new HashSet<String>();
-
- private Boolean useUnmapHack = false;
-
- public Directory open(String path) throws IOException {
- MMapDirectory mmapDir = new MMapDirectory(new File(path));
- mmapDir.setUseUnmap(useUnmapHack);
- return new FileSwitchDirectory(nonMappedFiles, mmapDir, FSDirectory.open(new File(path)), true);
- }
-
- public void init(NamedList args) {
- Object unmap, namedlist;
- nonMappedFiles = new HashSet<String>();
- if ((unmap = args.get("unmap")) instanceof Boolean)
- useUnmapHack = (Boolean) unmap;
- if ((namedlist = args.get("filetypes")) instanceof NamedList) {
- NamedList filetypes = (NamedList) namedlist;
- for (String type : IndexFileNames.INDEX_EXTENSIONS) {
- Object mapped = filetypes.get(type);
- if (Boolean.FALSE.equals(mapped))
- nonMappedFiles.add(type);
- }
- }
- }
- }
solrconfig.xml上的配置,使用於新的DirectoryFactory
- <directoryFactory class="solr.MMapDirectoryFactory">
- <str name="unmap">true</str>
- <lst name="filetypes">
- <bool name="fdt">false</bool>
- <bool name="tii">false</bool>
- </lst>
- </directoryFactory>
線上的索引文件大小:
7.3G ./_y8b.fdt
201M ./_y8b.fdx
4.0K ./_y8b.fnm
1.8G ./_y8b.frq
76M ./_y8b.nrm
537M ./_y8b.prx
7.1M ./_y8b.tii
571M ./_y8b.tis
4.0K ./segments.gen
4.0K ./segments_1p
因爲tii文件會加載到內存,因此這個不需要映射,fdt文件太大,主要是正向存儲的數據,可使用NiOFSDirectory方式
還有一個文件frq文件好大,這個也是須要考慮的。
- public final void setMaxChunkSize(final int maxChunkSize) {
- if (maxChunkSize <= 0)
- throw new IllegalArgumentException("Maximum chunk size for mmap must be >0");
-
- this.chunkSizePower = 31 - Integer.numberOfLeadingZeros(maxChunkSize);
- assert this.chunkSizePower >= 0 && this.chunkSizePower <= 30;
-
- }
從上面的代碼能夠看出,最大也只能是1G大小。。。杯具。。