当前位置: 首页 > news >正文

【kv存储】实时主从同步实现与eBPF旁路转发方案

一、背景

本文重点是实时数据的主从同步,以及使用eBPF做旁路转发的方案。

功能实现
仿照Redis实现的主从同步功能

Redis的主从同步分为两个阶段,第一个阶段:从机启动时,拉取主机的已有的数据,拉取完毕后从机正式上线。第二个阶段是从机上线后,主机实时将新的命令传播给从机,实现实时数据的变更。总结为:

  • 已有数据同步
  • 实时数据同步

    阶段一:已有数据同步
  1. 从机配置为slave,并且指定主机的IP和端口,从机启动时向主机发送SYNC指令
  2. 主机收到SYNC指令,将从机添加到从机列表当中后,打开积压缓冲区,触发BGSAVE全量保存数据到RDB文件中
  3. 主机将保存的RDB文件发送到从机
  4. 主机将积压缓冲区的数据发送到从机

阶段二:实时数据同步

  1. 主机收到来自客户端的新指令
  2. 主机解析RESP格式后后将变更类的指令(不包括GET等指令)重新编码,转发到从机

二、send网络转发实现

指令解析后,再变更类指令的分发分支上调用feed_slave

voidkvs_replication_feed_slaves(constchar*cmd,constchar*key,size_tklen,constchar*value,size_tvlen){if(g_repl.role!=KVS_ROLE_MASTER||g_repl.slave_count==0)return;charbuf[REPL_CMD_BUF];intlen=0,encoded=0;inthas_online=0,has_syncing=0;// 统计从库状态for(inti=0;i<g_repl.slave_count;i++){if(g_slaves[i].state==SLAVE_ONLINE)has_online=1;elsehas_syncing=1;}// 有同步中的从库 → 写 Backlogif(has_syncing){len=resp_encode_cmd(...);encoded=1;ensure_backlog();buffer_add(g_backlog,buf,len);// 满了则踢掉同步中的从库// ...}// 有在线从库 → 直接推送if(has_online){if(!encoded)len=resp_encode_cmd(...);for(inti=0;i<g_repl.slave_count;i++){if(g_slaves[i].state==SLAVE_ONLINE){reactor_append(...);// 失败则 drop_slave(i--);}}}}

待网络转发的数据填进reactor的wbuffer里,等待事件循环。

intreactor_append(intfd,constvoid*data,uint32_tlen){structconn*c=reactor_conn(fd);if(!c||!c->wbuffer||!data||len==0)return-1;if(buffer_add(c->wbuffer,data,len)!=0)return-1;set_event(fd,EPOLLIN|EPOLLOUT,0);return0;}

可以看到,这种方案面临着比较重的开销:

  • 整个过程中有两次编码
  • 若干次拷贝
  • 占用主机send的吞吐。

三、提出eBPF旁路转发的方案

eBPF 主从同步开启时,将hook点选择KV存储主机解析之后(RESP格式)的一个指定函数,此时hook函数的参数中已经获取了cmd、key、value以及klen、vlen等数据。

  1. 主机网络接收来自客户端的命令
  2. 解析完毕之后,拷贝到专门的hook函数(声明非内联,非优化,以便eBPF捕获)
  3. eBPF内核态程序捕获cmd,key,value等数据,抛入ringbuf(BPF map)中
  4. 用户态程序轮询获取ringbuf中的数据,并且编码
  5. send转发到从机

我们分析这条路径,不难发现,eBPF的思路是利用了旁路捕获并转发的思路,将编码、多次拷贝、send转发的开销旁路到了eBPF用户态进程中。KV存储中只需要维护一个类似这样的hook函数

__attribute__((noinline))voidkvs_eBPF_propagation_hook(constchar*cmd,constchar*key,size_tklen,constchar*value,size_tvlen){(void)cmd;(void)key;(void)klen;(void)value;(void)vlen;asmvolatile("");}

eBPF的实现比较复杂,涉及libbpf-bootstrap程序的改造,vertifier下编程容易踩的坑等,将来我写新的博客专门讲解。

http://www.cnnetsun.cn/news/4177284.html

相关文章:

  • 深入解析Kconfig语法:从核心元素到实战应用
  • C++模板与泛型编程:从STL容器到现代概念的核心机制解析
  • 蓝桥杯国赛递增序列题解:双指针算法与竞赛思维实战
  • 车载空间音频技术解析:从BOSE虚拟环绕声看沉浸式座舱体验
  • ozz-animation 骨骼动画深度指南:从资产导入到运行时播放的完整路径
  • OpCore-Simplify 使用指南:从硬件报告一键生成 OpenCore EFI
  • OpCore-Simplify:25 分钟从硬件报告到能开机的 OpenCore EFI
  • TrueForge开源智能体框架实测:本地部署、API调用与成本优化验证
  • Vial-QMK上手30分钟:改键位、加宏、把新固件烧进键盘
  • 数学建模竞赛全攻略:从组队到论文的实战经验与思维转变
  • 老Mac免费升级macOS:OpenCore Legacy Patcher完整指南
  • 10分钟生成OpenCore EFI:OpCore-Simplify快速上手指南
  • SerenityOS:从零造一个图形化 Unix 操作系统,能学到什么?
  • 免费全景查看器 Pannellum 完整指南:一张图片三步嵌入网页 360 全景
  • Glorious多用户与会话管理实战:一文看懂Linux登录界面全流程
  • 构建可验证与自进化的AI智能体:EVE-Agent架构设计与实践
  • 从零实现AI定制人像:LoRA微调实战,精准控制泪痣、发型等特征
  • PyNite DKMQ板单元揭秘:四边形板有限元公式推导详解
  • 多项式回归实战:从线性到非线性的建模进阶与避坑指南
  • meta-raspberrypi动态层设计哲学:5个可选layer只启用你需要的功能
  • 如何快速改造Angular Material滚动条:ngx-scrollbar集成Select/Dialog/Autocomplete完整指南
  • 企业招聘数据分析:从爬虫到可视化实战
  • canary金丝雀域名深度解析:用test.txt验证cache-domains缓存是否真正命中
  • Shardeum投票系统全解:去中心化治理与自动扩容投票指南
  • self-supervised-depth-completion数据管道全解析:KITTI数据集结构、相机标定与16位深度PNG读取
  • New API高可用背后的秘密:渠道重试与故障自动禁用机制深度解析
  • FreeRTOS运行一次后卡死
  • 如何给ScrollingStackViewController定制弹性动画:覆盖animate与scrollAnimate闭包的完整指南
  • 炉石HsMod插件:60+功能管换肤、战棋MMR和挂机,Windows 5分钟装好
  • Ditto核心原理(三):motion_stitch缝合网络如何让数字人自然眨眼与表情过渡