• Apache Pulsar 系列 —— 深入理解 Bookie GC 回收机制


    背景

    Apache Bookkeeper 是基于日志的一个持久化系统,所有的数据会以日志的形式存储到 Ledger 磁盘的 Entry Log 文件中,之后通过后台异步回收的形式来将 EntryLog 文件回收掉。但是在我们实际的使用场景中,发现很久之前的 EntryLog 文件无法被删除掉,对 Entry Log 文件存在的时间进行监控,具体如下:

    我们可以看到,假设从 Broker 侧设置的 Retention 策略最大为 5 天,即很久之前的 EntryLog 文件依然存在于对应的 Ledger 数据盘中,导致磁盘的占用率较高。虽然Bookie 的 GC 回收机制是后台异步回收的,当 Broker 侧认为某条消息可以删除时,Bookie 并不会立即从磁盘中将该数据删除掉,而是利用 Bookie 的 GC 线程周期性的触发回收的逻辑。但是数据的删除操作竟然滞后了半年多,于是萌生了搞懂 Bookie GC 回收机制的想法,究竟是什么原因导致了该现象的发生。

    Bookie GC 介绍

    在 Apache Bookkeeper 中,数据的写入,读取以及回收(压缩)操作是相互隔离的。为了避免过多碎片文件的产生,在 Bookies 中不同 Ledgers 中的 Entrys 会聚合存储到一个 EntryLog 文件中。Bookie 可以通过运行 GC 线程(GarbageCollectorThread)来删除未关联的 Entry 条目来达到回收磁盘空间的目的。在当前的 EntryLog 文件中,如果某一个 Ledger 中包含无法删除的 Entry,那么这个 EntryLog 文件将一直保留在数据盘(Ledger 盘)中无法被删除。由于业务场景的限定,我们没办法要求一个 EntryLog 文件中所有 Ledgers 的 Entries 都能在近乎相同的时间内满足可删除的条件。为了避免该现象,Bookie 引入了数据压缩的概念,即通过扫描 EntryLog 文件判定哪些 Entry 是可以删除的,可以删除的 Entry 继续保留在原始的 EntryLog 文件中,不可删除的 Entry 写入新的 EntryLog 文件中,扫描完成之后将原始的 EntryLog 文件删除掉。

    Bookie 压缩类型

    Bookie 的 GC 回收线程并不是一直执行的,而是基于特定的阈值,Bookie 按照一个 EntryLog 文件中有用数据的占比以及数据压缩被触发的时间将数据压缩的操作分为如下两种类型:

    Minor GC

    默认触发的时间为每 1 小时触发一次,可以通过 minorCompactionInterval 来自定义每一次 minor GC 触发的时间间隔。当到达 Minor GC 触发的时间阈值之后,会继续检查当前 EntryLog 中有用数据的占比是否超过默认配置的 20%。如果没有超过,则 Minor GC 生效,开始回收并压缩 EntryLog 中的数据。如果超过阈值,那么 Minor GC 不会被触发。可以通过 minorCompactionThreshold 来自定义 Minor GC 中有用数据的占比达到多少之后不会继续触发 Minor GC。为了避免 Minor GC 执行占用太多的时间,也可以通过 minorCompactionMaxTimeMillis 的参数来控制当前 Minor GC 最大允许执行的时间是多少。当 minorCompactionMaxTimeMillis <= 0 时,垃圾回收线程会一直执行直到扫描完成当前 Ledger 目录下所有的 Entry Log 文件。

    Major GC

    默认触发的时间为每 24 小时触发一次,可以通过 majorCompactionInterval 来自定义每一次 major GC 触发的时间间隔。当到达 Major GC 触发的时间阈值之后,会继续检查当前 EntryLog 中有用数据的占比是否超过默认配置的 80%。如果没有超过,则 Major GC 生效,开始回收并压缩 EntryLog 中的数据。如果超过阈值,那么 Major GC 不会被触发。可以通过 majorCompactionThreshold 来自定义 Major GC 中有用数据的占比达到多少之后不会继续触发 Major GC。为了避免 Minor GC 执行占用太多的时间,也可以通过 majorCompactionMaxTimeMillis 的参数来控制当前 Major GC 最大允许执行的时间是多少。当 majorCompactionMaxTimeMillis <= 0 时,垃圾回收线程会一直执行直到扫描完成当前 Ledger 目录下所有的 Entry Log 文件。

    注意: minorCompactionThreshold 和 majorCompactionThreshold 的最大值不可以超过 100%,当 minorGC 和 majorGC 同时配置时,MinorGC 的 minorCompactionInterval 和 minorCompactionThreshold 要求必须小于 MajorGC 中指定的阈值。

    为什么需要引入压缩有用占比阈值?

    当做数据压缩回收时,我们默认分别为 Minor GC 和 Major GC 引入了数据有用占比的阈值,这样做的目的是为了避免每次垃圾回收线程运行时,都会去频繁的扫描所有的 EntryLog 文件。当一个 EntryLog 文件中有用数据的占比超过 Major GC 指定的阈值,那么可以认为当前 EntryLog 中绝大部分数据仍然为有效的数据。这种情况下我们无需继续为了回收剩下的那一点无效数据,然后将该 EntryLog 中的数据从原始的 EntryLog 文件中再写入新的 EntryLog 文件中,这样可以大幅度的节省磁盘 I/O。

    Bookie 压缩方式

    当前,Bookie 提供了如下两种数据压缩的方式:

    按照 Entries 的数量

    默认情况下,Bookie 是通过 Entries 的数量进行压缩,默认值为 1000,即每次最大压缩 1000 条 Entry。可以通过 compactionRateByEntries 自定义每次压缩 Entries 的数量。

    按照 Entries 大小

    Bookie 按照 Entries 的大小进行压缩,可以通过 compactionRateByBytes 自定义每次回收最大允许被回收 Entries 的大小。当想要使用该压缩方式时,需要在 Bookie 的配置文件中同时打开如下配置:isThrottleByBytes=true。

    注意:生产环境中建议使用按照 Entries 大小压缩的方式,这个取决于 Entry 被打包的方式。对于 Pulsar 来说,普通消息和 Batch 消息都会被当作一条 Entry 来看待,这就可能会导致每一条 Entry 的大小都不一样。如果按照 Entries 的数量来回收,即每次回收的数据大小是不一致的,如果单个 Entry 过大,有可能导致回收期间占用较大的磁盘 IO,影响正常数据的读写IO,造成抖动的现象发生。

    Bookie GC 触发的方式

    当前 Bookie 的 GC 操作支持如下两种触发方式:

    自动触发

    Bookie 的 GC 回收线程按照 Bookie 压缩类型小节中介绍的方式,按照特定的时间间隔及阈值周期性的执行数据压缩回收的操作。

    手动触发

    Bookie 支持了 REST API 的 HTTP 服务,允许用户通过手动的方式触发 GC,使用方式如下:

    curl -X PUT http://127.0.0.1:8000/api/v1/bookie/gc

    • IP: 即为当前 Bookie 的 IP 地址

    • Port:示例中的 8000 端口为 Bookie 配置文件中 httpServerPort 指定的端口,默认为 8000。

    执行完成之后,也可以通过如下请求检查 GC 的状态等信息:

    curl http://127.0.0.1:8000/api/v1/bookie/gc_details

    Output:

    [ {
      
      "forceCompacting" : false,  
      "majorCompacting&#
  • 相关阅读:
    计算机开题报告怎么写?开题报告的几大模块!研究内容、研究方法、工作安排、预期目的
    m基于Matlab的fir和iir数字滤波器的设计与仿真
    YOLOv7改进之二十五:引入Swin Transformer
    MSQL系列(五) Mysql实战-索引最左侧匹配原则分析及实战
    【精品必知】Pod生命周期
    (三)DepthAI-python相关接口:OAK Nodes
    51单片机入门(一)
    STM32中的PWM
    Linux安装Apache(解压版)
    APP或小程序突然打开显示连接网络失败,内容一片空白的原因是,SSL证书到期啦,续签即可
  • 原文地址:https://blog.csdn.net/Q54665642ljf/article/details/126764543