京东网络接入体系解密之高性能四层网关 DLVS

阅读数:2594 2018 年 2 月 7 日

话题:语言 & 开发架构

DLVS 诞生之初

在 SLB 这块,京东用户接入系统提供四层负载均衡服务和应用层负载均衡服务,对于公网流量接入部分,和很多公司一样采用的是四层和应用层负载相结合的架构,利用四层负载来实现应用层的水平扩展。四层负载在 JFE 1.0 版本中使用开源的 LVS 实现,考虑单机性能的问题,使用了 DR 模式和集群部署方式,并将 LVS 和应用层负载按照服务单元进行部署。这种模式在中等规模的业务场景运行良好,随着业务的不断增长,单业务 QPS 超过 200 万,以及全站 HTTPS 改造要求 SSL 在 SLB 上完成卸载,应用层负载集群规模将不断扩大,同时受限机房机架资源等因素,需要实现四,应用层负载解耦。为此我们对四层负载进行了重新的设计和自主研发,加入了在线上服务保障过程中的业务诉求,在性能、可用性、运维管理以及安全防护上提升。

业务增长对性能的需求

在过去的 10 年,京东的流量峰值从几十万到现在的千万级 QPS,给流量分发的四层负载均衡服务带来了巨大的挑战。Linux 内核实现版本受限于网卡的中断收包模式以及二三层锁的开销,系统经过调优后的转发能力单台 QPS 在十万级别。为了满足业务流量的陡增,只能是通过增加集群规模和通过多集群的方式进行扩容,随着集群数量和规模的不断增加,给服务保障带来了具大的挑战,容量管理以及容灾方案设计都变得非常的复杂。

服务质量的精细化

由于支撑的业务场景越来越丰富,既有长连接(IM)应用场景又有视频业务需求,同时业务对服务稳定性的要求越来越高,接入平台作为基础设施服务,可用性要求越来越高,要求在不同层面保障服务的稳定性,避免单机故障和机房故障对线上服务的影响。

目前常用的集群方案是采用路由来实现,在京东内部我们使用的 BGP 协议(后面会介绍部署方式),最终要依赖交换机的 ECMP 来实现,ECMP 的缺陷是如果一台服务器宕机,同一条流的数据包可能就会被转发到集群其它机器上,如果没有会话同步,那么该连接数据包就会丢弃,最终业务层超时。这对于一些长连接在线的业务影响会更加明显,比如在线的 IM 业务以及推送业务等服务。

运维管理的自动化

随着业务流量的陡增,集群规模越来越大和多集群的出现,同时对于线上大量应用的业务配置变更,对运维也是很大的挑战。自动化程度,成为衡量公司技术能力的一项重要指标。

对于接入平台,承载了公司众多的业务,实现快速的业务变更同时做到每次变更对业务无损,从平台角度看这是必须要去解决的问题。

安全防护能力

接入流量作为服务入口,在面对网络攻击时,需要具备安全防护的能力,保障平台服务的稳定性,同时做到对业务透明和精准防护,减少对业务的影响。传统方案通常采用单独的检测和清洗集群来实现,从技术层面看完全可以把异常流量清洗功能移到四层负载上,并以集群的方式部署,节省资源的同时减少旁路部署带来的复杂网络拓扑。同时四层负载更加接近业务,更方便用户根据特定业务定制一些安全规则,真正起到分层防护的能力,保证业务的安全稳定。

方案选择与功能定义

数据包收发方案选择

对于高性能的数据包处理方案来说,目前主流方案包括了硬件化方案和软件化方案。

对于硬件化方案,性能上虽然会优于软件化方案,但它昂贵的价格、有限的容量、灵活性和扩展性都不太适合处于中间转发位置的四层负载。而且随着多核服务器的普及,软件方案也可以达到网卡限速的性能,从价格、容量和灵活性上都远高于硬件方案,最终我们放弃了硬件方案。

在众多的软件化方案中,pfring 依然轮询 RX Queue,而不能同时访问所有的 RX Queue。导致单核占用率比较高,不能充分利用多核性能。pfring 和 netmap 对于大叶内存和 numa 等也没有库来支持,在实际的应用中 (多路处理器和网卡),必然会影响性能。

综合来看,dpdk 能充分发挥多核处理的的优势,来提供更好的转发性能外。同时 dpdk 提供了便于快速开发的库(内存池、网卡信息获取、无锁队列、hash 等)。最重要的是 dpdk 由 Intel 发起并支撑,加之社区活跃程度高,我们最终选择了 dpdk 作为数据包收发方案。

功能定义

  • 支持集群部署
  • 支持配置集中管理
  • 支持会话保持
  • 支持 tcp、udp 的四层负载均衡
  • 支持 DR 和 FULLNAT 模式
  • 支持 rr、wrr、源 ip hash 等负载均衡算法
  • 支持主动健康检查
  • 支持透传客户机 IP
  • 支持会话同步
  • 支持 syn flood, ack flood 等四层攻击防护
  • 支持畸形报文过滤、黑白名单

系统实现

DLVS 核心架构

结合各个功能的实现方式,下图是四层负载的 DLVS 的核心架构(后续章节会展开讲解)。

DLVS 包括数据平面和控制平面,控制平面主要负责配置、监控和日志的管理。数据平面主要是基于 dpdk 实现的数据包处理和转发。控制平面和数据平面的通信主要通过 kni 接口和 unix 域套接字接口。

控制平面的 quagga 用于和交换机建立 BGP 连接,发布路由和 DLVS 保活监控;keepalived 用于 vip、real server 等业务的配置和 real server 的健康检查;管理 agent 用于提供对外配置接口和日志上报接口。

数据平面虽然是单进程,但我们在内部采用了多线程机制,并将管理和业务流量分离,以避免大的业务流量对管理流量产生影响。即把线程分为管理线程和业务线程,它们之间通过队列进行通信。管理线程负责处理经过内核的报文、进程间通信的报文等,同时将配置下发给各个业务线程,既每个业务线程都拥有一份配置。业务线程有多个线程,包括负载均衡业务的处理、安全防护和会话管理等。

接下来我们从业务角度、性能角度、高可靠性角度和安全防护角度来说明四层负载 DLVS 的具体实现。

负载均衡业务的实现

结合京东商城和京东云的业务需求,对于四层负载我们支持了 TCP 和 UDP 两种协议,支持 fullnat 和 dr 两种模式,并支持了 rr、wrr 和源 ip 哈希选择 real server 等基本功能,具体的实现我们不再详细解读,大家参考 kernel 版 lvs 的实现即可,原理方法基本一致。在这里我们只结合真实业务场景中遇到的问题来提醒大家在实现过程中特别需要注意的几点。

rr 算法选取 real server

在实际使用过程中,每台 DLVS 选取 real server 都是从头开始轮询的。在实际应用场景中,我们发现集群新增 DLVS 时,real server 的流量严重不平衡,都集中在了配置的比较靠前的几台 real server 上。我们通过随机哈希 real server 的位置,再进行 rr 选取,从而解决了这个问题。wrr 的选取解决方案类似。

业务配置的加载

开源的 lvs 是 kernel 的 module,在 dpdk 上来实现 lvs 的功能会导致原有的 keepalived 和 ipvsadm 无法进行配置和监控的管理。我们利用域套接字实现的接口来替换 keepalived 和 ipvsadm 的消息下发接口,从而实现了 dpdk 版 lvs 与 keepalived 和 ipvsadm 的无缝对接。

业务的接口我们使用统一的库 DLVS wrapper 来实现,交互流程如下图所示:

Client 真实 IP 获取

由于业务的需要,有些服务需要获取到 client 的真实 IP 和端口号。开源的 lvs 采用的 toa(将真实源 IP 和端口加在 tcp option 中的方式),需要 real server 安装相应的内核补丁,这对于在线业务迁移带来具大的成本。

我们采用 proxy protocol 将 client 的真实 IP 和端口号进行封装,然后传递给后端的应用,由于采用了应用层的方式,应用层支持 proxy protocol 即可,无需要修改内核代码,并且升级修改对业务无损。

proxy protocol 交互过程和协议格式如下图所示:

proxy protocol formatPROXY_STRING + single space + INET_PROTOCOL + single space + CLIENT_IP + single space + PROXY_IP + single space + CLIENT_PORT + single space + PROXY_PORT + "\r\n"

Example:PROXY TCP4 198.51.100.22 203.0.113.7 35646 80\r\n

在收到客户端发过来的第一个 ACK 数据包时,插入一个 TCP 数据包,负载是上述 proxy protocol 内容。

高可靠性的实现

管理流量与业务流量分离

如果管理流量和业务流量夹杂在一起,在高业务流量的情况下,对管理流量可能会产生影响,如:bgp 引流出错、配置的丢失、健康检查报文的丢失等。所以我们需要将业务流量和管理流量进行分离。我们结合 dpdk 的 fdir 技术和对 rss hash 配置的源码修改来实现。

由于控制平面基于 Linux 的进程,所以我们使用了 kni 口作为管理数据流接口,首先我们通过 fdir 接口,将 kni 的 IP 地址下发给网卡,并绑定到网卡的 0 号队列。然后对 dpdk 的 rss hash 进行了修改,保证业务报文(非 kni ip)在 rss hash 队列时,从 1~N 中选择。逻辑流程如下图所示:

会话同步

为了保障一些服务的长链接在部分四层负载服务节点出现异常后,同集群其他节点能够处理已建立的 TCP 连接,需要对会话进行跨机器存储,来保证四层负载设备出现异常时,流量被牵引到其他四层负载节点上,数据包能够继续正确转发。

对于京东一个在线业务来说,在线活跃连接在大促期间会非常大,为此,DLVS 会话同步方案设计出发点是需要支持亿级用户在线,并可以根据业务增长在单集群内水平扩展。对于会话保持的实施方案,我们先对现有方案进行了调研,然后结合现有方案的不足进行重新设计。

现有方案:

方案一,每台四层负载都采用主备的方式。具体逻辑架构如图所示:

从逻辑架构图上,可以明确看到这种方案的优缺点。优点是实现简单、扩展性好。缺点是正常工作时,一半的服务器闲置,造成资源浪费。

方案二,对四层负载进行分组,组内成员通过组播进行会话同步,逻辑架构如图所示:

与方案一相比,该方案可以充分利用四层负载服务器,不会造成资源的浪费。但是,它的缺点也很明显,由于四层负载集群被分组。分组内的四层负载通过组播的方式相互同步会话。这就会导致组的大小受限于单台四层负载的容量和带宽,集群组无法灵活地扩展。

DLVS 会话同步方案:

为了尽量减少资源浪费的问题,我们对四层负载进行了分类,master DLVS 和 backup DLVS。master DLVS 用于承载正常业务流量,backup DLVS 用于承载出现异常的 master DLVS 的流量。考虑到业务整体突发异常性的概率, backup DLVS 数量远小于 master DLVS 的数量,而且对 backup DLVS 的容量和带宽进行了扩容。

为了解决横向扩展的问题,我们首先采取了外部 cache 存储全局会话,其次将分组对业务(vip)透明,通过虚拟的分组来进行 cache 和 backup DLVS 的划分,从而使得横向扩展不会受限于单台四层负载的容量和带宽。使得四层负载在支持会话同步的情况下,实现对亿级在线用户流量的负载服务稳定。

结合解决资源浪费和扩展性的问题,给出整体的系统架构图:

为了更加方便大家了解会话同步相关的数据流程,我们结合几个场景讲解数据流的走向。

1. 分组对业务透明

通过将 backup DLVS 和 cache 进行分组,实现了业务 master DLVS 的分组的透明。使得 DLVS 的集群可以横向扩展,用于支撑亿级在线用户业务。

2. 正常 DLVS 的数据流

3. 宕机 DLVS 的数据流

4. 重启 DLVS 的数据流

重启过程中的数据流和宕机的数据流基本一致,参考宕机数据流。

重启后的数据流,首先恢复的 master DLVS 依据 device id 与 cache 进行会话批量同步,同步完后发送恢复通告给 backup DLVS,然后 master DLVS 进行业务流量的转发。

5. 新增 DLVS 的数据流

新增 master DLVS 时,首先根据 device id 与 cache 进行会话同步,然后发送设备新增通告,最后转发业务流量。由于一致性 hash 的原因,会有一部分原有会话流量发送到新增 DLVS 上,DLVS 将流量转发给 backup DLVS,backup 进行会话查询,根据 device id 进行二层转发给原 DLVS,保证会话的一致性。

安全防护的实现

作为流量的入口,需要提供基础的流量防护功能。传统的方式是在流量出入口部署流量检测和清洗设备。检测是被一般是旁路部署,通过引流的方式将异常流量引流到清洗设备进行清洗,然后进行流量回注。采用旁路部署的方式,主要是为了防止因为清洗异常流量的性能消耗(清洗设备对报文进行了深度的分析)而影响到正常流量。但旁路部署同样带来了一些问题,比如:清洗设备对报文进行了深度的解析分析(七层报文解析分析),使其自己成为流量的瓶颈;流量的多次转发造成一定的延迟;未被牵引的流量不能进行安全防护;对实际业务用户无感知等

四层负载作为流量的入口,由于我们采用的高性能实现方案,大大提升了四层负载的性能,所以我们希望四层负载能够替代传统的流量检测和清洗设备功能。来减少延迟、对全部业务进行四层防护,并结合业务进行定制化防护等。同时不需要在部署流量监测和清洗设备,节省大量的资源。

流量清洗设备防护内容一般包括畸形报文防护、黑白名单支持、dns 防护、四层 ddos 防护、cc 防护等。考虑到报文解析和深度分析带来的性能消耗,结合四层负载所承载的功能,我们已经将报文解析到了传输层(TCP、UDP 等),将 cc 的防护放到了四层负载后端的七层负载上来进行。把畸形报文防护、黑白名单、dns 防护和四层 ddos 防护放到 DLVS 上来实现(这也符合网络分层防护的思想)。最终流量接入的防护架构如下。

在通过四七层负载来提供分层防护替换流量检测和清洗设备后,使得整个流量接入的网络拓扑变得简单易操作。

结合具体的实现我们来详细解读四层防护在 DLVS 上的实现

一键开启关闭

对于安全防护,我们采取了一键开启或关闭。在安全防护能力比较健全的用户环境中,可以直接关闭安全防护功能,以便进一步提升四层负载的性能。

同时,我们也支持了基于 vip 的安全防护开关,可以根据特殊的业务,开启安全防护功能,使得安全防护更加灵活。

多样性防护

开源 lvs 在安全防护上,只支持了 synproxy(用于对 tcp syn flood 的伪造源 IP 进行校验)。我们在支持 synproxy 的基础上,增加了多种防护机制。

畸形报文防护:对于数据报文解析过程中,对非法的报文(IP 分片攻击、TCP 标志位攻击、smurf 攻击和 land 攻击等)格式进行过滤。

黑白名单:结合大数据学习分析和威胁情报的信息,直接对五元组报文进行过滤或放行。对于临时的业务封禁非常便捷。

DNS 防护:对于 DNS 的 flood 攻击、DNS 缓存投毒攻击、DNS 异常报文攻击等的防护。

四层 DDOS 防护:对 udp flood、icmp flood、tcp flags flood 等进行防护。

结合一键开关和多样性防护,我们安全防护内部的数据包流程逻辑如下图所示:

增加了安全防护后,必然会对四层负载的性能造成一定的影响,不过我们经过优化处理后,单机的 TCP 新建也达到了 1M、并发达到了 8M+,足以满足线上业务需求。

常用防护手段

结合业务使用场景的实现。我们对主要的 TCP 攻击防护、UDP 攻击防护和 DNS 攻击防护进行概要的介绍。

  • TCP 防护的常用手段:synproxy、首包丢弃、tcp flags 检查、sequence 检查、基于阈值的分析、限速等
  • UDP 防护的常用手段:基于阈值的分析、UDP 报文随机指针内容统计、负荷指纹学习和识别、限速等。
  • DNS 防护的常用手段:基于阈值的分析、首包丢弃、构造 request 回验、校验 query id 和域名等

高性能的实现

dpdk 的使用

底层的框架我们采用的是 Intel 提供的 dpdk 技术。dpdk 的特性 (用户态驱动、网卡驱动采取 poll mode、支持 burst 收发、支持大页内存、numa、无锁队列、CPU 亲和性、内存池等) 我们这里不再重复,详情参考官网www.dpdk.org。我们采用了 run-to-completion 的方式,主要是考虑到减少线程之间通过队列传递报文造成的性能损耗。dpdk 主要模块分解 (摘自网络) 如下图所示:

配置无锁实现

四层负载配置的管理不同于通用网络设备,由于后端的 real server 可能会经常的变化。所以四层负载下发配置的频率也会比较高。传统的实现方式,对于配置的下发,都是要进行加锁处理的。这势必会影响其它流量的性能。

为了避免这种影响,我们通过配置 per core 化即 master core 利用 core 间队列,为每个业务 core 都下发一份配置,各个业务 core 顺序执行读取配置和处理业务,实现了配置下发的无锁。

会话无锁实现

四层负载的新建和并发能力,直接和会话的创建和查找是否加锁有直接关系。如果一个会话只有一个 core 来处理,即可实现无锁,但是多核处理器下如何保证上下行流量都能落到同一个 core 呢?

我们再下发配置时,将 local ip 进行了 per core 绑定,即下行流量通过 rss hash 到达某个 core 绑定的队列时,在选择 local ip 时,也就只会选择已经绑定该 core 的 local ip。同时我们利用 fdir 技术,将该 local ip 与该 core 绑定的网卡队列绑定。这样便实现了上下行流量都落在同一个业务处理 core。逻辑流程如下所示:

性能数据

数据基于 X86 服务器并配置 Intel X520 网卡,分别以大小数据包为例,对转发过程中的 bps、cps 及 cpu 使用率进行了统计。

CPU 型号

资源大小

bps

CPS(每秒 TCP 新建连接数)

CPU(%)

Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.10GHz

2

8.5G

120 万 +

90

Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.10GHz

2K

9.2G

40 万 +

40

线上应用

京东商城 SLB 应用场景

DLVS 是京东商城用户接入系统一部分,为全站业务提供四层负载均衡服务,目前接入业务除了有短连接服务,还有像 IM,消息推送等长连接业务场景。 DLVS 作为底层服务,承载全站业务流量,除了在实现上要保障高可用,同时在线上部署架构层面,我们要规避依赖的基础设施故障(比如机房,机架) 层面对服务的影响,为此我们和网络团队一起协作,设计了一套全新部署架构,实现了部署在多机房里的 DLVS 集群互备,依赖京东商城内网传输网络,通过动态路由(IBGP)将流量导入到 DLVS 集群,依赖 BGP 的强大流量调度功能,可以快速地将不同 VIP 的流量在集群间调度,在依赖底层的基础设施出现故障时,系统自动将流量切换到其它机房备份集群,整个过程对服务几乎无影响,示意图如下:

DLVS 和交换机建立 BGP 连接,集群的机器发布同样的路由,不同集群之间通过 BGP 的 community 选项进行区分,通过匹配不同的 community 字段在把路由重分布时设置不同的 cost,来控制路由。在所有集群的 BGP 失效时,所有流量落到其中一个默认的集群

京东云 IP 高防应用场景

京东云高防产品针对网站类业务提供网站高防服务,非网站类业务提供 IP 高防服务。

在高防业务场景中,流量首先到我们的 DLVS,经过清洗模块完成流量清洗后,通过 FULLNAT 模式将流量导入到用户源站或者我们的 WAF 集群。在高防 IP 中部署逻辑图如下:

总结

基于 Intel dpdk 实现的高性能四层负载 DLVS,无论是京东商城接入体系和京东云高防产品中作为所有业务流量的入口,在平台可用性和支撑业务发展都发挥了重要的作用。与开源实现相比,支持会话同步以及层网络防护等特性,为业务提供了更精细化的服务质量保障,成为同类产品中的佼佼者。现已整合为企业接入系统解决方案的核心部件,对外提供解决方案支持,帮助公司快速建立一套领先的流量接入体系,并可在此基础上进行二次开发,根据公司业务特点进行定制化,为业务保驾护航。