首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >RocksDb手动合并文件导致数据库hang住

RocksDb手动合并文件导致数据库hang住

作者头像
老周聊架构
发布2025-11-20 10:15:47
发布2025-11-20 10:15:47
240
举报

一、背景

老周最近遇到一个生产问题,这个问题比较诡异。我先来说下背景,应用启动的时候,起了一个下载download线程,并且是守护线程,去离线拉取云端的数据到本地的RocksDb数据库进行存储,其中呢有个open方法,它是用来打开RocksDb数据库的,download线程下载数据的时候进程存库的时候会先去调用open方法打开数据库,然后再去执行put操作也就是保存数据的操作。问题来了,打开了数据库后都有日志,但唯独保存的时候没看到任何日志,也没有看到任何报错,这个download线程好像消失掉了。

二、问题排查

看了下唯一的日志 rocksDB compactRange failed, reason: 进程中断

我以为是RocksDb手动合并文件,由于文件太大,导致IO负载一直很高,进而导致进程中断,再触发钩子函数应用程序结束导致put操作没反应了,也进而解释了后续也没有日志了。

其实上面的分析是错的,下面认真分析了下才是对的:

第一次打开数据库的时候调open方法是ok,第二次put的时候由于手动合并文件导致数据库hang住了,一直put不进去,这也解释了为啥没有日志。那为啥会出现进程中断这种错误日志呢?是因为用户手动结束应用程序,触发了钩子函数,进而导致RocksDb手动合并文件进程中断结束的日志。整体流程也说得通了。

代码语言:javascript
复制
private RocksDB open() throws RocksDBException {

    if (rocksDB == null) {
        synchronized (lock) {
            if (rocksDB == null) {
                final int availableProcessors = Runtime.getRuntime().availableProcessors();
                final Options options = new Options();
                options.setCreateIfMissing(true);
                options.setIncreaseParallelism(availableProcessors);
                options.setMaxBackgroundFlushes(1);
                options.setMaxBackgroundCompactions(availableProcessors);
                options.setParanoidChecks(false);
                options.setWalRecoveryMode(WALRecoveryMode.SkipAnyCorruptedRecords);
                options.setKeepLogFileNum(5);
                options.setMaxLogFileSize(1024L * 1024);
                Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                    if (rocksDB != null) {
                        rocksDB.close();
                    }
                    options.close();
                }));

                String path = Environment.path() + PATH;
                rocksDB = TtlDB.open(options, path, SECONDS_OF_TTL, false);
                CompletableFuture.runAsync(() -> {
                    try {
                        rocksDB.compactRange();
                    } catch (RocksDBException e) {
                        logger.error("rocksDB compactRange failed, reason: ", e);
                    }
                });
            }
        }
    }

    return rocksDB;
}

三、问题解决

3.1 是否可以不进行手动合并?

大多数情况下:对于大多数应用来说,依赖 RocksDB 的自动合并机制已经足够。自动合并机制能够有效地管理数据库状态,确保性能和空间利用率。

特殊情况: 高负载场景:在高负载场景下,自动合并可能会增加系统负担。此时,可以通过手动合并来避免在关键时间段内进行合并操作。

特定优化需求: 如果有特定的优化需求,例如需要在某个时间窗口内进行数据整理,手动合并可以提供更精细的控制。 结合我们自身的业务,人员刚上的时候,系统负载不是那么高,交给RocksDB自动合并就行。

所以RocksDb手动合并文件得代码直接移除掉

代码语言:javascript
复制
CompletableFuture.runAsync(() -> {
    try {
        rocksDB.compactRange();
    } catch (RocksDBException e) {
        logger.error("rocksDB compactRange failed, reason: ", e);
    }
});

3.2 RocksDb参数设置的不合理

3.2.1 setKeepLogFileNum

含义

用于设置 RocksDB 保留的日志文件的最大数量。默认情况下,setKeepLogFileNum 的值为 1000。

问题

虽然 setKeepLogFileNum 主要影响日志文件的管理,但它间接影响文件合并的频率。如果日志文件被频繁删除,可能会导致更多的小文件积累,从而增加文件合并的频率。

影响

频繁的文件合并会增加 CPU 和磁盘 I/O 负载,从而影响整体性能。

3.2.2 setMaxLogFileSize

含义

setMaxLogFileSize 用于设置单个日志文件的最大大小。

默认情况下,setMaxLogFileSize 的值为 10485760 字节(即 10 MB)。

但看之前设置的参数setKeepLogFileNum只有5,setMaxLogFileSize只有1M。简单的说,RocksDb只有5个文件,每个文件只有1M,当合并的时候到达5个文件的时候就会根据底层设置的淘汰策略把旧的淘汰掉。5M的文件明显不够,就会导致手动合并的时候一直会合并,导致数据库hang住。所以我针对下面两个参数做了优化:

代码语言:javascript
复制
// 优化前
options.setKeepLogFileNum(5);
options.setMaxLogFileSize(1024L * 1024);

// 优化后
options.setKeepLogFileNum(500);
options.setMaxLogFileSize(10L * 1024 * 1024);

欢迎大家关注我的公众号【老周聊架构】,AI、大数据、云原生、物联网等相关领域的技术知识分享。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老周聊架构 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
  • 二、问题排查
  • 三、问题解决
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档