2Core+1千兆网卡如何打出100万RPS 的DNS流量

背景

以前在一次DNS压力测试中,尝试用DPDK撰写了一个DNS的压力测试工具,难度不大,直接用DPDK的SAMPLE 和一个DNS发包程序的源码糅合在一起即可,测试效果还行,代码写的很渣,但是能用,可以把被测试设备的性能打到极限。

如何搭建DPDK编译环境可以在dpdk官网可以找到,本文完整的linux源码在下面的github地址,包含eclipse环境配置

[https://github.com/Linjian139/dpdk_dns_flood/blob/master/main.c]

关键点

由于dpdk直接使用底层发包,从mac->ip->udp,需要自己构造每一层次的报文头和报文体,代码包含若干结构体和构造方法,关键结构体包含:

    struct DNS_HEADER
    struct QUESTION
    struct R_DATA
    struct RES_RECORD
    struct ADD_RECORDS

主要的数据包构造方法:

void build_udp_mac_header
void build_dns_header

另外checksum也要自己做(根据文档DKDP似乎是可以直接用硬件功能进行checksum的,不过我没弄成功)

代码要点

主要函数包含main函数和循环发送数据包的main_loop

static int main_loop(__attribute__((unused)) void *arg)
{

  const unsigned lcore_id = rte_lcore_id();


  char argv_2[] ="172.16.1.252";  //目标被测试设备的入口IP地址
  const char *question=arg_query;//查询的域名
  char argv_1[] ="10.128.10.";//本机地址段,该程序从这个段然后根据lcore id生成的真实ip地址
       ......
 

      if (unlikely(udphdr_ptr->source>=65534))
      {
          iphdr_ptr->ip_src.s_addr++;
          iphdr_ptr->ip_sum=0;
          iphdr_ptr->ip_sum=cksum(iphdr_ptr,20);
          udphdr_ptr->source= base_port;

      }else
      {
          udphdr_ptr->source++;//此处会变换端口
       }

     .....
}

main_loop中构造数据包

main.c中初始化RTE环境参数,检查对应dev,这些都可以用dpdk官方sample代码中找到,最后调用main_loop执行死循环发送DNS数据包

rte_eal_mp_remote_launch(main_loop, NULL, CALL_MASTER);

如何执行

Usage 信息是准的:

  PRINT_INFO("\nUsage: %s [EAL options] -- -p PORTMASK -i IN_CORES -o OUT_CORES\n"
             "    -p PORTMASK: hex bitmask of ports to use\n"
             "    -o OUT_CORES: hex bitmask of cores which write to NIC",
             prgname);

在DKDP环境中使用bitmask的方式指定使用那张网卡执行,可以使用DPDK的自带的工具查看哪些网卡可用,用网卡在dpdk的序号映射为bitmask进行指定。

效果和感想

坏处:

DPDK使用感想是三个字:”真费电“,一启动啥都不干,cpu直接原地爆炸到100%,DPDK 2.1版本中只能通过intel的cpu节能技术把频率降低,达到业务闲时降低能耗的效果,不知道新版本会不会好点,但是感觉从poll mode driver的实现角度说,也只有这样。

好处:

用DPDK没有soft irq的瓶颈,不会像nginx一样数据包多的时候会造成大量的soft irq,nginx还是依赖linux本身的协议栈,哪怕是走了epoll,数据包的后半处理还是要用软中断通知cpu执行TCP部分的后半,然后从TCP再走epoll的callback直接调用挂在socket的nginx方法

因为直接从net dev的buff拿数据到userspace,又是死循环模式,处理延迟很低,可以适配一些低延迟场景

现在也有用dpdk直接实现多核tcp协议的,比如mTCP,国内也有一些实现,不过17年后国内那个项目没有在更新了,感觉mTCP 14年开始兴起,17年慢慢就冷了,大约在14年普林斯顿大学有一篇相关的论文:
mTCP: A Highly Scalable User-level TCP Stack for Multicore Systems
里面有过一些测试,在高压力场景下,可以看到内核消耗了大量的资源,通过dpdk可以把cpu cycle更多的给到应用,而不是消耗在软中断和从kernel space 到user space的memcpy:

Screen Shot 2019-08-07 at 5.30.29 PM.png

测试效果

在使用F5 5200V ,wideip进行解析,round robin算法下,一台服务器使用两个core,一个千兆网卡,可以打出100万RPS并成功解析,此时F5 5200V CPU为100%,解析率100%:

DNS RPS 1M+:


Picture1.png

每秒新建1M+:


Picture2.png

F5 5200 CPU 100%:

Picture3.png

感觉帮客户省了一笔租IXIA的钱,但也没到我兜里 :P

下一篇写源进源出在linux kernel中如何通过魔改实现

魔改一时爽,一直魔改一直爽

你可能感兴趣的:(2Core+1千兆网卡如何打出100万RPS 的DNS流量)