ContainerDNS性能优化之路 17W到1000W QPS超高性能DNS技术实践

一、 引入

随着TIG阿基米德平台全面应用。组成京东容器生态技术栈的分布式域名解析服务ContainerDNS(go版https://github.com/tiglabs/containerdns )全量生产环境应用,承载着每天百亿的访问量,单实例峰值每秒请求达到15W QPS,已经接近ContainerDNS的性能极限(17W QPS)。为了更好的提高系统的并发服务,对ContainerDNS 的优化也势在必行。

本文对ContainerDNS性能优化思考和技术实践历程,希望对业内在容器领域和域名解析方向技术实践一些启迪。

ContainerDNS 的DNS Server 代码用Go 语言实现,我们在后期的优化中,通过各种尝试,并通过pprof 采集数据分析,发现性能损耗最大的是收发包的地方。同时我们对bind9 进行了压测、采集分析发现同样是收发包函数最为耗时。

数据平面开发套件DPDK(Data Plane Development Kit)可以极大提高数据处理性能和吞吐量,提高数据平面应用程序的工作效率。灵感来自TIG容器生态技术栈另外一个重要的服务高性能负载均衡服务Jupiter (https://github.com/tiglabs/jupiter )实现单实例200万QPS的高性能。因此TIG团队工程师想到用DPDK 来实现DNS数据报文的收发是一个有挑战和前景的尝试。

二、系统概述

让我们先来回顾下ContainerDNS设计之初的愿景和初心。ContainerDNS作为京东商城新一代软件定义数据中心的关键基础服务之一,具有以下特点:

  • 分布式设计 多数据中心数据同步复制 避免维护多个域名解析元数据副本
  • 支持自动发现服务域名 支持容器Service
  • 支持后端探活
  • 易于维护、易于动态扩展

图一 ContainerDNS 架构图

ContainerDNS 包括四大组件 DNS server、service to DNS 、user API 、IP status check。这四个组件通过etcd 数据库集群结合在一起,彼此独立,降低了耦合性,每个模块可以单独部署。DNS server 用于提供DNS 查询服务的主体。service to DNS 组件是k8s 集群与DNS server的中间环节,会实时监控k8s集群的服务的创建,将服务转化为域名信息,存入etcd 数据库中。user API 组件提供restful api,用户可以创建自己的域名信息,数据同样保持到etcd数据库中。IP status check 模块用于对系统中域名所对应的ip做探活处理,数据状态也会存入到etcd数据库中。如果某一个域名对应的某一个ip地址不能对外提供服务,DNS server 会在查询这个域名的时候,将这个不能提供服务的ip地址自动过滤掉。

三、 KDNS系统设计与实现

DNS server 是提供DNS的主体模块实现架构如下图:

如上图所示,系统中用到的CPU核有两种角色:主核和从核。主核相当于控制通道,域名数据、交给协议栈的数据都是主核处理。从核主要处理数据通道的数据,通过DPDK网口收包,报文解析处理,解析结果发包给用户。

Data Plane Development Kit(DPDK):是运行在Linux用户态,实现X86通用平台网络报文快速处理的库和驱动的集合,其主要特点:

  • 多核编程框架及CPU亲和性
  • 巨页(HugePage),减少页表项数目,降低TLB miss
  • 无锁队列
  • UIO支持,用户态驱动,减少报文copy
  • poll-mode网卡模式,无中断轮询收包

下面是主核的处理流程:

从核的处理逻辑较为简单,首先调用处理主核发过来的域名数据,从而及时改变自己的域名数据缓存信息。然后调用DPDK收包函数rte_eth_rx_burst 收取报文,如果有数据则进行数据包解析处理,参考下面的协议解析处理模块。如果是本地zone 的域名查询,将查询的结果直接发送给客户端。如果是ARP请求,则将数据包放入kni-pkt-ring 中交由主核处理。如果是转发域名,则交由转发报文处理线程处理。

数据收发模块:采用DPDK的收发包接口,开DPDK启RSS (Receive Side Scaling,多 CPU之间高效分发的网卡驱动技术),由于DNS 访问基本是UDP包端口是53,RSS采用了对IP和端口进行Hash的方式,当客户端很多的时候可以有效地实现多核的均衡。为了更好地提高性能,系统中每一个从核只处理一个收包队列上面的数据。发包也是只发送对应队列上的数据。所以收发包数据间,所有的核都是独立的,没有任何耦合不需要任何锁机制,更加快速。

协议解析处理模块:每一个从核通过DPDK 接口收到数据包,进行数据包解析。并将结果返回给客户端。流程图如下:

转发报文处理模块:系统所有的域名数据都是基于某一个或者多个zone进行的,如果域名不在本地支持的zone内就要将请求发送给上级的DNS Server,比如我们的DNS Server 支持本地的zone是 tst.local,也就是说所有访问*.tst.local的域名本地的DNS Server 都会查询解析,如果用户访问的不是*.tst.local的域名就得转发给上级的DNS 进行解析,这个转发的处理流程较慢,我们采用了一组后台的线程进行处理,这些线程不会绑定到CPU上,完全与主核、从核的功能分离开来,这样主、从核都不会处理这样的慢速数据请求。

首先数据处理从核收到数据包,发现如果请求的域名不是本地的zone配置的域名后缀,走慢速流程即转发流程。从核会将本请求入放在和转发处理线程共享的数据队列中,这样做的好处是把从核解放出来,只处理快速的查询请求,不会block住,从而能全速的处理本地数据。转发报文处理线程是一个死循环,首先从队列中读取数据,没有数据则休眠。如果有数据则将预处理数据并调用转发接口转发给上级DNS Server,并将上级DNS Server的回包处理后放入与主核共享的rte_mbuf无锁队列中。主核会及时的出队转发报文处理线程放入的数据,调用DPDK的网卡发送接口,将数据从主核的发送队列发送出去。需要说明的是这期间数据都是公用一个rte_mbuf 内存,没有任何的数据复制的过程,从而更好地提高性能。

域名信息数据处理模块: 这个是一个后台的线程提供Restful API,可以和agent进行数据交互,从而获取系统的域名数据。

首先注册支持url和方法,目前支持GET、POST、DELETE分别对应着域名的查询、增加、删除三个接口。同时提供状态的查询接口,目前只有两种状态Init和Runing,当agent 检测到进程是刚启动(Init 状态)时,会将所有的域名信息下发到DPDK DNS Server,之后将DPDK DNS Server的状态设置为Runing状态。后面如果有域名信息变更,agent 会调用POST或者DELETE 接口将域名数据同步到DNS Server。为了提高数据的安全性,DNS Server的API支持ssl证书,这样可以有效的防止域名数据被恶意的窃取、修改。同时域名数据插入删除操作的时候,采用了Hash 表的设计,每一个域名先计算出Hash值,如果发生冲突先比较Hash值,如果相同再进行字符串匹配。由于Hash值远远大于Hash桶的长度,当发生Hash冲突的时候先匹配Hash值会增加大大提高匹配的效率。

ARP/BGP报文处理:这模块较为简单,从核解析数据包如果发现是ARP协议报文,将数据传送给主核,主核在将数据通过DPDK的KNI将数据报文发给Linux 协议栈,主核后面再通过KNI 读取Linux协议栈处理的结果,然后调用DPDK的发送接口,将数据发送出去。BGP 协议的处理模式类似,也是交与Linux 内核协议栈处理。

四、性能优化及测试

  1. 恰当地使用rte_prefetch0(),可以减少cache-miss次数
  2. likely()和unlikely()的使用,可以减少分支预测失败的次数
  3. 数据处理全程无锁,交互部分利用无锁队列实现
  4. 整个处理过程无包copy,发送包复用收包的mbuf内存,减少mbuf的申请

性能测试:

1)测试环境

CPU:Intel(R) Xeon(R) CPU E5-2698 v4 @ 2.20GHz NIC:intel 82599ES 10-Gigabit SFI/SFP+ Network Connection

2)测试配置

KDNS(八个数据核一个控制核),bind9 (16个核,版本bind-9.10.6-P1)

3)测试结果

bind9 五分钟单域名测试结果(47W QPS):

上图是bind9 稳定运行5分钟的数据采集结果,平均47W QPS。

KDNS 20分钟单个域名测试结果(1000W QPS):

如上图所示,优化后的KDNS性能达到1000万QPS,而且二十分钟运行很平稳,并发性能是bind9 20多倍、ContainerDNS(go版)的50倍。

KDNS 多个域名测试结果,其中系统域名记录大概20亿条。

相同网络环境下响应时间对比(queryperf 测试):

Queryperf数量

最慢响应us(bind9/ KDNS)

最块响应us(bind9/ KDNS)

平均响应us(bind9/ KDNS)

1

1140/226

15/16

102/68

3

1138/654

18/17

172/83

如上图所示,可以看到在相同的测试服务器、客户端主机、网络的环境下测试,利用DPDK收发包实现的DNS,对于访问的响应更加优秀和稳定,最慢响应由bind9的1140微妙提高到226微妙,平均响应时间也提高了一倍。

五、总结

本文主要介绍了KDNS,一种基于Intel DPDK平台开发的DNS Server。其接近网卡线速处理能力,灵活的部署,多样的监控以及可靠的稳定性,同时兼顾ContainerDNS的所有的分布式模块功能。作为TIG阿基米德平台京东数据中心操作系统(JDOS)的一个重要的组成部分,在京东数据中心发挥至关重要的作用。

原文发布于微信公众号 - IT技术精选文摘(ITHK01)

原文发表时间:2018-03-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏更流畅、简洁的软件开发方式

js的动态加载、缓存、更新以及复用(二)恼人的命名冲突

  上一篇发出来后得到了很多回复,在此首先感谢大家的热情捧场!有的推荐第三方框架,比如 In.js、requrieJS、sea.js、lab.js等。这个开阔了...

2458
来自专栏python全栈布道师

想不想用标准库写一个桌面应用程序,就写个群聊天室吧

39110
来自专栏FreeBuf

反取证技术:内核模式下的进程隐蔽

介绍 本文是介绍恶意软件的持久性及传播性技术这一系列的第一次迭代,这些技术中大部分是研究人员几年前发现并披露的,在此介绍的目的是建立这些技术和取证方面的知识框架...

3368
来自专栏Java后端技术栈

记一次解决业务系统生产环境宕机问题!

Zabbix告警生产环境应用shutdown,通过堡垒机登入生产环境,查看应用容器进程,并发现没有该业务应用的相应进程,第一感觉进程在某些条件下被系统杀死了,然...

881
来自专栏lgp20151222

傻瓜式的go modules的讲解和代码

国内关于gomod的文章,哪怕是使用了百度 -csdn,依然全是理论,虽然golang的使用者大多是大神但是也有像我这样的的弱鸡是不是?

4862
来自专栏QQ音乐技术团队的专栏

全民K歌后台编译优化:从40分钟到30秒

编者注 :全民K歌上线1年半的从0发展到1.5亿,用户越来越多,后台代码库越来越大,编译速度也与日俱慢,编译一下整个工程需要30-40分钟,如何实现秒编至关重要...

3847
来自专栏coding

django2.0入门教程第一节启动开发模式下的服务器

1602
来自专栏恰童鞋骚年

NoSQL初探之人人都爱Redis:(1)Redis简介与简单安装

  随着互联网Web2.0网站的兴起,传统的关系数据库在应付Web2.0网站,特别是超大规模和高并发的SNS类型的Web2.0纯动态网站已经显得力不从心,暴露了...

1152
来自专栏编程直播室

折腾git pages+hexo+NexT初识hexo开始本地试运行准备服务器准备上传工具先告一段落发表文章主题

2246
来自专栏IT笔记

SVN自动化部署全流程之架构之美

公司一直没有一个完善的部署流程,基本都是通过上线打包以后SSH手动拖拽部署项目。 当然网上也有现成的持续集成工具,比如jenkins。Jenkins是一个开源软...

3967

扫码关注云+社区

领取腾讯云代金券