Apache BookKeeper中数据目录分析

Apache BookKeeper中数据目录分析

需要落盘的数据
  • Journals
  1. 这个journals文件里存储的相当于BookKeeper的事务log或者说是写前log, 在任何针对ledger的更新发生前,都会先将这个更新的描述信息持久化到这个journal文件中。
  2. Bookeeper提供有单独的sync线程根据当前journal文件的大小来作journal文件的rolling;
  • EntryLogFile
  1. 存储真正数据的文件,写入的时候Entry数据先缓存在内存buffer中,然后批量flush到EntryLogFile中;
  2. 默认情况下,所有ledger的数据都是聚合然后顺序写入到同一个EntryLog文件中,避免磁盘随机写;
  • Index文件
  1. 所有Ledger的entry数据都写入相同的EntryLog文件中,为了加速数据读取,会作 ledgerId + entryId 到文件offset的映射,这个映射会缓存在内存中,称为IndexCache;
  2. IndexCache容量达到上限时,会被 Sync线程flush到文件;
  • LastLogMark
  1. 从上面的的讲述可知, 写入的EntryLog和Index都是先缓存在内存中,再根据一定的条件周期性的flush到磁盘,这就造成了从内存到持久化到磁盘的时间间隔,如果在这间隔内BookKeeper进程崩溃,在重启后,我们需要根据journal文件内容来恢复,这个LastLogMark就记录了从journal中什么位置开始恢复;
  2. 它其实是存在内存中,当IndexCache被flush到磁盘后其值会被更新,其也会周期性持久化到磁盘文件,供BookKeeper进程启动时读取来从journal中恢复;
  3. LastLogMark一旦被持久化到磁盘,即意味着在其之前的Index和EntryLog都已经被持久化到了磁盘,那么journal在这个LastLogMark之前的数据都可以被清除了。
落盘数据目录设置优化
  • journal, entrylog, index最好设置在不同磁盘上,避免IO竞争;
  • journal 最好写在SSD等高速磁盘上。
数据写入后各种文件的更新流程
  • 流程图
data-flow1.png
文件目录使用情况监控
  • 用于写入文件的目录有三种状态:

    1. 可写;
    2. 可写,但剩余空间低于所配置的警告阈值;
    3. 不可写,已经写满; 当被GC清理了一部分数据后,其状态又可变为可写;
  • BookKeeper需要持续监控目录空间使用情况, 通过 LedgerDirsMonitor 类实现, 我们主要来分析一下它的 check 方法, 注释写在函数体内

    private void check(final LedgerDirsManager ldm) {
    // 对于Index, EntryLog, Journal都可以设置多个存储路径, 每一种对应一个LedgerDirsManager
    // 先获取每种对应的dirs的使用情况
        final ConcurrentMap<File, Float> diskUsages = ldm.getDiskUsages();
        try {
        //获取当前可写状态的目录
            List<File> writableDirs = ldm.getWritableLedgerDirs();
            // Check all writable dirs disk space usage.
            // 循环遍历当前可写状态的dirs的剩余可写容量,更新diskUsages
            // 同时处理各种异常,比如
            // 1. 读dir失败,回调diskFailed
            // 2. 可写容量低于警戒阈值,但还处于可写状态, 回调 diskAlmostFull
            // 3. 不可写,调用ldm.addToFilledDirs
            for (File dir : writableDirs) {
                try {
                    diskUsages.put(dir, diskChecker.checkDir(dir));
                } catch (DiskErrorException e) {
                    LOG.error("Ledger directory {} failed on disk checking : ", dir, e);
                    // Notify disk failure to all listeners
                    for (LedgerDirsListener listener : ldm.getListeners()) {
                        listener.diskFailed(dir);
                    }
                } catch (DiskWarnThresholdException e) {
                    diskUsages.compute(dir, (d, prevUsage) -> {
                        if (null == prevUsage || e.getUsage() != prevUsage) {
                            LOG.warn("Ledger directory {} is almost full : usage {}", dir, e.getUsage());
                        }
                        return e.getUsage();
                    });
                    for (LedgerDirsListener listener : ldm.getListeners()) {
                        listener.diskAlmostFull(dir);
                    }
                } catch (DiskOutOfSpaceException e) {
                    diskUsages.compute(dir, (d, prevUsage) -> {
                        if (null == prevUsage || e.getUsage() != prevUsage) {
                            LOG.error("Ledger directory {} is out-of-space : usage {}", dir, e.getUsage());
                        }
                        return e.getUsage();
                    });
                    // Notify disk full to all listeners
                    ldm.addToFilledDirs(dir);
                }
            }
            // Let's get NoWritableLedgerDirException without waiting for the next iteration
            // in case we are out of writable dirs
            // otherwise for the duration of {interval} we end up in the state where
            // bookie cannot get writable dir but considered to be writable
            // check完之前所有可写目录的最新状态后,
            // 看看现在还有没有可写的目录,没有可用的就抛出异常
            ldm.getWritableLedgerDirs();
        } catch (NoWritableLedgerDirException e) {
            LOG.warn("LedgerDirsMonitor check process: All ledger directories are non writable");
            boolean highPriorityWritesAllowed = true;
            try {
                // disk check can be frequent, so disable 'loggingNoWritable' to avoid log flooding.
                ldm.getDirsAboveUsableThresholdSize(minUsableSizeForHighPriorityWrites, false);
            } catch (NoWritableLedgerDirException e1) {
                highPriorityWritesAllowed = false;
            }
            
            //进到这里,表明没有可写的目录了,回调allDisksFull
            for (LedgerDirsListener listener : ldm.getListeners()) {
                listener.allDisksFull(highPriorityWritesAllowed);
            }
        }

        List<File> fullfilledDirs = new ArrayList<File>(ldm.getFullFilledLedgerDirs());
        boolean makeWritable = ldm.hasWritableLedgerDirs();

        // When bookie is in READONLY mode, i.e there are no writableLedgerDirs:
        // - Update fullfilledDirs disk usage.
        // - If the total disk usage is below DiskLowWaterMarkUsageThreshold
        // add fullfilledDirs back to writableLedgerDirs list if their usage is < conf.getDiskUsageThreshold.
        try {
            if (!makeWritable) {
                // 返回当前所有目录总的已用容量百分比
                float totalDiskUsage = diskChecker.getTotalDiskUsage(ldm.getAllLedgerDirs());
                if (totalDiskUsage < conf.getDiskLowWaterMarkUsageThreshold()) {
                    makeWritable = true;
                } else {
                    LOG.debug(
                        "Current TotalDiskUsage: {} is greater than LWMThreshold: {}."
                                + " So not adding any filledDir to WritableDirsList",
                        totalDiskUsage, conf.getDiskLowWaterMarkUsageThreshold());
                }
            }
            // Update all full-filled disk space usage
            // 之前处于不可写状态的目录,如果GC时清除掉一些数据,则可能变为可写状态,这里作check
            for (File dir : fullfilledDirs) {
                try {
                    diskUsages.put(dir, diskChecker.checkDir(dir));
                    if (makeWritable) {
                        ldm.addToWritableDirs(dir, true);
                    }
                } catch (DiskErrorException e) {
                    // Notify disk failure to all the listeners
                    for (LedgerDirsListener listener : ldm.getListeners()) {
                        listener.diskFailed(dir);
                    }
                } catch (DiskWarnThresholdException e) {
                    diskUsages.put(dir, e.getUsage());
                    // the full-filled dir become writable but still above the warn threshold
                    if (makeWritable) {
                        ldm.addToWritableDirs(dir, false);
                    }
                } catch (DiskOutOfSpaceException e) {
                    // the full-filled dir is still full-filled
                    diskUsages.put(dir, e.getUsage());
                }
            }
        } catch (IOException ioe) {
            LOG.error("Got IOException while monitoring Dirs", ioe);
            for (LedgerDirsListener listener : ldm.getListeners()) {
                listener.fatalError();
            }
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容