本文翻译自《Apache BookKeeper Observability — Part 4— Read USE Metrics》,作者 Jack Vanlightly,Apache BookKeeper Committer。
译者:程兴源
本文由 StreamNative 组织翻译并校对。
本系列基于为 Apache Pulsar 配置的 BookKeeper 4.14。
在本系列前两篇文章中,我们研究了如何诊断写入路径中的瓶颈。在本文中,我们将针对读取路径继续关注 USE 指标。在接下来的文章中,我们将详细介绍所有指标以及如何诊断读取缓存抖动(cache thrashing)。
建议先阅读 BookKeeper 内部原理第三部分,因为它描述了 DbLedgerStorge 组件的内部工作原理。
时间利用率
时间利用率用于计算每秒花在做某事上的时间。因此,如果一个线程每秒花费 500 毫秒进行工作,那么它的利用率为 50%。我们可以测量不同地方的时间利用率,以发现是否存在瓶颈。
读取线程
读取完全在读取线程内执行,每个读取线程同步和串行执行每个读取。由此,时间利用率很有助于我们了解读取行为(并且比写入线程简单得多)。一旦线程达到 100% 的时间利用率,它就不太可能承担更多的工作并达到其最大读取吞吐能力。
图 1. 读取线程池执行请求的时间消耗
sum(irate(bookkeeper_server_BookieReadThreadPool_task_execution_sum[1m])) by (pod)
这个 Grafana 面板来自一个 bookie,它有 8 个读取线程(默认),其读取负载正不断增加,直到达到其读取容量。我们看到它达到了每秒消耗 8s 的时间,这意味着所有线程的利用率为 100%。这种衡量利用率方法的不便之处在于必须知道线程数,否则秒数没有意义。
注意:对于这些任务执行指标,你必须将 enableTaskExecutionStats 设置为 true。
DbLedgerStorage
BookKeeper 中所有文件 IO 都是同步的,并且对于每个读取线程也是串行的。借助具有总和指标的读取延迟指标,我们可以测量读取线程在 DbLedgerStorage 中花费的时间。
图 2. DbLedgerStorage 读取中的时间消耗
sum(irate(bookie_read_entry_sum[1m])) by (pod)
在本示例中,我们看到在 DbLedgerStorage 中花费的时间几乎完全匹配所有读取线程作为一个整体所花费的时间。但可能并非总是如此,因为当网络成为瓶颈时,将响应发送回客户端会花费大量时间。在这些情况下,在 DbLedgerStorage 中花费的时间将低于在读取线程中花费的时间。
饱和度
读取路径的饱和度主要取决于读取线程池任务队列的大小。如果 DbLedgerStorage 无法足够快地执行读取,则读取线程池任务队列会开始堆积,直至达到容量。
图 3. 读取线程任务队列长度和请求队列时间
任务队列长度(对于池中每个线程的重复请求): sum(bookkeeper_server_BookieReadThreadPool_queue_0) by (pod)
P99 请求队列时长: sum(bookkeeper_server_BookieReadThreadPool_task_queued{success=”true”, quantile=”0.99"}) by (pod)
在本示例中,我们看到各线程的队列越来越长,与读取线程的利用率相对应。请求在这些队列中花费的时间最终会急剧增加。
读取线程任务队列长度指标的不足之处在于线程序号是指标名称的一部分,这可能会使创建仪表盘变得更加复杂。同样,线程池队列时间是跨所有线程的时间总和,因此我们无法深入查看某个线程是否已经到达饱和状态。
总结
在调查读取性能问题时,这些利用率和饱和度指标应该是首先检查的内容之一。在我们的简单示例中,这些指标显示的值与读取路径过载时一样高。
如果读取的利用率和饱和度较高,建议尽快找出问题原因。它可能只是负载供应不足,也可能是读取缓存抖动(该情况较少见)。当然,诸如 CPU、内存、磁盘利用率/饱和度等系统指标超出了本系列的范围,但对于诊断性能问题也非常重要。
在本系列下一篇文章中,我们将查看所有可用的 DbLedgerStorage 读取指标以及指标盲点,并解释如何检测缓存抖动或将其排除为读取性能问题的原因。