fqueue 是國內開發人員用JAVA開發的一款開源訊息佇列系統。訊息佇列可用來處理高並發量的資料庫讀寫操作,降低資料庫負載。fqueue的通訊層使用了netty架構,資料存放區則採用檔案隊列的方式。
儲存層主要的類有以下幾個:
FQueue:主要的隊列實現主類,所有的訊息儲存與讀取都通過此類進行
FSQueue:FQueue的底層實現,主要是在檔案隊列系統層面的讀寫與管理控制
LogEntity:針對單個資料存放區檔案的操作類
LogIndex:索引檔案控制類
整個儲存隊列關鍵的代碼及功能如下:
1. 有專門的讀和寫操作控制代碼負責對當前隱藏檔的操作。
//當前寫到的位置指標<br />private LogEntity writerHandle = null;<br />//當前讀到的位置指標<br />private LogEntity readerHandle = null;
writerHandle = createLogEntity(path + fileSeparator + filePrefix + "data_" + writerIndex + ".idb", db,<br />writerIndex);<br />if (readerIndex == writerIndex) {<br />readerHandle = writerHandle;<br />} else {<br />readerHandle = createLogEntity(path + fileSeparator + filePrefix + "data_" + readerIndex + ".idb", db,<br />readerIndex);</p><p>}
2.專門的索引管理
public class LogIndex {</p><p> /**<br /> * 記錄寫位置<br /> *<br /> * @param pos<br /> */<br /> public void putWriterPosition(int pos);</p><p> /**<br /> * 記錄讀取的位置<br /> *<br /> * @param pos<br /> */<br /> public void putReaderPosition(int pos);</p><p> /**<br /> * 記錄寫檔案索引<br /> *<br /> * @param index<br /> */<br /> public void putWriterIndex(int index);</p><p> /**<br /> * 記錄讀取檔案索引<br /> *<br /> * @param index<br /> */<br /> public void putReaderIndex(int index);</p><p> 3. 使用記憶體對應檔來處理隱藏檔,預設最大為150M,
private File file;<br />private RandomAccessFile raFile;<br />private FileChannel fc;<br />public MappedByteBuffer mappedByteBuffer;</p><p> raFile = new RandomAccessFile(file, "rwd");<br /> fc = raFile.getChannel();<br /> mappedByteBuffer = fc.map(MapMode.READ_WRITE, 0, this.fileLimitLength);</p><p>
public FSQueue(String path) throws Exception {<br />this(path, 1024 * 1024 * 150);<br />} 4.實際的資料存放區開始位置從20byte開始,前8byte為“FQueuefs”標識,接著4byte為版本,接著4byte為下一個檔案編號,再接著4byte 為當前儲存位置。
public class LogEntity {<br /> .....<br /> public static final String MAGIC = "FQueuefs";<br />public static int messageStartPosition = 20;</p><p> mappedByteBuffer.put(MAGIC.getBytes());<br /> mappedByteBuffer.putInt(version);// 8 version<br /> mappedByteBuffer.putInt(nextFile);// 12next fileindex<br /> mappedByteBuffer.putInt(endPosition);// 16<br />
基本的增刪流程如下:
新增FQueue.offer() ---> FSQueue.add() ----->LogEntity.write() ----[writeFull]--->產生下一個檔案ID,建立隱藏檔和索引rotateNextLogWriter() ---->LogEntity.write()
讀取FQueue.poll() ----> FSQueue.readNextAndRemove() ----->LogEntity.readNextAndRemove() ------[當前檔案已讀到了尾部]---> 擷取下一個檔案,將當前檔案加入刪除隊列FileRunner.addDeleteFile()---->再次讀取LogEntity.readNextAndRemove() 並更新索引位置。