Kudu 启动性能优化--slurp metadata file into memory
背景 Kudu 启动慢是长期以来饱受诟病的一个问题,部分数据量大的集群,单节点重启极端耗时需要 30 分钟以上,同时其部分参数并不能进行运行时调优,需要重启才能生效,这困扰着运维人员,影响升级和变更流程。 社区以及一些组织实现了一些优化方案,具体可以见 此文 tserver启动加速 一节,一些具体的 patch 包括: KUDU-2977 Sharding block map of LogBlockManager KUDU-3001 Multi-thread to load containers in a data directory 然而即使在一些高版本上,当前依然存在启动慢耗时长的问题,原因通常是:数据量大、资源限制导致的 metadata 的 compact 不及时等。 社区目前最佳的手段可能是使用 RocksDB 去存储底层的 metadata 数据,这是较新的方式,然而对于大量的存量环境,要将现有的 metadata 存储迁移到 RocksDB 上,成本较高;并且较新的特性不确定是否还有其他的问题,底层文件存储的问题可能导致数据问题,风险也较大。 近期,在探索 kudu 启动问题上,笔者注意到一个点是:在抓取 kudu 启动时间的过程中,发现 kudu tserver 启动中 sys time 较高。 结合之前探索过的 kudu 文件系统实现: [笔记] Kudu 存储引擎 | Kudu 文件系统 日期: 2024-10-23 标签: #big data #kudu Block 抽象接口 操作系统把磁盘抽象成文件,Kudu 则在文件之上再加了一层抽象——Block。在 Kudu 中,一列数据、一个 BloomFilter、一份主键索引,最终都变成一个或多个 Block 写入磁盘。Block 是 Kudu 存储引擎与本地文件系统之间的分界线:上层组件只需面对 Block 接口的 Append / Read,不必关心底层是一个独立文件(FileBlockManager)还是日志容器中的一段字节区间(LogBlockManager)。 这种隔离方式与 Unix 的设备抽象思路一致——Unix 内核用 struct file 加上 read/write 函数指针屏蔽底层设备差异;Kudu 用 Block 基类加上虚函数屏蔽底层文件系统的组织差异。 BlockId:Block 的身份标识 每个 Block 都有一个全局唯一的身份标识 BlockId(src/kudu/fs/block_id.h),本质上是一个 64 位无符号整数: 1 2 3 4 class BlockId { private: uint64_t id_; }; BlockId 可以序列化到 protobuf(CopyToPB / FromPB),也可以打印成 16 位十六进制字符串供调试。它是不透明的——上层代码不应假设 ID 的分配规则或数值含义,只需把它当作一把钥匙,用来在 BlockManager 中取回对应的数据。 Block 基类 Block 是所有 Block 的基类,接口极为简洁——只有一个方法: 1 2 3 4 5 class Block { public: virtual ~Block() = default; virtual const BlockId& id() const = 0; }; id() 返回该 Block 的 BlockId。这足以让上层代码通过 ID 引用任何 Block,而不必关心它是可读的还是可写的。Block 的两个子类——WritableBlock 和 ReadableBlock——分别定义了写路径和读路径的完整接口。 ...... 进一步详细分析发现,sys time 高的原因是在启动的过程中存在大量的 preadv syscall。 ...