前半部分,对于背景和需求的分析,写的相当好啊!

原文地址:https://www.jianshu.com/p/0ff8cb4deaef

背景分析

前10年中,网络程序性能优化的目标主要是为了解决C10K问题,其研究主要集中在如何管理数万个客户端并发连接,各种I/O框架下如何进行性能优化,以及操作系统参数的一些优化。当前,解决C10K问题的服务器已经非常多。Nginx和Lighttpd两款非常优秀的基于事件驱动的web服务框架,Tornado和Django则是基于python开发的非阻塞的web框架这些软件使得C10K已经不再是问题了。

  • 从整体上看
    为了满足日益增长的需求主要采用分布式集群来分担负荷,应对大量的用户请求.
 
集群
  • 从结构上来看一个节点的服务器框架包含

  • 网络模块

  • 事件驱动模块

  • 隔离,多核业务分发模块

  • 业务层

  • 在单个节点上,核的使用来看,主要包括

  • 单线程服务器
    优点是无竞争,缺点是没有充分利用系统资源

  • 多进程模型
    隔离性好,利用了系统更多的资源,缺点是进程间资源共享难

  • 多线程模型
    充分利用系用资源,竞争需要小心处理

需求分析

综合分析

  • 在应对网络密集型的巨大数据量时,一般选择是横向扩展节点,但是节点的增多会变相的增加设备成本和技术风险,且当集群节点到一定的量后,节点之间的交互成本本身就会成为瓶颈。
  • 在特定场合下,譬如嵌入式设备上的后台服务,服务器不可能搭建集群。

因此提升服务器本身性能同样重要。

具体分析

传统服务器可能有下面的潜在问题

  • 异步模式的弊端
    一般我们使用epoll来高效的处理网络读写事件。在基于多线程的服务器设计框架中,在没有请求到来的时候,线程将会休眠,当数据到来时,将由操作系统唤醒对应的线程,也就是说内核需要负责线程间频繁的上下文切换,我们是在依靠操作系统调度系统来服务网络包的调度。在网络负载很大的场景下只会造成核满转且不断相互切换,进一步增加负荷.那么就需要回到最原始的方式,使用轮询方式来完成一切操作,来提升性能。

  • 协议栈的扩展性
    Linix诞生之初就是为电话电报控制而设计的,它的控制平面和数据转发平面没有分离,不适合处理大规模网络数据包。并且为了全面的支持用户空间的各个功能,协议栈中嵌入了大量用于对接的接口,如果能让应用程序直接接管网络数据包处理、内存管理以及CPU调度,那么性能可以得到一个质的提升。为了达到这个目标,第一个要解决的问题就是绕过Linux内核协议栈,因为Linux内核协议栈性能并不是很优秀,如果让每一个数据包都经过Linux协议栈来处理,那将会非常的慢。像Wind River和6 Wind Gate等公司自研的内核协议栈宣称比Linux UDP/TCP协议栈性能至少提高500%以上,因此能不用Linux协议栈就不用。
    不用协议栈的话当然就需要自己写驱动了,应用程序直接使用驱动的接口来收发报文。PF_RING,Netmap和intelDPDK等可以帮助你完成这些工作,并不需要我们自己去花费太多时间。
    Intel官方测试文档给出了一个性能测试数据,在1S Sandbridge-EP 8*2.0GHz cores服务器上进行性能测试,不用内核协议栈在用户态下吞吐量可高达80Mpps(每个包处理消耗大约200 cpu clocks),相比之下,使用Linux内核协议栈性能连1Mpps都无法达到。

  • 多核的可扩展性
    多核的可扩展性对性能提升也是非常重要的,因为服务器中CPU频率提升越来越慢,纳米级工艺改进已经是非常困难的事情了,但可以做的是让服务器拥有更多的CPU和核心,像国家超级计算中心的天河二号使用了超过3w颗Xeon E5来提高性能。在程序设计过程中,即使在多核环境下也很快会碰到瓶颈,单纯的增加了处理器个数并不能线性提升程序性能,反而会使整体性能越来越低。一是因为编写代码的质量问题,没有充分利用多核的并行性,二是服务器软件和硬件本身的一些特性成为新的瓶颈,像总线竞争、存储体公用等诸多影响性能平行扩展的因素。那么,我们怎样才能让程序能在多个CPU核心上平行扩展:尽量让每个核维护独立数据结构;使用原子操作来避免冲突;使用无锁数据结构避免线程间相互等待;设置CPU亲缘性,将操作系统和应用进程绑定到特定的内核上,避免CPU资源竞争;在NUMA架构下尽量避免远端内存访问

  • 内存的可扩展性
    内存的访问速度永远也赶不上cache和cpu的频率,为了能让性能平行扩展,最好是少访问。
    从内存消耗来看,如果每个用户连接占用2K的内存,10M个用户将消耗20G内存,而操作系统的三级cache连20M都达不到,这么多并发连接的情况下必然导致cache失效,从而频繁的访问内存来获取数据。而一次内存访问大约需要300 cpuclocks,这期间CPU几乎被空闲。因此减少访存次数来避免cachemisses是我们设计的目标。
    指针不要随意指向任意内存地址,因为这样每一次指针的间接访问可能会导致多次cache misses,最好将需要访问的数据放到一起,方便一次性加载到cache中使用。
    按照4K页来计算,32G的数据需要占用64M的页表,使得页表甚至无法放到cache中,这样每次数据访问可能需要两次访问到内存,因此建议使用2M甚至1G的大页表来解决这个问题。

解决方案

  • 控制层留给Linux做,其它数据层全部由应用程序来处理。
    减少系统调度、系统调用、系统中断,上下文切换等
  • 摒弃Linux内核协议栈,将数据包传输到用户空间定制协议栈
  • 使用多核编程技术替代多线程,将OS绑在指定核上运行
  • 针对SMP系统,使CPU尽量使用所在NUMA系统节点的内存,减少内存刷写
  • 使用大页面,减少访问
  • 采用无锁技术解竞争

而DPDK恰好为我们提供了解决问题的脚手架。

[DPDK] 转发 DPDK分析的更多相关文章

  1. [dev][ipsec][dpdk] strongswan/dpdk源码分析之ipsec算法配置过程

    1 简述 storngswan的配置里用一种固定格式的字符串设置了用于协商的预定义算法.在包协商过程中strongswan将字符串转换为固定的枚举值封在数据包里用于传输. 协商成功之后,这组被协商选中 ...

  2. [dev][dpdk][crypto] dpdk加解密设备与IPSEC

    概述 分三部分,加解密框架(crypto framework),加解密设备(crypto dev),安全协议(Security Framework) ×  API,设计思路等,都在加解密框架里:见文档 ...

  3. [ovs][dpdk] ovs-dpdk, dpdk port 大量丢包

    gdb了ovs的代码,发现是 dpdk的imiss计数在不断的丢包. 看了ovs-openvswitchd的日志,重启时发现如下行: --21T11::.427Z||timeval|WARN|Unre ...

  4. [DPDK][转]DPDK编程开发(4)—lcore

    1.知识百科 返回值 操作函数 函数功能 RTE_DECLARE_PER_LCORE (unsigned, _lcore_id) RTE_DECLARE_PER_LCORE (rte_cpuset_t ...

  5. Linux转发性能评估与优化-转发瓶颈分析与解决方式(补遗)

    补遗 关于网络接收的软中断负载均衡,已经有了成熟的方案,可是该方案并不特别适合数据包转发,它对server的小包处理非常好.这就是RPS.我针对RPS做了一个patch.提升了其转发效率. 下面是我转 ...

  6. Linux转发性能评估与优化(转发瓶颈分析与解决方式)

    线速问题 非常多人对这个线速概念存在误解. 觉得所谓线速能力就是路由器/交换机就像一根网线一样. 而这,是不可能的.应该考虑到的一个概念就是延迟. 数据包进入路由器或者交换机,存在一个核心延迟操作,这 ...

  7. [dpdk][hotplug] DPDK网卡设备热插拔

    dpdk pci网卡设备的热插拔. 样例程序如下: ... ... static int driverctl(char* pci) { int pid; pid = fork(); ) { execl ...

  8. [dpdk][kni] dpdk kernel network interface

    文档:https://doc.dpdk.org/guides/prog_guide/kernel_nic_interface.html 摘要: The KNI kernel loadable modu ...

  9. Socks协议以及代理转发工具分析

    前言:最近两场HW都和某师傅学到了挺多东西,算是对内网不出网以及流量代理做个分析(SOCKS协议,reGeorg原理分析,frp的代理,CS上的代理 SOCKS SOCKS(Socks:Protoco ...

随机推荐

  1. C++调用外部应用程序

    很多时候,我们的程序需要调用DOS命令,通过Dos命令调用其他程序从而完成所需要完成的功能.比如,调用Dos程序PKZIP完成ZIP包的解压缩,调用SVN完成文件的更新或者上传.但是在程序运行时又要求 ...

  2. golang:吐槽multipart的设计

    最近在做邮件解析的工作,因此接触到multipart库,用了之后才发现golang的multipart有一点设计很诡异. 红线标出来的话意思是:当Content-Transfer-Encoding的值 ...

  3. YII页面显示trace

    修改protected/config/main.php 'db'=>array( 'connectionString' => 'mysql:host=localhost;dbname=te ...

  4. python虚拟环境virtualenv的安装与使用

    如果我们要同时开发多个应用程序,每个应用可能需要各自拥有一套“独立”的Python运行环境,我们可以使用virtualenv解决这个问题,它可以为一个应用创建一套“隔离”的Python运行环境. 一. ...

  5. Linux x64系统上安装 oracle 11g R2 x64

    1.首先到官网上下载oracle 11g x64位软件包 下载地址: http://download.oracle.com/otn/linux/oracle11g/R2/linux.x64_11gR2 ...

  6. 【emWin】例程三十:窗口对象——Multiedit

    简介: 本例程介绍MULTIEDIT的使用方法通过MULTIEDIT 小工具可编辑多行文本.它既 可以被用作简单的文本编辑器,也可以用来显示静态文本.该小工具支持带滚动条 和不带滚动条的滚动 触摸校准 ...

  7. 字节顺序:高位优先(big-endian)和低位优先(little-endian)

    网络字节序: MSB 高字节前存法 Most Significant Bit   (Big Edian) 主机字节序: LSB 低字节前存法 Lest Significant Bit  (Little ...

  8. PLSQL存储过程(基础篇)-转

    我不是专门的开发人员,但存储过程又是很重要的知识,为了能够很好的记忆,现把这些基础知识总结一下.存储过程可以实现代码的充分共享,提高系统性能. 基础篇       知识回顾 如果经常使用特定操作,哪么 ...

  9. GoLang之strings、buffers、bytes、binary包

    strings包 strings包的使用举例: package main import s "strings" import "fmt" var p = fmt ...

  10. [JS] ECMAScript 6 - Async : compare with c#

    一段引言: Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大. 它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对 ...