最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Zookeeper事務日志預分配空間解讀

 更新時間:2023年04月04日 09:02:55   作者:恐龍弟旺仔  
這篇文章主要介紹了Zookeeper事務日志預分配空間解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

前言

Zookeeper的通過快照日志和事務日志將內存信息保存下來,記錄下來每次請求的具體信息。

尤其是其事務日志,每次處理事務請求時都需要將其記錄下來。

Zookeeper事務日志的默認存儲方式是磁盤文件,那么Zookeeper的總體性能就受限與磁盤文件的寫入速度。

針對這個瓶頸,Zookeeper做了什么優(yōu)化操作呢,本文我們就一起來了解下。

1.事務日志的預分配

事務日志的添加,我們需要從FileTxnLog.append()方法看起

public class FileTxnLog implements TxnLog {
? ? volatile BufferedOutputStream logStream = null;
? ? volatile OutputArchive oa;
? ? volatile FileOutputStream fos = null;
? ??
? ? // 追加事務日志
? ? public synchronized boolean append(TxnHeader hdr, Record txn)
? ? ? ? throws IOException
? ? {
? ? ? ? if (hdr == null) {
? ? ? ? ? ? return false;
? ? ? ? }
?
? ? ? ? if (hdr.getZxid() <= lastZxidSeen) {
? ? ? ? ? ? LOG.warn("Current zxid " + hdr.getZxid()
? ? ? ? ? ? ? ? ? ? + " is <= " + lastZxidSeen + " for "
? ? ? ? ? ? ? ? ? ? + hdr.getType());
? ? ? ? } else {
? ? ? ? ? ? lastZxidSeen = hdr.getZxid();
? ? ? ? }
?
? ? ? ? // 默認logStream為空
? ? ? ? if (logStream==null) {
? ? ? ? ? ?if(LOG.isInfoEnabled()){
? ? ? ? ? ? ? ? LOG.info("Creating new log file: " + Util.makeLogName(hdr.getZxid()));
? ? ? ? ? ?}
?
? ? ? ? ? ? // 以下代碼為創(chuàng)建事務日志文件
? ? ? ? ? ? // 根據(jù)當前事務ID來創(chuàng)建具體文件名,并寫入文件頭信息
? ? ? ? ? ?logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid()));
? ? ? ? ? ?fos = new FileOutputStream(logFileWrite);
? ? ? ? ? ?logStream=new BufferedOutputStream(fos);
? ? ? ? ? ?oa = BinaryOutputArchive.getArchive(logStream);
? ? ? ? ? ?FileHeader fhdr = new FileHeader(TXNLOG_MAGIC,VERSION, dbId);
? ? ? ? ? ?fhdr.serialize(oa, "fileheader");
? ? ? ? ? ?// Make sure that the magic number is written before padding.
? ? ? ? ? ?logStream.flush();
? ? ? ? ? ?filePadding.setCurrentSize(fos.getChannel().position());
? ? ? ? ? ?streamsToFlush.add(fos);
? ? ? ? }
? ? ? ? // 預分配代碼在這里
? ? ? ? filePadding.padFile(fos.getChannel());
? ? ? ? byte[] buf = Util.marshallTxnEntry(hdr, txn);
? ? ? ? if (buf == null || buf.length == 0) {
? ? ? ? ? ? throw new IOException("Faulty serialization for header " +
? ? ? ? ? ? ? ? ? ? "and txn");
? ? ? ? }
? ? ? ? Checksum crc = makeChecksumAlgorithm();
? ? ? ? crc.update(buf, 0, buf.length);
? ? ? ? oa.writeLong(crc.getValue(), "txnEntryCRC");
? ? ? ? Util.writeTxnBytes(oa, buf);
?
? ? ? ? return true;
? ? }
}

創(chuàng)建FileTxnLog對象時,其logStream屬性為null,所以當?shù)谝淮翁幚硎聞照埱髸r,會先根據(jù)當前事務ID來創(chuàng)建一個文件。

1.1 事務日志預分配

public class FilePadding {
? ? long padFile(FileChannel fileChannel) throws IOException {
? ? ? ? // 針對新文件而言,newFileSize=64M
? ? ? ? long newFileSize = calculateFileSizeWithPadding(fileChannel.position(), currentSize, preAllocSize);
? ? ? ? if (currentSize != newFileSize) {
? ? ? ? ? ? // 將文件擴充到64M,全部用0來填充
? ? ? ? ? ? fileChannel.write((ByteBuffer) fill.position(0), newFileSize - fill.remaining());
? ? ? ? ? ? currentSize = newFileSize;
? ? ? ? }
? ? ? ? return currentSize;
? ? }
? ??
? ? // size計算
? ? public static long calculateFileSizeWithPadding(long position, long fileSize, long preAllocSize) {
? ? ? ? // If preAllocSize is positive and we are within 4KB of the known end of the file calculate a new file size
? ? ? ? // 初始時候position=0,fileSize為0,preAllocSize為系統(tǒng)參數(shù)執(zhí)行,默認為64M
? ? ? ? if (preAllocSize > 0 && position + 4096 >= fileSize) {
? ? ? ? ? ? // If we have written more than we have previously preallocated we need to make sure the new
? ? ? ? ? ? // file size is larger than what we already have
? ? ? ? ? ? // Q:這里確實沒看懂...
? ? ? ? ? ? if (position > fileSize) {
? ? ? ? ? ? ? ? fileSize = position + preAllocSize;
? ? ? ? ? ? ? ? fileSize -= fileSize % preAllocSize;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? fileSize += preAllocSize;
? ? ? ? ? ? }
? ? ? ? }
?
? ? ? ? return fileSize;
? ? }
}

預分配的過程比較簡單,就是看下當前文件的剩余空間是否<4096,如果是,則擴容。

Q:

這里有一個不太明白的問題,position > fileSize的場景是怎樣的呢?

2.創(chuàng)建新的事務日志文件時機

通過上述代碼分析我們知道,當logStream=null時,就會創(chuàng)建一個新的事務日志文件,那么logStream對象什么時候為空呢?

搜索代碼,只看到FileTxnLog.rollLog()方法會主動將logStream設置為null

public class FileTxnLog implements TxnLog {
? ? public synchronized void rollLog() throws IOException {
? ? ? ? if (logStream != null) {
? ? ? ? ? ? this.logStream.flush();
? ? ? ? ? ? this.logStream = null;
? ? ? ? ? ? oa = null;
? ? ? ? }
? ? }
}

那么根據(jù)這個線索,我們來搜索下rollLog的調用鏈

SyncRequestProcessor.run() -> ZKDatabase.rollLog() -> FileTxnSnapLog.rollLog() -> FileTxnLog.rollLog()

最終看到是在SyncRequestProcessor.run()方法中發(fā)起調用的,而且只有這一條調用鏈,我們來分析下

2.1 SyncRequestProcessor.run()

public class SyncRequestProcessor extends ZooKeeperCriticalThread implements RequestProcessor {
?? ?public void run() {
? ? ? ? try {
? ? ? ? ? ? int logCount = 0;
?
? ? ? ? ? ? setRandRoll(r.nextInt(snapCount/2));
? ? ? ? ? ? while (true) {
? ? ? ? ? ? ? ? ...
? ? ? ? ? ? ? ? if (si != null) {
? ? ? ? ? ? ? ? ? ? // 追加事務日志
? ? ? ? ? ? ? ? ? ? if (zks.getZKDatabase().append(si)) {
? ? ? ? ? ? ? ? ? ? ? ? logCount++;
? ? ? ? ? ? ? ? ? ? ? ? if (logCount > (snapCount / 2 + randRoll)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? setRandRoll(r.nextInt(snapCount/2));
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 注意:在這里發(fā)起了rollLog
? ? ? ? ? ? ? ? ? ? ? ? ? ? zks.getZKDatabase().rollLog();
? ? ? ? ? ? ? ? ? ? ? ? ? ? ...
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? } else if (toFlush.isEmpty()) {
? ? ? ? ? ? ? ? ? ? ? ? ...
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? toFlush.add(si);
? ? ? ? ? ? ? ? ? ? if (toFlush.size() > 1000) {
? ? ? ? ? ? ? ? ? ? ? ? flush(toFlush);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } catch (Throwable t) {
? ? ? ? ? ? handleException(this.getName(), t);
? ? ? ? ? ? running = false;
? ? ? ? }
? ? ? ? LOG.info("SyncRequestProcessor exited!");
? ? }
}

需要注意下rollLog()方法執(zhí)行的條件,就是logCount > (snapCount / 2 + randRoll)

snapCount是一個系統(tǒng)參數(shù),System.getProperty("zookeeper.snapCount"),默認值為100000

randRoll是一個隨機值

那么該條件觸發(fā)的時機為:處理的事務請求數(shù)至少要大于50000。

這時就出現(xiàn)了一個筆者無法理解的情況:

通過對事務日志的觀察可以看到其都是64M,而至少處理50000次事務請求后,Zookeeper才會分配一個新的事務日志文件,那么這個snapCount是一個經驗值嘛?

如果事務請求的value信息都很大,那么可能到不了50000次,就會超過64M,理論上應該要創(chuàng)建一個新的文件了,但是貌似并沒有,這個該怎么處理呢?

如果事務請求value信息都很小,那么即使到了50000次,也不會超過64M,那么之前預分配的文件大小就浪費了一部分。

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Java實現(xiàn)的漢語拼音工具類完整實例

    Java實現(xiàn)的漢語拼音工具類完整實例

    這篇文章主要介紹了Java實現(xiàn)的漢語拼音工具類,結合完整實例形式分析了java基于pinyin4j包實現(xiàn)編碼轉換的相關操作技巧,需要的朋友可以參考下
    2017-11-11
  • Java8中Stream的一些神操作

    Java8中Stream的一些神操作

    Stream是Java8中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復雜的查找、過濾和映射數(shù)據(jù)等操作,這篇文章主要給大家介紹了Java8中Stream的一些神操作,需要的朋友可以參考下
    2021-11-11
  • JAVA  字符串加密、密碼加密實現(xiàn)方法

    JAVA 字符串加密、密碼加密實現(xiàn)方法

    這篇文章主要介紹了JAVA 字符串加密、密碼加密實現(xiàn)方法的相關資料,需要的朋友可以參考下
    2016-10-10
  • 詳解java的值傳遞、地址傳遞、引用傳遞

    詳解java的值傳遞、地址傳遞、引用傳遞

    這篇文章主要介紹了詳解java的值傳遞、地址傳遞、引用傳遞的相關資料,需要的朋友可以參考下
    2017-06-06
  • Java聊天室之使用Socket實現(xiàn)傳遞圖片

    Java聊天室之使用Socket實現(xiàn)傳遞圖片

    這篇文章主要為大家詳細介紹了Java簡易聊天室之使用Socket實現(xiàn)傳遞圖片功能,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以了解一下
    2022-10-10
  • java中BIO、NIO、AIO都有啥區(qū)別

    java中BIO、NIO、AIO都有啥區(qū)別

    這篇文章主要介紹了java中BIO、NIO、AIO都有啥區(qū)別,IO模型就是說用什么樣的通道進行數(shù)據(jù)的發(fā)送和接收,Java共支持3種網絡編程IO模式:BIO,NIO,AIO,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • JavaCV調用百度AI實現(xiàn)人臉檢測方法詳解

    JavaCV調用百度AI實現(xiàn)人臉檢測方法詳解

    在檢測人臉數(shù)量、位置、性別、口罩等場景時,可以考慮使用百度開放平臺提供的web接口,一個web請求就能完成檢測得到結果。本文就為大家介紹JavaCV如何調用百度AI實現(xiàn)最簡單的人臉檢測,需要的可以參考一下
    2022-01-01
  • SpringMVC中攔截器的實現(xiàn)

    SpringMVC中攔截器的實現(xiàn)

    SpringMVC 中的 Interceptor 攔截器是非常重要和相當有用的,它的主要作用是攔截指定的用戶請求,并進行相應的預處理與后處理,這篇文章主要介紹了SpringMVC的攔截器相關知識,需要的朋友可以參考下
    2022-01-01
  • Java的Spring框架中實現(xiàn)發(fā)送郵件功能的核心代碼示例

    Java的Spring框架中實現(xiàn)發(fā)送郵件功能的核心代碼示例

    這篇文章主要介紹了Java的Spring框架中實現(xiàn)發(fā)送郵件功能的核心代碼示例,包括發(fā)送帶附件的郵件功能的實現(xiàn),需要的朋友可以參考下
    2016-03-03
  • SpringBoot簡單實現(xiàn)定時器過程

    SpringBoot簡單實現(xiàn)定時器過程

    這篇文章主要介紹了SpringBoot簡單實現(xiàn)定時器過程,對于Java后端來說肯定實現(xiàn)定時功能肯定是使用到Spring封裝好的定時調度Scheduled
    2023-04-04

最新評論

丁青县| 辉南县| 常山县| 灵山县| 绵阳市| 许昌市| 灵寿县| 山东省| 右玉县| 江陵县| 灌南县| 六枝特区| 开平市| 鄂伦春自治旗| 达日县| 平乐县| 中卫市| 南开区| 柳林县| 尚志市| 文水县| 克什克腾旗| 东乌珠穆沁旗| 邛崃市| 丽江市| 乌兰察布市| 玉环县| 凤阳县| 柳河县| 林西县| 基隆市| 金秀| 佛坪县| 土默特右旗| 邯郸市| 斗六市| 定兴县| 仁寿县| 榆社县| 宜宾县| 鄂伦春自治旗|