0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RaftKeeper v2.1.0版本发布,性能大幅提升!

京东云 来源:jf_75140285 作者:jf_75140285 2024-07-15 15:10 次阅读

RaftKeeper 是一款高新能分布式共识服务,完全兼容 Zookeeper 但性能更出色,更多关于 RaftKeeer 参考Github,我们将 RaftKeeper 大规模应用到 ClickHouse 场景中,用于解决 ZooKeeper 的性能瓶颈问题,同时 RaftKeeper 也可以用于其它大数据组件比如 HBase。

v2.1.0 作为 v2.0.0 后的重要版本,引入了一系列新特性,包括异步创建 snapshot。该版本的最大亮点在于性能优化:写请求性能提升 11%,读写混合场景更是大幅提升了 118% 。本文将从工程细节的角度深入解析新版本的改进与优化。

一、性能优化效果

在性能测试中,我们使用了raftkeeper-bench工具,测试环境为三个节点组成的集群,每个节点配置为 16 核 CPU、32GB 内存和 100GB 存储空间。测试对象包括 RaftKeeper v2.1.0、RaftKeeper v2.0.4 和 ZooKeeper 3.7.1,均采用默认配置。

测试分为两组:

第一组测试纯 create 操作的性能,create 操作的 value 大小为 100 字节。结果显示,RaftKeeper v2.1.0 相较于 v2.0.4 性能提升了 11%,相较于 ZooKeeper 性能提升了 143%。

wKgZomaUy2WAdQS0AADauYIyalQ672.png

第二组请求比例为 create-1%、set-8%、get-45%、list-45%、delete-1%。其中,list 请求结果包含 100 个子节点,每个子节点大小为 50 字节;get、set、create 请求的节点 value 大小为 100 字节。结果显示,RaftKeeper v2.1.0 相较于 v2.0.4 性能提升了 118%,相较于 ZooKeeper 性能提升了 198%。

wKgaomaUy2aAZ-PhAADLBPDZjYg815.png

rk2.1.0 版本在测试中 avgRT 和 TP99 指标均优于 rk2.0.4,具体可以参考测试报告。

二、性能优化

接下来从工程细节的角度,介绍一些 v2.1.0 的优化点。

1. 响应并行序列化

RaftKeeper 被我们广泛应用到 ClickHouse 中,下图是一个规模较大的 RaftKeeper 集群的火焰图,通过火焰图发现 ResponseThread 线程消耗不少 CPU 时间片,其中大概三分之一时间片用于序列化响应。

wKgZomaUy2iAKXWzAAez_1JQguQ215.png

ResponseThread 负责序列化响应并且转发给 IO 线程,它是一个单线程,串行执行序列化会增大延迟。我们可以把响应的序列化交给 IO 线程来做,以并发的方式提高吞吐。

同时可以看到sdallocx_default函数占用了不少时间片,该函数是 jemelloc 释放内存的函数,函数对于时间片的消耗没有问题,但是该操作在基于 mutex 的同步队列中执行会增加锁的时间。

/// responses_queue是一个基于mutex的同步队列,在tryPop方法中释放response_for_session会增加lock的时间

复制代码

解决的方式是在 tryPop 方法前先释放 response_for_session 的内存空间。

下面的表格展示了优化前后的性能指标,测试共有四组每组使用不同的并发度,其中响应大小为 50bytes,当并发度为 10 的时候,TPS 增加 31%,AvgRT 降低 32%。

wKgaomaUy2iAalpvAABcXLmCMzc751.png

2. 优化 List 请求

依然是同一个 RaftKeeper 集群,通过火焰图发现,List 请求处理几乎消耗了 request-processor 线程所有的 CPU 时间片。在 RaftKeeper 的执行链路中 request-processor 负责处理用户的请求,它是一个单线程,所以比较容易成为瓶颈点。

通过火焰图可以发现两个瓶颈点:1.为字符串分配内存空间;2.插入 vector。

wKgZomaUy2mAejdPAAF_jyc-r0g487.png

List 请求返回的结果是一个 std::vector动态数组,其内存 layout 如下图所示,每个成员是一个字符串,每个字符串需要分配一块动态内存用于保存数据,所以当字符串多的时候需要大量的动态内存分配。

wKgaomaUy2mAQ3SKAAAc_lBtAbI960.png

一个很直观的优化思路,可以设计一个 compact strings,数据采用紧凑的方式存储,在以下的设计中,采用两个连续内存空间,一个用于存储数据,一个用于存储 offset,具体参考:CompactStrings实现。

wKgZomaUy2qAdJJlAAAe2TLPHis649.png

优化后从火焰图方面看 List 请求处理在 CPU 的占比从 5.46%下降到 3.37%,进行 List 请求的 benchmark 测试,TPS 从 45.8w/s 增长到 61.9w/s,同时 TP99 更低。

优化前:

复制代码

3. 优化无用的系统调用

系统调用会引起用户态和内核态的上下文切换,往往系统调用函数会有比较大的开销,我们通过 bpftrace 对 RaftKeeper 进行了 profile

BPFTRACE_MAX_PROBES=1024 bpftrace -p 4179376 -e ' 

复制代码

发现大量的getsockname和getsockopt系统调用占用了不少开销。

Execution count:

复制代码

这些系统调用本不该存在,经过排查发现是在打印日志的时候错误的进行了调用。

const auto socket_name = sock.isStream() ? sock.address().toString() : sock.peerAddress().toString();

复制代码

4. 线程池优化

下图是一次 benchmark(读写 4:6 的比例)RaftKeeper 的火焰图,进行性能瓶颈分析发现,发现 request-processor 线程的 CPU 时间片大部分时间(超过 60%)消耗在条件变量等待的调用。

wKgaomaUy2uAGQ88AALL6JbEvN0188.png

在 RaftKeeper 的主执行链路中 request-processor 线程负责处理用户请求,它的主要流程可以简单抽象为:1. 对于写请求,单线程处理;2. 对于读请求,通过线程池并发处理,然后调用 request_thread->wait()阻塞等待所有读取请求完成。

/// 1. process read-request by a thread pool

复制代码

增加监控指标分别统计读和写请求的执行时间发现,在读请求和写请求数量几乎相同的情况下,读请求的处理延时是写请求的 3 倍。

因为每个请求的处理时间很短,到这里可以推测出,线程池任务调度的时间不可忽视,所以出现了性能下降。解决方式是去掉线程池,单线程处理读请求,以下 benchmark 是优化前后 benchmark 结果,TPS 提升 13%。

优化前:

复制代码

三、Snapshot 优化

1. 异步 snapshot

在 RaftKeeper 整个请求处理链路中,创建 snapshot 是在主链路中进行处理的,当数据量大的时候会长时间阻塞用户请求,造成请求超时、leader 切换等引起服务不可用的问题,在我们线上场景中对于 6000w 的数据做 snapshot 需要 180s。

为了解决以上问题,新版本中支持了异步 snapshot,当需要创建 snapshot 的时候首先将整个 DataTree 拷贝一份,这一步在主线程中处理,然后在后台将拷贝的 DataTree 序列化到磁盘中。

wKgZomaUy2yARXWsAABfwEpzgW8379.png

采用这用方式 6000w 的数据做 snaphot 对用户的阻塞时间从 180s 降低到了 4.5s,但是这种方案也有一些负面效果,需要额外消耗大于 50%的内存。

为了进一步降低对用户的阻塞时间,对 DataTree 拷贝进行了进一步优化。DataTree 拷贝其实是一个计算密集型的任务,所以可以采用向量化的方式,同时会遍历 hashmap 可以适当进行 prefetch。

inline void memcopy(char * __restrict dst, const char * __restrict src, size_t n)

复制代码

上面的拷贝函数基于 SSE 指令集,优化后 DataTree 拷贝时间从 4.5s 降低到 3.5s。

2. Snapshot 加载速度优化

RaftKeeper 老版本中,启动服务之后 snapshot 加载速度比较慢,线上一个作为 ClickHouse metadata 存储的 Raftkeeper 有 6kw 的数据,在 NVMe 磁盘的服务器上加载 snapshot 需要 180s,导致服务启动速度很慢。

加载 snapshot 主要分两步,第一步读取磁盘上的数据,反序列化成节点;第二步遍历 DataTree 并构建父子关系,其中第一步是并行的,第二步是单线程的。

wKgaomaUy2yAOULmAAC8Yml_fZY584.png

由于第二步是单线程执行,可以改成并行的方式,并行化改造的基础是 DataTree 是一个二层 HashMap 结构,改造后每个线程负责固定的 bucket,这样避免了并发问题。具体流程为首先从磁盘读取数据并按照 bucket 的粒度存储节点和父子关系,然后填充 DataTree 并构建父子关系。

优化后加载 snapshot 时间从 180s 降低到 99s,之后又通过锁优化、snapshot 格式优化、减少数据拷贝等手段将时间降低到 22s。

四、上线效果

我们选取线上一个对 ZooKeeper 请求量大的 ClickHouse 集群,在 ClickHouse 测的监控指标看 QPS 大概为 17w/s,其中绝大部分为 List 请求。依次将其从 ZooKeeper 升级到 RaftKeeper v2.0.4 和 v2.1.0,观察监控指标

wKgZomaUy26AVk7ZAABqnh49Wz0186.png

wKgZomaUy26AJFCuAABak5klZPM516.png

可以看到 RaftKeeper v2.0.4 的表现不及 ZooKeeper(主要原因是该场景下绝大部分请求是 list,v2.0.4 对于 list 请求性能较差),但是 v2.1.0 有比较大幅的优势。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    8

    文章

    2885

    浏览量

    73433
  • 性能
    +关注

    关注

    0

    文章

    268

    浏览量

    18927
  • zookeeper
    +关注

    关注

    0

    文章

    33

    浏览量

    3646
收藏 人收藏

    评论

    相关推荐

    nonos sdk V2.1.0中使用混杂模式api,运行时崩溃了怎么解决?

    我正在努力在 nonos sdk V2.1.0 中使用混杂模式 api,并且我*有时*在注册回调后立即崩溃。从转储中可以看出,这似乎位于 sdk 的深处,并且它正在尝试找到 128 字节缓冲区中的一
    发表于 07-10 08:18

    Flint OS树莓派定制版正式发布0.3版本

    本帖最后由 carrieflint 于 2017-5-17 15:56 编辑 Flint OS树莓派定制版正式发布0.3版本!Flint OS for RPi是基于Chromium OS
    发表于 05-15 15:08

    DLC发布V5.0版本增加哪些测试要求

    次光效提升,平均提升10.8%,提升23%。  1.2相较于一版草稿,部分产品光效要求又做了提升,另外本次草稿
    发表于 02-24 17:32

    求STM8库函数中文使用手册要V2.1.0

    前辈们,谁有STM8库函数中文使用手册要V2.1.0
    发表于 03-26 14:21

    RT-Thread Studio for VS Code来了 精选资料分享

    来源 | RT-Thread转眼间RT-Thread Studio V2.1.0已经发布两个多月了,估计很多用户已经在翘首期待V2.1.1更新完善版本了,
    发表于 07-20 07:28

    STM32MP151C构建Custom Board“Eco system V2.1.0”发行版时存在不创建devicetree符号链接怎么解决?

    大家好基于STM32MP151C芯片构建Custom Board“Eco system V2.1.0”发行版时,存在不创建devicetree符号链接的问题。自定义板设备树的符号链接未在
    发表于 01-12 07:05

    串口ISP下载软件Flash Loader Demonstrator V2.1.0的免费下载

    串口ISP下载软件Flash_Loader_Demonstrator_V2.1.0:Cortex-M3串口对STM32烧写程序。
    发表于 11-24 11:41 87次下载
    串口ISP下载软件Flash Loader Demonstrator <b class='flag-5'>V2.1.0</b>的免费下载

    谈谈FreeRTOS_V 10版本

    谈谈FreeRTOS_V10版本
    的头像 发表于 03-12 14:01 5059次阅读

    Oculus Quest V18版本发布 大幅优化用户体验

    据外媒vrfocus报道,Oculus近期发布Oculus Quest V18版本,用户通过使用该版本将能体验一整套功能完善的全新功能。
    发表于 07-13 15:10 1520次阅读

    RT-Thread Studio V2.1.0发布,支持用户自制开发板支持包!

    不知不觉已经到了牛年的3月份,春天已经悄悄的来临,天气逐渐回暖,万物复苏,RT-Thread Studio V2.1.0版本终于可以“破土而出”和大家见面了。为了便于大家参与到Studi...
    发表于 12-16 16:52 9次下载
    RT-Thread Studio <b class='flag-5'>V2.1.0</b><b class='flag-5'>发布</b>,支持用户自制开发板支持包!

    大疆智图3.4.0版本更新 大幅提升用户体验

    4 月28日,大疆智图迎来 3.4.0 版本更新,新增多项功能:自定义三维重建分块、自定义三维模型坐标原点、二维可见光及多光谱重建的光照均匀与去雾模式。另外进行了多项功能优化,大幅提升用户体验。
    的头像 发表于 04-29 10:46 2598次阅读

    瑞萨灵活软件包 (FSP) v2.1.0 用户手册

    瑞萨灵活软件包 (FSP) v2.1.0 用户手册
    发表于 02-03 19:28 2次下载
    瑞萨灵活软件包 (FSP) <b class='flag-5'>v2.1.0</b> 用户手册

    瑞萨灵活软件包(FSP) v2.1.0 用户手册

    瑞萨灵活软件包 (FSP) v2.1.0 用户手册
    发表于 07-04 20:01 0次下载
    瑞萨灵活软件包(FSP) <b class='flag-5'>v2.1.0</b> 用户手册

    Embedded office发布安全插件V1.1版本

    Embedded office很高兴地宣布安全插件V1.1版本发布了!现在通过外部设备或不同核心架构的专门通道支持端到端受保护的安全通信。
    的头像 发表于 02-20 11:12 435次阅读

    ENV-Windows v2.0.0版本发布

    ENV-Windows v2.0.0版本发布
    的头像 发表于 06-26 08:35 319次阅读
    ENV-Windows <b class='flag-5'>v</b>2.0.0<b class='flag-5'>版本</b><b class='flag-5'>发布</b>