登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
登录
注册
代码拉取完成,页面将自动刷新
开源项目
>
程序开发
>
网络开发包
&&
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
33
Star
121
Fork
108
openEuler
/
gazelle
代码
Issues
117
Pull Requests
22
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
【重构】RTW/RTC模式架构归一、高效的内存管理
已完成
#IB6PDF
任务
LemmyHuang
成员
创建于
2024-11-25 10:02
<!-- #请根据issue的类型在标题左侧下拉框中选择对应的选项(需求、缺陷或CVE等)--> <!-- #请根据issue相关的版本在里程碑中选择对应的节点,若是与版本无关,请选择“不关联里程碑”--> ### 一、重构收益 #### 1. 性能提升 redis 性能32K以下包长平均提升11-16%,32K以上包长平均提升1-3% netperf TCP性能持平 netperf UDP性能持平 #### 2. 解决了疑难问题:高并发下的内存不足 redis高并发基准测试 10000连接节省内存 50%(1200M -> 600M) redis高并发基准测试 20000连接节省内存 44%(1800M -> 1000M) #### 3. 提供可扩展能力:大包收发性能、xdp内核发送性能 使用per_thread缓存,而不是per_connection缓存。 将mbuf缓存与socket收发队列解耦开来,为支持 4K big buf 提供基础条件。 #### 4. 提供可扩展能力:读写零拷贝 使用per_thread缓存,而不是per_connection缓存。 将mbuf缓存与socket收发队列解耦开来,提供高效的内存池API给业务。 #### 5. 功能的完备性: 底层采用统一的事件通知、报文收发和内存池架构。 保证RTW RTC两种模式、TCP UDP两种协议,在各种包长下的 “功能可用性”和“性能一致性”。 #### 6. 代码的可维护性可测试性: 事件通知、报文收发和内存池封装了独立模块API,可独立进行单元测试。 ### 二、性能测试 #### 1. redis + 1822物理网卡  #### 2. redis + ipvlan XDP网卡  #### 3. netperf + TCP + 1822物理网卡  #### 4. netperf + UDP + 1822物理网卡  ### 三、高效的内存管理方案 #### 1. 现有内存策略(异步per_connection缓存)  mempool只在协议栈线程申请释放,将socket的收发队列作为缓存,解决内存池竞争和cachemiss问题。 缺点:随着连接数增加,内存消耗越大(2w连接 8G内存),容易触发OOM导致网络断流。 #### 2. 优化后异步内存策略(异步per_thread缓存)  收方向:将socket连接的收队列作为缓存,延迟到协议栈线程释放buf(消耗少量内存) 发方向:内存池支持将stack_cache迁移到thread_cache(内存消耗不随连接数增加,随线程数增加) 适用场景:占用内存较少,内存管理消耗在协议线程侧。适用物理网卡(大包效果更好)。 #### 3. 优化后同步内存策略(同步per_thread缓存)  收方向:直接批量释放内存到per_thread缓存 发方向:直接从per_thread缓存中申请内存 适用场景:占用内存极少,内存管理消耗在业务线程侧。适用XDP网卡、虚拟网卡(小包效果更好)。 #### 4. 三种socket收发队列 https://gitee.com/src-openeuler/lwip/tree/master_dev/src/include/arch/sys_arch.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/mbox_ring.h ```c # 收发队列的接口 struct mbox_ring_ops { int (*create)(struct mbox_ring *mr, const char *name, unsigned count); void (*destroy)(struct mbox_ring *mr); unsigned (*get_capacity)(const struct mbox_ring *mr); unsigned (*count)(const struct mbox_ring *mr); unsigned (*free_count)(const struct mbox_ring *mr); unsigned (*enqueue_burst)(struct mbox_ring *mr, void *const *obj_table, unsigned n); unsigned (*dequeue_burst)(struct mbox_ring *mr, void **obj_table, unsigned n); unsigned (*recv_count)(const struct mbox_ring *mr); unsigned (*recv_start_burst)(struct mbox_ring *mr, void **obj_table, unsigned n); void (*recv_finish_burst)(struct mbox_ring *mr); void *(*read_tail)(const struct mbox_ring *mr); void (*push_tail)(struct mbox_ring *mr, void *obj); void* (*pop_tail)(struct mbox_ring *mr, void *expect); }; ``` * single thread ring:单线程队列 (RTC模式) * multi thread ring:跨线程单生产者单消费者队列 (RTW模式+同步内存策略) * peek ring:跨线程单生产者出入队单消费者查看队列 (RTW模式+异步内存策略) #### 5. 内存池特性 https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/lstack_mempool.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/core/lstack_mempool.c * 支持per_thead_cache动态水线,随申请释放比例动态调整。 * 支持异步模式下,per_stack_cache迁移到per_thead_cache。 * 支持主内存池快OOM时,保留一部分内存,给网卡收包、ARP、ICMP等使用,避免OOM断流。 * 支持线程数量较多且内存池剩余不足时,降低per_thread_cache水线直至禁用per_thread_cache。避免内存分摊到cache中耗尽。 * 支持主内存池OOM时,通知各per_thread_cache刷回内存到主内存池。 * 支持线程退出之后,释放per_thread_cache。 ### 四、RTW/RTC模式架构归一 https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/lstack_sockio.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/api/lstack_sockio.c https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/api/lstack_epoll.c https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/lstack_wait.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/core/lstack_wait.c ```c // poll/epoll 在 RTW/RTC 模式下的事件接口 struct sock_wait { /* blocking and return 0 on timeout */ int (*timedwait_fn)(struct sock_wait *sk_wait, int timeout, uint32_t start); /* trigger event */ void (*notify_fn)(struct sock_wait *sk_wait, struct sock_event *sk_event, enum netconn_evt evt, int stack_id); /* remove event */ void (*remove_fn)(struct sock_wait *sk_wait, struct sock_event *sk_event, enum netconn_evt evt); ... }; ``` 主要问题: * RTC RTW 两种模式实现割裂,功能不复用 * RTW 实现侵入式修改lwip开源仓严重,gazelle与lwip函数之间互相依赖调用 * RTW UDP 不符合协议标准,不在IP层分片 * RTC UDP 功能不通 #### 1. TCP对比 * 当前 RTC + TCP ```c send lwip_send lwip_netconn_do_writemore tcp_output(+TSO) recv lwip_recvfrom lwip_recv_tcp netconn_recv_tcp_pbuf_flags ip4_input tcp_input recv_tcp sys_mbox_trypost ``` * 当前 RTW + TCP ```c send do_lwip_send_to_stack do_lwip_tcp_fill_sendring stack_tcp_send lwip_send lwip_netconn_do_writemore tcp_write_from_stack tcp_write_from_stack tcp_output(+TSO) recv do_lwip_read_from_stack recv_ring_tcp_read recv_ring_get_one ip4_input tcp_input recv_tcp sys_mbox_trypost do_lwip_read_recvlist lwip_recvfrom lwip_recv_tcp netconn_recv_tcp_pbuf_flags ``` * 重构后 RTC/RTW + tcp ```c send rtw_stack_tcp_write rtw_stack_tcp_append rtw_stack_tcp_write_one rtw_stack_tcp_write_bulk rtc_stack_tcp_write tcp_write rtw_stack_tcp_send/rtc_stack_tcp_send tcp_output recv stack_tcp_read ip4_input tcp_input recv_tcp ``` #### 2. UDP对比 * 当前 RTC + UDP ```c send lwip_send netconn_send udp_sendto_chksum recv lwip_recvfrom lwip_recvfrom_udp_raw netconn_recv_udp_raw_netbuf_flags netconn_recv_data sys_arch_mbox_fetch ip4_input udp_input recv_udp sys_mbox_trypost ``` * 当前 RTW + UDP ```c send do_lwip_send_to_stack do_lwip_udp_fill_sendring lwip_send lwip_netconn_do_send udp_sendto_chksum recv do_lwip_read_from_stack recv_ring_udp_read recv_ring_get_one ip4_input udp_input recv_udp sys_mbox_trypost do_lwip_read_recvlist lwip_recvfrom lwip_recvfrom_udp_raw netconn_recv_udp_raw_netbuf_flags ``` * 重构后 RTC/RTW + udp ```c send stack_udp_write stack_udp_output recv stack_udp_readmsg lwip_recvfrom_udp_raw ip4_input udp_input recv_udp ``` ### 五、其他具体优化点 * RTW 删除多余的recv_ring队列 * RTW send_ring批量出队 * RTW send发送通知的rpc_msg无需动态申请释放 * TCP TSO 无需合并包后再重新拆包,只在重传时拆包 * RTW epoll批量唤醒,减少持有spin_lock ### 六、bugfix * rpc_msg_pool每个线程一个,线程退出没有释放 * RTW send append功能,拼接报文死锁,改用原子操作实现 * RTW recv 释放内存之后再 update wnd(不符合协议标准) * udp 不应该复用tcp的append功能 (不符合协议标准) * udp ip层分片,而不是使用tcp的逻辑在 send 中分段 (不符合协议标准) * RTW redis 2w连接断流,用mbuf更少 * RTW tcp 没有限制发送内存使用量,超过send_buf应该不允许发送 ### 七、对外变更 * 删除参数 send_ring_size (与内存解耦之后,预留一个最大值256) * 删除参数 recv_ring_size (与内存解耦之后,预留一个最大值4096) * 删除参数 rpc_msg_max (不是每个线程一个rpc_msg_pool池,根据最大连接数预留) * 新增参数 mem_cache_size (per_thread缓存的大小) 默认32,允许16-1024 redis一个线程,建议设置较大值 1024 mysql一个连接一个线程,线程数量多且多是小包,建议设置较小值 16或32 * 新增参数 mem_async_mode (启用异步内存策略) 默认打开,XDP场景关闭 ### 八、其他场景性能测试 mysql 性能 TODO gaussdb 性能 TODO
<!-- #请根据issue的类型在标题左侧下拉框中选择对应的选项(需求、缺陷或CVE等)--> <!-- #请根据issue相关的版本在里程碑中选择对应的节点,若是与版本无关,请选择“不关联里程碑”--> ### 一、重构收益 #### 1. 性能提升 redis 性能32K以下包长平均提升11-16%,32K以上包长平均提升1-3% netperf TCP性能持平 netperf UDP性能持平 #### 2. 解决了疑难问题:高并发下的内存不足 redis高并发基准测试 10000连接节省内存 50%(1200M -> 600M) redis高并发基准测试 20000连接节省内存 44%(1800M -> 1000M) #### 3. 提供可扩展能力:大包收发性能、xdp内核发送性能 使用per_thread缓存,而不是per_connection缓存。 将mbuf缓存与socket收发队列解耦开来,为支持 4K big buf 提供基础条件。 #### 4. 提供可扩展能力:读写零拷贝 使用per_thread缓存,而不是per_connection缓存。 将mbuf缓存与socket收发队列解耦开来,提供高效的内存池API给业务。 #### 5. 功能的完备性: 底层采用统一的事件通知、报文收发和内存池架构。 保证RTW RTC两种模式、TCP UDP两种协议,在各种包长下的 “功能可用性”和“性能一致性”。 #### 6. 代码的可维护性可测试性: 事件通知、报文收发和内存池封装了独立模块API,可独立进行单元测试。 ### 二、性能测试 #### 1. redis + 1822物理网卡  #### 2. redis + ipvlan XDP网卡  #### 3. netperf + TCP + 1822物理网卡  #### 4. netperf + UDP + 1822物理网卡  ### 三、高效的内存管理方案 #### 1. 现有内存策略(异步per_connection缓存)  mempool只在协议栈线程申请释放,将socket的收发队列作为缓存,解决内存池竞争和cachemiss问题。 缺点:随着连接数增加,内存消耗越大(2w连接 8G内存),容易触发OOM导致网络断流。 #### 2. 优化后异步内存策略(异步per_thread缓存)  收方向:将socket连接的收队列作为缓存,延迟到协议栈线程释放buf(消耗少量内存) 发方向:内存池支持将stack_cache迁移到thread_cache(内存消耗不随连接数增加,随线程数增加) 适用场景:占用内存较少,内存管理消耗在协议线程侧。适用物理网卡(大包效果更好)。 #### 3. 优化后同步内存策略(同步per_thread缓存)  收方向:直接批量释放内存到per_thread缓存 发方向:直接从per_thread缓存中申请内存 适用场景:占用内存极少,内存管理消耗在业务线程侧。适用XDP网卡、虚拟网卡(小包效果更好)。 #### 4. 三种socket收发队列 https://gitee.com/src-openeuler/lwip/tree/master_dev/src/include/arch/sys_arch.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/mbox_ring.h ```c # 收发队列的接口 struct mbox_ring_ops { int (*create)(struct mbox_ring *mr, const char *name, unsigned count); void (*destroy)(struct mbox_ring *mr); unsigned (*get_capacity)(const struct mbox_ring *mr); unsigned (*count)(const struct mbox_ring *mr); unsigned (*free_count)(const struct mbox_ring *mr); unsigned (*enqueue_burst)(struct mbox_ring *mr, void *const *obj_table, unsigned n); unsigned (*dequeue_burst)(struct mbox_ring *mr, void **obj_table, unsigned n); unsigned (*recv_count)(const struct mbox_ring *mr); unsigned (*recv_start_burst)(struct mbox_ring *mr, void **obj_table, unsigned n); void (*recv_finish_burst)(struct mbox_ring *mr); void *(*read_tail)(const struct mbox_ring *mr); void (*push_tail)(struct mbox_ring *mr, void *obj); void* (*pop_tail)(struct mbox_ring *mr, void *expect); }; ``` * single thread ring:单线程队列 (RTC模式) * multi thread ring:跨线程单生产者单消费者队列 (RTW模式+同步内存策略) * peek ring:跨线程单生产者出入队单消费者查看队列 (RTW模式+异步内存策略) #### 5. 内存池特性 https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/lstack_mempool.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/core/lstack_mempool.c * 支持per_thead_cache动态水线,随申请释放比例动态调整。 * 支持异步模式下,per_stack_cache迁移到per_thead_cache。 * 支持主内存池快OOM时,保留一部分内存,给网卡收包、ARP、ICMP等使用,避免OOM断流。 * 支持线程数量较多且内存池剩余不足时,降低per_thread_cache水线直至禁用per_thread_cache。避免内存分摊到cache中耗尽。 * 支持主内存池OOM时,通知各per_thread_cache刷回内存到主内存池。 * 支持线程退出之后,释放per_thread_cache。 ### 四、RTW/RTC模式架构归一 https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/lstack_sockio.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/api/lstack_sockio.c https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/api/lstack_epoll.c https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/include/lstack_wait.h https://gitee.com/openeuler/gazelle/tree/master_dev/src/lstack/core/lstack_wait.c ```c // poll/epoll 在 RTW/RTC 模式下的事件接口 struct sock_wait { /* blocking and return 0 on timeout */ int (*timedwait_fn)(struct sock_wait *sk_wait, int timeout, uint32_t start); /* trigger event */ void (*notify_fn)(struct sock_wait *sk_wait, struct sock_event *sk_event, enum netconn_evt evt, int stack_id); /* remove event */ void (*remove_fn)(struct sock_wait *sk_wait, struct sock_event *sk_event, enum netconn_evt evt); ... }; ``` 主要问题: * RTC RTW 两种模式实现割裂,功能不复用 * RTW 实现侵入式修改lwip开源仓严重,gazelle与lwip函数之间互相依赖调用 * RTW UDP 不符合协议标准,不在IP层分片 * RTC UDP 功能不通 #### 1. TCP对比 * 当前 RTC + TCP ```c send lwip_send lwip_netconn_do_writemore tcp_output(+TSO) recv lwip_recvfrom lwip_recv_tcp netconn_recv_tcp_pbuf_flags ip4_input tcp_input recv_tcp sys_mbox_trypost ``` * 当前 RTW + TCP ```c send do_lwip_send_to_stack do_lwip_tcp_fill_sendring stack_tcp_send lwip_send lwip_netconn_do_writemore tcp_write_from_stack tcp_write_from_stack tcp_output(+TSO) recv do_lwip_read_from_stack recv_ring_tcp_read recv_ring_get_one ip4_input tcp_input recv_tcp sys_mbox_trypost do_lwip_read_recvlist lwip_recvfrom lwip_recv_tcp netconn_recv_tcp_pbuf_flags ``` * 重构后 RTC/RTW + tcp ```c send rtw_stack_tcp_write rtw_stack_tcp_append rtw_stack_tcp_write_one rtw_stack_tcp_write_bulk rtc_stack_tcp_write tcp_write rtw_stack_tcp_send/rtc_stack_tcp_send tcp_output recv stack_tcp_read ip4_input tcp_input recv_tcp ``` #### 2. UDP对比 * 当前 RTC + UDP ```c send lwip_send netconn_send udp_sendto_chksum recv lwip_recvfrom lwip_recvfrom_udp_raw netconn_recv_udp_raw_netbuf_flags netconn_recv_data sys_arch_mbox_fetch ip4_input udp_input recv_udp sys_mbox_trypost ``` * 当前 RTW + UDP ```c send do_lwip_send_to_stack do_lwip_udp_fill_sendring lwip_send lwip_netconn_do_send udp_sendto_chksum recv do_lwip_read_from_stack recv_ring_udp_read recv_ring_get_one ip4_input udp_input recv_udp sys_mbox_trypost do_lwip_read_recvlist lwip_recvfrom lwip_recvfrom_udp_raw netconn_recv_udp_raw_netbuf_flags ``` * 重构后 RTC/RTW + udp ```c send stack_udp_write stack_udp_output recv stack_udp_readmsg lwip_recvfrom_udp_raw ip4_input udp_input recv_udp ``` ### 五、其他具体优化点 * RTW 删除多余的recv_ring队列 * RTW send_ring批量出队 * RTW send发送通知的rpc_msg无需动态申请释放 * TCP TSO 无需合并包后再重新拆包,只在重传时拆包 * RTW epoll批量唤醒,减少持有spin_lock ### 六、bugfix * rpc_msg_pool每个线程一个,线程退出没有释放 * RTW send append功能,拼接报文死锁,改用原子操作实现 * RTW recv 释放内存之后再 update wnd(不符合协议标准) * udp 不应该复用tcp的append功能 (不符合协议标准) * udp ip层分片,而不是使用tcp的逻辑在 send 中分段 (不符合协议标准) * RTW redis 2w连接断流,用mbuf更少 * RTW tcp 没有限制发送内存使用量,超过send_buf应该不允许发送 ### 七、对外变更 * 删除参数 send_ring_size (与内存解耦之后,预留一个最大值256) * 删除参数 recv_ring_size (与内存解耦之后,预留一个最大值4096) * 删除参数 rpc_msg_max (不是每个线程一个rpc_msg_pool池,根据最大连接数预留) * 新增参数 mem_cache_size (per_thread缓存的大小) 默认32,允许16-1024 redis一个线程,建议设置较大值 1024 mysql一个连接一个线程,线程数量多且多是小包,建议设置较小值 16或32 * 新增参数 mem_async_mode (启用异步内存策略) 默认打开,XDP场景关闭 ### 八、其他场景性能测试 mysql 性能 TODO gaussdb 性能 TODO
评论 (
1
)
登录
后才可以发表评论
状态
已完成
待办的
进行中
已完成
已拒绝
负责人
未设置
LemmyHuang
LemmyHuang
负责人
协作者
+负责人
+协作者
标签
sig/sig-high-perform
未设置
项目
未立项任务
未立项任务
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (6)
标签 (5)
master
master_dev
ospp-2024
xdp
next
openEuler-22.03-LTS
1.0.0
1.0.3
1.0.2
1.0.1
v1.0.0
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
预计工期
(小时)
参与者(1)
1
https://gitee.com/openeuler/gazelle.git
git@gitee.com:openeuler/gazelle.git
openeuler
gazelle
gazelle
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册