Posted on 2011-09-16 20:10
dennis 閱讀(9225)
評論(7) 編輯 收藏 所屬分類:
java 、
源碼解讀
fqueue是國產(chǎn)的一個類似memcacheq,kestrel這樣的支持memcached協(xié)議的輕量級開源MQ。它的項目主頁:
http://code.google.com/p/fqueue/downloads/list,介紹和特點都可以看主頁,我就不廢話了。
今天老大提到, co了源碼看了下,寫個初步分析報告。
首先是它的存儲層,主要是一個FQueue這么一個抽象隊列,內(nèi)部實現(xiàn)是FSQueue,也就是基于文件的FIFO隊列。這個隊列是多個文件組成的。每個文件默認大小在150M,超過即切換一個新文件來寫。讀的時候如果讀到尾部,則查找下一個文件進行讀取。數(shù)據(jù)文件名以idb為后綴,并且從編號1開始遞增,除了數(shù)據(jù)文件外,每個隊列還有個db為后綴的索引文件,記錄當前寫和讀的數(shù)據(jù)文件編號和偏移量。目錄結(jié)構(gòu)大概是這樣:
--fqueue
--fqueuedata_1.idb
--fqueuedata_2.idb
--……
--icqueue.db
文件的存儲比較有特色,采用
MappedByteBuffer做文件讀寫,
MappedByteBuffer是java nio引入的文件內(nèi)存映射方案,讀寫性能極高,但是也有一定的問題,比如說內(nèi)存占用,以及數(shù)據(jù)刷入設(shè)備的不確定性和關(guān)閉問題。在fqueue中,每隔10毫秒會強制force一次buffer,將修改過的數(shù)據(jù)刷入設(shè)備。對于關(guān)閉問題,則采用那個技巧,示例代碼:
/**
* 關(guān)閉索引文件
*/
public void close() {
try {
mappedByteBuffer.force();
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
Method getCleanerMethod = mappedByteBuffer.getClass().getMethod("cleaner", new Class[0]);
getCleanerMethod.setAccessible(true);
sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod.invoke(mappedByteBuffer,
new Object[0]);
cleaner.clean();
} catch (Exception e) {
log.error("close logindexy file error:", e);
}
return null;
}
});
fc.close();
dbRandFile.close();
mappedByteBuffer = null;
fc = null;
dbRandFile = null;
} catch (IOException e) {
log.error("close logindex file error:", e);
}
}
利用反射,并且使用了sun特有的類,不具有可移植性。MappedByteBuffer還有一個問題是map的代價比較高,可能在切換文件的時候fqueue會有一定程度的阻塞現(xiàn)象。
存儲的性能,我在我的機器測試了下,似乎沒有作者宣稱的那么高,我的機器是5400轉(zhuǎn)的普通SATA盤,寫入1K數(shù)據(jù)的平均QPS在8000左右。我估計fqueue的性能跟磁盤有很大關(guān)系,如果使用15000轉(zhuǎn)的SAS盤應(yīng)該能有很大改觀。
網(wǎng)絡(luò)層直接使用了jmemcached的實現(xiàn),
jmemcached是一個java實現(xiàn)的memcached,通常用于單元測試之類。看情況fqueue也支持memcached的二進制協(xié)議了。網(wǎng)絡(luò)框架使用了netty3,這些就不多說了。自己看都明白。額外提一下,作者做的單元測試使用了
xmemcached,咔咔,廣而告之。
總體來說fqueue是一個整體上很清爽和輕量級的MQ實現(xiàn),適合一些特定的場景,至于性能,我們下周準備做個壓測,到時候再談吧。