终于有一篇文章把互联网性能优化-性能挑战与分析给讲清楚了!

首要性能目标
为了能有的放矢,在探讨负载平衡器的性能优化题目之前,我们先要明白若何权衡、评价负载平衡器的性能。下面连系负载平衡器的利用处景,简单先容收集装备的首要性能目标。
1.带宽
带宽(Bandwidth)通常为权衡收集速度的标志。当我们会商通讯链路的带宽时,一般指链路上每秒传输的最大比特数;当我们会商收集装备的带宽时,一般指该装备的收集接口支持的每秒传输的最大比特数。
带宽的单元是bps(bits per second)。负载平衡器作为一种收集装备,其网卡速度可以作为带宽的权衡目标。随着网卡技术的进步,千兆、万兆网卡已成为数据中心的支流设置,25GB/40GB/100GB网卡也起头慢慢在现实中利用。对于大部分营业场景,网卡的物理带宽对负载平衡器性能的约束已经不再是题目。
2.吞吐量
吞吐量(Throughput)是系统在给按时候内可以处置的信息量的一种怀抱。在收集数据传输范畴,吞吐量是收集从一个节点到另一个节点每秒传输的现实有用比特数,单元是bps(bits per second)。
我们常用“吞吐量”评价一个系统的观察性能,即系统在一段时候内丈量到的传输有用比特数的均匀值。收集的吞吐量不但受收集带宽、延时等链路物理性能约束,而且受利用办事软件性能的影响。在一个复杂的系统中,吞吐量最小的节点决议着全部系统的整体吞吐量。
3.延时
延时(Latency)是数据在系统中传输需要的时候,即数据从起头发送到投递对端需要的时候,单元一般用ms(millisecond,毫秒)。延时分为单向延时(One-way Latency)和往返延时(Round-trip Latency),在现实丈量时一般采用往返延时。
延时和吞吐量有什么关系?很多人会以为低延时意味着高吞吐量,实在这类概念是不正确的。比如,高负载运转的长肥管道收集(Long FatNetwork)的收集延时很高,但其吞吐量也很大。打个例如,假如把吐吞量看做人的胖瘦,那末延时就相当于人的高矮,这两个目标没有必定的联系。
4.包转发率
包转发率是收集在单元时候内转发的包的数目,单元是pps(packets persecond)。负载平衡器的首要功用是数据转发,作为无状态的四层负载平衡器,包转发率表现了其处置数据包的速度和效力,是以一般将包转发率作为权衡四层负载平衡器最关键的性能目标。收集链路支持的最大包转发率称为“线速”(Wire Speed),按照收集带宽、传输介质和相关协议标准,可以计较出网 络 链 路 的 最 大 包 转 发 率 ( 线 速 ) 和 最 小 包 转 发 率 。
以 万 兆 以 太 网(Ethernet)为例,其收集带宽为10Gbit/s,由于不成能每个比特都是有用数据,以太网两个帧之间有默许12字节的帧间距(Inter-Frame Gap,IFG),每个帧之前还有7字节的前导(Preamble)、1字节的帧首定界符(Start FrameDelimiter,SFD),所以以太网的包转发率为:

在以太网中,一个帧的物理长度的计较方式如表7-1所示。

表7-1 以太网帧物理长度计较方式
因 此 , 对 于 万 兆 以 太 网 络 来 说 , 最 大 包 转 发 速 率 范 围 是 0.08 ~14.88Mpps。即,当收集PDU为最小值46字节时,理论线速可达14.88Mpps;当收集PDU为最大值1500字节时,包转发率最大能到达0.08Mpps。对于现实的以太网,每帧的收集PDU不成能完全一样,是以万兆以太收集的现实最大包转发率的范围为0.08~14.88Mpps。
万兆以太收集的最大包转发率为0.08~14.88Mpps,现实包转发率实在为0~14.88Mpps。14.88Mpps是万兆以太收集理论可达的最大线速,要“实现”这个转发速度,最少要满足两个条件:一个条件是数据包发送无间隔,收集有充沛的数据包来历;另一个条件是转发装备对数据包停止处置的时候低于67.2ns,即1/(14.88Mpps)s。
5.最大并发毗连数
最大并发毗连数是收集装备可以同时保护的最大会话毗连的数目,其首要受以下几个身分的影响。
● 地址空间:可以用套接字对(SocketPair)唯一标识一个收集毗连,一个套接字对由五元组“协议、当地IP地址、当地端口、远端IP地址、远端端口”组成。远端IP地址和远端端口作为办事的拜候地址凡是是牢固的,是以在不斟酌毗连复用的情况下,一个收集节点可以支持的最大并发毗连数不跨越“当地IP地址”和“当地可用端口范围”的乘积。
● 内存巨细:每个毗连的保持都需要一定的内存开销,对于内存较小的装备,内存极能够成为最大毗连数的制约身分。
● CPU性能:在负载平衡器中,毗连凡是以哈希表的形式存在。毗连数的增加意味着哈希表抵触的几率增加,而处理哈希表抵触需要消耗额外的CPU时候。是以毗连数越大,哈希表抵触的几率就越大,新建毗连的速度也越低。在利用短毗连形式的办事中,当新建毗连的速度下降到小于毗连消亡的速度时,系统的最大并发毗连数就不能再增加了。
6.每秒事务数
每秒事务数是指在单元时候内可以完成的特定范例的操纵数目,单元是tps(transactions per second)。“事务”用于暗示由一系列行动组成的具有特定完整意义的操纵。对于负载平衡器,我们首要关心以下两种事务性能目标。
● 每秒请求查询数(qps):负载平衡器每秒能转发的用户查询和处置的数目,单元是qps(queries per second),首要用于评价七层负载平衡器的性能。
● 每秒新建毗连数(cps):负载平衡器每秒能接管的用户新建毗连的数目,单元是cps(connections per second),首要用于评价四层负载平衡器的性能。
性能应战与分析
中国互联网用户的范围庞大且还在不竭增加,这就要求作为流量分发的负载平衡器要有很高的性能。下面具体分析一下传统的负载平衡器的性能题目。
7.2.1 C10K题目及C10M题目
畴前文先容的性能目标我们可以看到,评价系统的性能是有多个维度的。
随着互联网范围的迅猛成长,客户端数目及同一时候内建立的毗连数目越来越多,这对办事器处置并发毗连的才能提出了应战。而对于一个大型网站的高性能收集办事器来说,其首要需求和瓶颈常常在于并发。
在互联网的成长早期,1999年Dan Kegel提出了C10K题目,那时办事器以1Gbit/s的速度为10000个客户端供给办事,当硬件没有瓶颈时软件能否抗住高并发?随着“事务驱动模子”的出现,C10K题目获得了有用的处理,例如,事务驱动在Epoll、Kqueue等系统挪用上的实现和在以Lighttpd、Nginx、Libevent等利用上的实现。它们改良了本来基于多进程和多线程的模子,大幅进步了办事器的并发处置才能。
现在,大师担忧的早已不是C10K题目,而是C10M题目:办事器的软件性能能否跟上营业的成长和硬件的成长?能否每秒处置万万数目级的并发毗连和10Gbit、25Gbit,甚至100Gbit的流量,到达14.88Mpps万兆网卡的理论线速或更高的线速极限?SMP(Symmetric Multiprocessing,对称多处置)架构、NUMA(Non-Uniform Memory Access,非同一内存拜候)架构下多焦点的办事器性能的可扩大性若何?
关于C10K题目和C10M题目,互联网上有大量的文章先容,写得都很不错,所以这里不再深入探讨,大师可以参考互联网上的文章。下面分析一下传统负载平衡器LVS(Linux Virtual Server,Linux虚拟办事器)的性能瓶颈及其发生的缘由,然后先容一下实现高性能负载平衡的关键技术,再以一个基于DPDK(Data Plane Development Kit,数据平面开辟套件)实现的高性能四层负载平衡器为例,展现若何理论这些技术。
7.2.2 LVS性能瓶颈分析
LVS最早由章文嵩开辟,焦点转发部分是Linux内核Netfilter收集架构中的一个名为IPVS的子模块。随后国内多家公司对其停止了革新,如增加FullNAT转发形式和SYNPROXY功用(见链接[25])、SNAT转发功用等。
其中,FullNAT转发形式被普遍利用的首要缘由是其摆设和运维非常简单、方便,该转发形式对LVS办事器和后端办事器所处的收集情况没有要求,可以跨二层收集摆设,同时不需要在后端办事器上停止额外的IP地址、路由战略、ARP(Address Resolution Protocol,地址剖析协议)抑制等复杂设置。
既然LVS的焦点模块IPVS是基于Linux内核实现的,那末我们就不能不面临这样一个现实,在高性能收集情况下,内核会成为性能瓶颈。这么说也许有人会希奇,究竟内核给人的印象一向是高水准及高性能。现实上,多年来对内核收集部分的优化也从未停止,为何会成为性能瓶颈呢?
我们先看两组数据,如图7-1和图7-2所示,一组来自Google Maglev(见链接[26]),即(Maglev负载平衡器在Linux Kernel形式及Kernel Bypass形式下的性能比力,另一组来自mTCP(见链接[27]),即Linux多核系统下mTCP用户态协议栈形式(mTCP)、REUSEPORT形式(REUSEPORT)、REUSEPORTMultiprocess形式(Multiprocess)及根基形式(Linux)下系统的毗连吞吐量性能比力,经过旁观图7-1和图7-2中的两组数据我们可以对内核性能瓶颈有一个直观的印象。.

图7-1 Linux Kernel形式和Kernel Bypass形式下的Maglev吞吐

图7-2 分歧形式下多核系统的毗连吞吐量性能比力
不丢脸出,一方面,在只要一个CPU焦点的情况下,基于内核的计划在转发性能上不如Kernel Bypass计划;另一方面,在SMP/NUMA系统结构具有多焦点CPU的情况下,Kernel Bypass计划可以实现性能随CPU焦点数目的线性扩大,可是内核却很难做到。
LVS的焦点转发部分IPVS是在内核态实现的,虽然分歧的版本有PER-CPU毗连表、缩小锁的范围、报文尽早处置(pre_routeing)等优化手段,但对于高并发的负载平衡器来说,来自内核的性能题目仍然存在。
7.2.3 内核成为瓶颈的缘由
为什么内核会成为负载平衡器性能的瓶颈呢?总结下来,大致包括以下几个方面。
● 高低文切换。
● 资本同享与锁的利用。
● 中断风暴。
● 强大且复杂的收集协议栈。
● 数据复制。
下面来依次说明一下。
1.高低文切换
从广义上来说,高低文切换包括用户态/内核态的切换、多进程/线程高低文的切换等。高低文切换有一定的开销,应当只管避免频仍切换。假如需要进步性能,则利用法式可以挑选将使命和CPU焦点停止亲和性绑定,而非采用大量线程或进程的模子。就像Nginx中的Worker进程所做的,将Worker进程数目设备为利用的CPU焦点数,各个Woker进程之间对等且相互自力,每个Worker进程绑定一个CPU焦点,一个请求始终在同一个Worker进程中处置,从而将多进程间高低文切换的开销降到最低。
假如想更好地了解事务驱动模子和异步编程,则可以参考“C10K题目”及其对应的具体的实现:Nginx、Lighttpd、Libevent等。
2.资本同享与锁的利用
我们晓得,像UNIX、Linux这样的时分复用操纵系统的一个根基方针就是进步资本操纵率,使多个用户或多个进程/线程同时利用操纵系统的资本,而且让它们都以为自己“独占”了资本。经过量个进程/线程同享资本并分时切换的实现,一个CPU焦点可以并发履行多个使命。现代的SMP、NUMA等技术更是让多个进程/线程在物理上并行化。非论是什么形式,在有资本同享的情况下,一定要庇护资本,否则就会发生合作条件。
为了使同享资本不会被合作破坏,只能为其加上林林总总的锁,大概采用类似技术,如原子变量、内存屏障等。
加锁就意味着,当拿不到资本时只能期待(非论是切换进来等,还是忙等),这会形成CPU浪费,下降性能。在系统利用SMP或NUMA架构和进程、线程数目变多的情况下,上述CPU浪费的题目则加倍突出。虽然人们采用各类优化锁的技术,如读/写锁、spinlock、RCU、顺序锁等来削减锁对性能的影响,可是不管怎样个“锁”法,都不如“没锁”来得高效。
不外,从内核资本同享的本质上来看,不利用锁是不成能的。就内核的协议栈来说,虚拟装备需要锁、L2/L3/L4分用的表需要锁、Netfilter的Hook表需要锁、Conntrack需要锁、路由/ARP/IP地址需要锁、TCP/UDP层需要锁、Socket层需要锁、TC(qdisc)需要锁等。
究竟,UNIX/Linux是“通用目标操纵系统”,历来就不是为单个进程或某个特定高性能场景办事的“公用装备”而设想的,设想之初也没有斟酌要为SMP、NUMA多CPU焦点停止优化,多年来的性能提升和优化只能在资本同享、公允的条件下停止。比如,缩小锁的范围,利用合适的锁,有些地方甚至可以用PER-CPU的资本分派方式避免锁的利用。但毕竟太多资本同享了,不能破坏多用户、多使命、通用系统、公允这些大条件。是以,在某些特别的高性能范畴内,内核协议栈表示得不够高效就比力好了解了。这些范畴包括高速数据包转发、抗DDoS(Distributed Denial of Service,散布式拒绝办事)进犯等。
别的,硬件性能,如网卡性能逐步进步,网卡速度从100Mbit/s进步到1Gbit/s、10Gbit/s、25Gbit/s、100Gbit/s,硬件不再是性能的瓶颈。假如只是为了某个单一范例的利用,硬件是可以定制的。对于这类高性能要求的专有益用情况,为什么还要运转一个完整的操纵系统及其复杂通用的协议栈呢?
3.中断风暴
我们晓得,内核网卡驱动的收发包部分是经过硬件中断和下半部(bottom-half)软中断实现的,经过NAPI(New API)接口实现了“中断加轮询”的方式,一方面操纵中断来实时处置响应,避免对用户形成提早,另一方面为兼顾吞吐量等性能,每次软中断处置函数城市以一定的配额尝试轮询(polling)多个装备的报文。这类机制与各类硬件卸载(offload)和软件优化计划相连系,可以最大限度地兼顾大部分场景的延时和性能需求。
但是在高性能、高包转发率的特别收集利用处景下,这类形式仍然不够好,当收集I/O(特别是包转发率)很是大时,在Linux中经过top号令便可以看到CPU被大量消耗在软中断及其处置函数上。在理论中,我们可以设备“中断/CPU亲和性”,充实操纵网卡多行列和CPU多焦点的才能,只是收发包仍然会成为系统瓶颈。
关于中断风暴形成CPU浪费及性能瓶颈的题目,DPDK的答案是用轮询取代中断。为什么是“轮询”?提到轮询,大师首先想到:轮询间隔太短浪费CPU,轮询间隔太长会形成不需要的提早和收包不实时,怎样设备这个轮询间隔都欠好。可是,假如不斟酌CPU浪费,没有间隔,以“死循环”方式停止轮询,每次轮询时都尝试批量读取和处置数据,那末不但能处理提早题目,性能也能获得大幅提升。究竟这个CPU的焦点在于尽力停止包的接收和处置。
4.强大且复杂的收集协议栈
内核收集协议栈实现了太多的复杂功用,如Netfilter及相关的表和法则、Conntrack系统、各类百般的QoS(Quality of Service,办事质量)。这意味着一个数据包在内核中需要经过很多函数停止处置,途径很是长,看似细小的消耗会聚沙成塔。即使将每个函数都优化到极致,不去花费CPU太多时候,那末假如一个数据经过的函数挪用链太长,其累计的性能消耗也会比力大。如图7-3所示(图片来自ACM论文,见链接[28]),内核收集协议栈收发部分的高度能否是出格“高”?这是由于多层函数挪用累计的消耗所酿成的。在某些特别的场景下,实在不需要那末多功用。

图7-3 内核收集协议栈CPU火焰图
5.数据复制
在用户态和内核态之间停止间接的数据复制会非常消耗CPU的资本。当收集数据经过内核和用户空间鸿沟时,不单会发生系统挪用的开销,还会发生一次额外的数据复制的开销。假如从网卡DMA到内存,那末全部数据复制的处置进程中不存在额外的数据复制,则性能也可以获得不错的提升。Linux的Sendfile机制便可以避免这类数据复制开销。而Kernel Bypass计划可以避免内核态和用户态之间间接停止数据复制。
说明一下,数据复制对于内核态实现的LVS的性能的影响较小,由于内核态实现的IPVS是不需要把数据复制到用户态后再复制到内核态的。可是,对于在内核态下停止收发包,而在用户态下处置利用逻辑的上层利用办事,停止数据复制时CPU开销是一个不成疏忽的性能影响身分。我们只是指出数据复制很是影响性能,实现时要尽能够避免。
本文给大师讲授的内容是性能优化-性能应战与分析
- 下篇文章给大师讲授是高性能四层负载平衡关键技术
