全用户态网络开发套件 F-Stack 架构分析

F-Stack是一个全用户态(kernel bypass)的高性能的网络接入开发包,基于DPDK、FreeBSD协议栈、微线程接口等,适用于各种需要网络接入的业务,用户只需要关注业务逻辑,简单的接入F-Stack即可实现高性能的网络服务器。

本文介绍F-Stack的详细架构及如何解决了内核协议栈面临的问题。

传统内核协议栈的性能瓶颈

在传统的内核协议栈中,网络包处理存在诸多瓶颈,严重影响网络包的收发性能。性能瓶颈主要包括以下几个方面

  1. 局部性失效 - 一个数据包的处理可能跨多个CPU核心、缓存失效、NUMA不友好 一个数据包可能中断在cpu0,内核态处理在cpu1,用户态处理在cpu2, 这样跨越多个核心,造成局部性失效,CPU缓存失效, 同时可能存在跨NUMA访问内存,性能受到很大影响。
  2. 中断处理 - 硬件中断、软中断、上下文切换 当网络中数据量很大时,大量的数据包产生频繁的硬件中断请求, 这些硬件中断可以打断之前较低优先级的软中断或者系统调用的执行过程, 如果这种打断频繁进行的话,将产生较高的性能开销。 用户态内核态的上下文切换和软中断都增加了额外的开销。
  3. 内存拷贝 - 内核态和用户态之间的内存拷贝 网络数据包从网卡到应用程序需要经过如下的过程: 数据从网卡通过DMA等方式传到内核开辟的缓冲区;数据从内核空间复制到用户态空间。在Linux内核协议栈中,这个耗时甚至占到了数据包整个处理流程的一半。
  4. 系统调用 - 软中断、上下文切换、锁竞争频繁到达的硬件中断或者软中断都可能随时抢占系统调用的运行,这也将产生大量的上下文切换开销。 内核中一些资源如PCB表等都需要加锁处理,大量的并发操作造成很大的性能浪费,特别是大量短连接的创建。

F-Stack总体架构

无共享架构

F-Stack使用了多进程的无共享架构,每个进程CPU、网卡队列绑定,具有无竞争、零拷贝、线性扩展、NUMA友好等特点。

  • 各进程绑定独立的网卡队列和CPU,每个NUMA节点使用独立的内存池,请求通过设置网卡RSS散落到各进程进行处理,解决了局部性失效的问题。
  • 使用DPDK的轮询模式,排除中断处理造成的性能影响。
  • 使用DPDK作为网络I/O模块,将数据包从网卡直接接收到用户态,减少内核态到用户态的内存拷贝。
  • 请求平均分配到每个核上,通过设置DPDK的rss hash函数保证相同ip、port的请求落到同一个核上。
  • 各进程拥有独立的协议栈、PCB表等资源,消除了协议处理过程中的各种资源竞争。
  • 进程之间不共享内存,通过无锁环形队列(rte_ring)传递通信,如ARP包等。

用户态协议栈

移植FreeBSD协议栈至用户态。

通过外加头文件、宏控制、以及hook相关实现进行的移植,对FreeBSD源代码的修改不到100行,对后续的跟进社区,升级版本非常友好。

  • 内存分配相关函数重新hook实现。(当前使用mmap和malloc,后续会替换成rte_mempool和rte_malloc)
  • 定时器使用rte_timer驱动,ticks定时更新,timecounter定时执行。
  • 移除内核线程、中断线程等,统一进行轮询处理。
  • 移除文件系统相关的绑定。
  • 移除FreeBSD内核中的所有锁,用空的宏替换掉。
  • 其他glue code。

类posix接口和微线程框架

提供了类posix接口和微线程框架,方便现有应用接入,替换接口。

后续我们会提供类似LD_PRELOAD的方式,使得现有程序尽量无改动迁移到F-Stack。

微线程框架,移植自腾讯开源的毫秒服务MSEC里使用的spp_rpc

具有同步编程、异步执行的特点,无需处理复杂的异步逻辑。

问题及优化

  • CPU 100% 由于使用的DPDK轮询模式,cpu使用率会一直是100%, 后续会引入DPDK的轮询+中断模式,当连续几次轮询没有收到包后, 转为中断模式,有包后持续轮询,直到又没包进来。
  • 常规网络工具(如tcpdump、ifconfig、netstat等)无法使用 由于DPDK接管了网卡,所有的数据包都运行在用户态,常规的网络工具都无法使用, 为此我们对一些工具进行了移植,目前已经完成了sysctl、ifconfig。 抓包可以在config.ini里配置开启,抓包文件也可以在wireshark里直接分析。
  • Nginx reload 当前F-Stack的Nginx是运行在NGX_PROCESS_SINGLE模式下的, 各个进程互不关联,无法使用原有的reload命令。后续会进行修复。

最佳实践

  • 使用性能高的多核CPU,配置config.ini里的lcore_mask(进程运行在哪些cpu上)运行多个进程。
  • 使用10G、25G、40G的多队列网卡,支持硬件卸载功能,支持的RSS队列数越多越好。
  • 配置尽可能多的Hugepage。
  • 配置config.ini关闭抓包。

Roadmap

  • 继续移植各种网络配置工具,方便F-Stack在各种网络环境(如GIF/GRE/VxLAN等隧道)下的部署使用。
  • 移植SPDK的用户态驱动至F-Stack,提升磁盘I/O性能。
  • 增加对数据流的HOOK点/镜像等,方便对数据包进行自定义处理。
  • 提供协议栈的相关优化模块,如TCP加速、防护等。
  • 类posix接口提供LD_RRELOAD方式,简化已有应用的接入方式。
  • 提供PHP/Python等语言的接口封装,方便相关WEB服务的快速接入。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

万字长文带你OpenStack从入门到放弃

1514
来自专栏汪伟的专栏

性能优化的正确方向

性能优化并不是一个孤立的课题,除了响应时间的考虑,我们往往还需要综合功能完整性、安全性等等方面的问题。

6530
来自专栏架构之美

五分钟学会分布式事务

1222
来自专栏Java Edge

Kafka架构解析1之背景及架构介绍简介为何使用消息系统常用Message Queue对比Kafka架构拓扑结构Producer消息路由

3195
来自专栏无题

读曾宪杰《大型网站系统与Java中间件实践》

十年,一个时代过去 1.分布式系统相对集中式而言,是指多台计算机互相通过消息通信进行协作而对外提供服务;可解决大型机的伸缩性和单点等问题; 2.网络i/o有b...

2945
来自专栏后端技术探索

大型网站架构系列:消息队列

消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件...

651
来自专栏杨建荣的学习笔记

Datapump数据迁移前的准备工作(r9笔记第31天)

其实对于Datapump迁移而言,如果参与过XTTS,OGG,Veritas SF,外部表增量等迁移方式的话,会发现Datapump还是很简单清晰的,一个优点...

2573
来自专栏北京马哥教育

超清晰的 DNS 原理入门指南

来源:阮一峰的网络日志 作者:阮一峰 链接:http://www.ruanyifeng.com/blog/2016/06/dns.html DNS 是互联网核...

3176
来自专栏IT技术精选文摘

LVS集群中的IP负载均衡技术

1.前言 在已有的IP负载均衡技术中,主要有通过网络地址转换(Network Address Translation)将一组服务器构成一个高性能的、高可用的虚拟...

2867
来自专栏IT技术精选文摘

负载均衡详解

面对大量用户访问、高并发请求,海量数据,可以使用高性能的服务器、大型数据库,存储设备,高性能Web服务器,采用高效率的编程语言比如(Go,Scala)等,当单机...

2477

扫码关注云+社区