欢迎您光临本站,如有问题请及时联系我们。

给高并发降温,美团高性能、高可靠四层负载均衡MGW优化实践

  近日,在51CTO以“TechNeo”为主题的第十五期技术沙龙中,邀请了来自美团云负载均衡网关MGW产品研发负责人王伟。他拥有多年负载均衡系统的一线实施经验,主导并推进MGW(美团四层负载均衡)的技术选型以及性能优化工作。


  MGW


  通过本文,我们可以了解到承载美团点评数十Gbps的流量、上千万的并发连接的MGW如何实现高性能、高可靠的详尽优化过程等。


  负载均衡的作用及分类

  互联网初期阶段,业务逻辑简单、流量不大,单台服务器就可满足日常需求。随着互联网的发展,业务不仅会流量爆发、逻辑越来越复杂且对可靠性的需求也逐步递增。


  这时,就需要多台服务器来应对单台服务器在性能、单点等方面凸显出来的问题,进行性能的水平扩展和灾备。但客户端的流量要如何顺利访问到这么多不同的服务器是个问题。


  对于这个问题,可选择使用DNS做负载,对客户端不同IP地址进行解析,使得流量直接到达不同的应用服务器。


  但这个调度策略相对简单却不能很好的满足业务需求,当改变调度策划后,DNS各级节点的缓存不能及时在客户端生效,会导致很严重的延时性问题。这时可选择使用负载均衡,如下图:


  DNS


  如图所示,客户端的流量先到达负载均衡服务器,再由负载均衡服务器采用一些调度算法,把流量分发到不同的应用服务器。


  与此同时,负载均衡服务器对应用服务器进行周期性健康检查,一旦查出故障节点,直接剔除,进而保证应用的高可用。


  负载均衡分为四层和七层两种,如下图:


  负载均衡


  四层负载均衡

  核心是转发,收到客户端流量,对数据包地址信息进行修改后,转发到应用服务器,整个过程均在OSI模型的传输层完成。


  七层复杂均衡

  核心是代理,当接收到客户端的流量后,通过完整的TCP/IP协议栈对应用层流量进行解析。之后,基于调度算法选择合适的应用服务器,并与应用服务器建立连接将请求发送,整个过程在OSI模型的应用层完成。


  四层负载均衡的转发模式

  转发是四层负载均衡的主要工作,目前主要有四种转发模式:


  DR模式。

  NAT模式。

  TUNNEL模式。

  FULLNAT模式。

  如下是四种转发模式的优缺点对比图表:


  从图中可以直观的看到四种转发模式的优缺点:


  DR模式(三角传输)的实现方式是修改数据包的目的MAC地址。

  NAT模式的实现方式是修改数据包的目的IP地址。

  TUNNEL模式的实现方式和DR相同,但要求应用服务器必须支持TUNNEL功能。

  美团点评最终选择FULLNAT作为MGW的转发模式,它是在NAT模式的基础上做一次源地址转换(即SNAT)。


  此模式的优势在于可使应答流量经过正常三层路由回归负载均衡,负载均衡就不需以网管的形式存在于网络中,进而降低了对网络环境的要求。不足之处在于做SNAT,应用服务器会出现丢失客户端的真实IP地址的情况。


  如下图,是FULLNAT转发模式的具体实现流程:


  FULLNAT


  如图在负载均衡上布设localip池,做SNAT的过程中,源IP取自其中。当客户端流量到达负载均衡设备,负载均衡依据调度策略在应用服务器池中选择一个应用服务器,将数据包的目的IP改为应用服务器IP。


  同时从localip池中选择一个localip将数据包的源IP改为localip,这样应用服务器在应答时,目的IP是localip,而localip是真实存在于负载均衡上的IP地址,因此可以经过正常的三层路由到达负载均衡。


  与NAT模式相比,FULLNAT模式会多做一次SNAT,过程中还有选端口的操作,在性能方面要稍弱于NAT模式,但FULLNAT模式在网络适应性方面要占优势。


  采用四层负载均衡的原因

  为什么美团点评会选择自研的四层负载均衡呢?主要有两个原因:


  业务流量递增,LVS出现性能瓶颈及运维成本的上升。

  采用硬件负载均衡,成本是门槛。

  LVS方面,美团点评最初的方式是使用LVS做四层负载均衡、Nginx做七层负载均衡。


  Nginx


  如上图所示,流量高速增长,LVS在性能上出现瓶颈,故障率增加。


  在硬件负载均衡方面,凸显出来的问题有三方面:


  异常高的硬件成本

  人力成本。

  时间成本。

  综合这两个原因,美团点评决定自研四层负载均衡MGW来替换LVS,MGW需要满足高性能、高可靠两个特性。那么如何实现高性能、高可靠呢?


  MGW实现高性能的四大问题和解决方法

  对比LVS的一些性能瓶颈,我们可以直观了解MGW实现高性能的解决方法。这里主要涉及LVS遇到的中断、过长的协议栈路径、锁和上下文切换这四大问题。


  MGW应对这些问题的解决办法分别是PMD驱动、Kernelbypass、无锁的设计和CPU绑定、隔离。


  1.中断


  LVS是做在内核中的,而内核在设计时要兼顾通用性,所以采用中断的方式感知流量的接收。


  中断对LVS性能的影响非常大,如果每秒处理500万数据包,每5个数据包产生一个硬件中断,那么一秒会产生100万个硬件中断,每一次产生的硬件中断都会打断正在进行密集计算的负载均衡程序,中间产生大量的cachemiss,这对性能的影响非常大。


  2.过长协议栈路径


  因为LVS是基于内核netfilter开发的应用程序,而netfilter是运行在内核协议栈的一个钩子框架。


  当数据包到达LVS时,要经过一段很长的协议栈处理。实际情况是负载均衡在接到流量以后,只需对MAC、IP、端口进行修改发出即可,并不需要这段处理来增加额外的消耗。


  LVS


  针对中断和过长协议栈路径这两个问题的解决方法是采用由DPDK提供的用户态PMD驱动以及做Kernelbypass。


  DPDK在设计过程中,使用了大量硬件特性,如numa、memorychannel、DDIO等对性能提升很大。同时提供网络方面的库,进而减小开发难度,提升开发效率。


  这些都是美团点评选择DPDK作为MGW的开发框架的因素。


  3.锁


  内核是较通用的应用程序,为了兼顾不同硬件,在设计过程中会加一些锁。而自主研发只需对某些特定场景进行定制设计,不用兼顾很多硬件,进而通过一些方法去掉锁,实现完全无锁的状态,方便后续扩展。


  先来看看什么情况需要进行锁的设计,首先介绍一下RSS(ReceiveSideScaling)。


  RSS是一个通过数据包的元组信息将数据包散列到不同网卡队列的功能,这时不同CPU再去对应的网卡队列读取数据进行处理,就可充分利用CPU资源。


  MGW使用的是FULLNAT模式,会将数据包的元组信息全部改变。


  这样同一个连接,请求和应答方向的数据包有可能会被RSS散列到不同的网卡队列中,在不同的网卡队列也就意味着在被不同的CPU进行处理,这时在访问session结构就需要对这个结构进行加锁保护。


  解决这个问题,一般情况下有如下两种方案:


  在做SNAT选端口时,通过选择一个端口lport0让RSS(cip0,cport0,vip0,vport0)=RSS(dip0,dport0,lip0,lport0)相等。

  为每个CPU分配一个localip,做SNAT选IP时,不同CPU选择自有的localip,当应答回来后,再通过lip和CPU的映射关系,将指定目的IP的数据包送到指定队列上。

  由于第二种方法恰好可被网卡的flowdirector特性支持,因此MCW选择第二种方法来去掉session结构的锁。


  CPU


  flowdirector可依据一定策略将指定的数据包送到指定网卡队列,其在网卡中的优先级要比RSS高,因此在做初始化的时候就为每个CPU分配一个localip。


  如为cpu0分配lip0,为cpu1分配lip1,为cpu2分配lip2,为cpu3分配lip3。


  当一个请求包(cip0,cport0,vip0,vport0)到达负载均衡后,被RSS散列到了队列0上,这时这个包被cpu0处理。


  cpu0在对其做fullnat时,选择cpu0自己的localiplip0,然后将数据包(lip0,lport0,dip0,dport0)发到应用服务器,在应用服务器应答后,应答数据包(dip0,dport0,lip0,lport0)被发到负载均衡服务器。


  这样就可以在flowdirector下一条将目的IP为lip0的数据包发送到队列0的规则,这样应答数据包就会被送到队列0让cpu0处理。


  这时CPU在对同一个连接两个方向的数据包进行处理的时候就是完全串行的一个操作,也就不需再对session结构进行加锁保护。


  4.上下文切换


  针对上下文切换的问题,MGW设计有对CPU进行分组,实现控制平面与数据平面完全分离的状态,可以很好的避免数据平面做处理时被打断的现象,如下图所示:


  MGW


  同时,对数据平面CPU进行隔离,实现控制平面进程不会调度数据平面这组CPU;对数据平面线程进行CPU绑定,实现每个数据线程独占一个CPU。


  控制平面的程序均跑在控制平面的CPU上,如Linuxkernel、SSH等。


  MGW实现高可靠的解决方法

  1.MGW集群


  集群的高可靠主要涉及三部分:


  session同步。

  故障切换。

  故障恢复与扩容。

  如下图所示,MGW采用ECMP+OSPF的模式组成集群:


  MGW集群


  ECMP的作用是将数据包散列到集群中各个节点,再通过OSPF保证单台机器故障以后将这台机器的路由动态的剔除出去,这样ECMP就不会再给这台机器分发流量,也就做到了动态的failover。


  session同步

  传统ECMP在算法方面存在一个严重问题,当复杂均衡集群中节点数量发生变化时,会导致大部分流量的路径发生改变。


  当发生改变的流量到达其他MGW节点上,找不到自身的session结构,就会导致大量的连接出现异常,对业务影响很大,且当在对集群做升级操作时会将每个节点都进行一次下线操作,这样就加重了这个问题的影响。


  传统的解决方式是使用支持一致性hash的交换机,如下图所示:


  交换机


  当节点发生变化的时候,只对发生变化的节点上面的连接会有影响,其他连接都会保持正常,但是支持这种算法的交换机比较少,并且也没有完全实现高可用。


  因此需要做集群间的session同步功能,如下图所示:


  session


  集群中每个节点都会全量的将自身session进行同步,使集群中每个节点都维护一份全局session表。当节点发生变化,流量路径无论发生任何形式的改变,流量都可以找到自身的session结构。


  故障切换与故障恢复及扩容是在做集群间的session同步功能的整个过程中首要考虑的两大问题。


  故障切换

  针对故障切换问题,当机器发生故障后,交换机可立刻将流量切到其他机器,避免大量丢包的情况。


  经过调研测试,MGW采用如下图所示的操作方法,可做到升级操作0丢包,主程序故障0丢包,其他异常(网线等)会有一个最长500ms的丢包,因为这种异常需要靠自检程序去检测,而自检程序的周期是500ms。


  具体包括如下四方面内容:


  交换机侧不使用虚拟接口。全部使用物理接口且服务器侧对接口进行断电时,交换机会瞬间将流量切换到其他机器。

  通过100ms发两个包的测试(客户端和服务端各发一个),表明这种操作方法可实现0丢包。


  半秒一次机器健康自检。故障切换主要依赖于交换机的感知,当服务器上出现异常,交换机感知不到时,交换机就无法进行故障切换操作。

  因此需要一个健康自检程序,每半秒进行一次健康自检,当发现服务器存在异常时就对服务器执行网口断电操作,从而将流量立刻切走。


  检测到故障自动给网口断电。故障切换主要依赖于网口断电操作且网卡驱动是跑在主程序里面的,当主程序挂掉以后,就无法再对网口执行断电操作。

  主进程会捕获异常信号。针对主程序挂掉后,就无法再对网口执行断电操作的现象,主进程会捕获异常信号,当发现异常时就对网卡进行断电操作,在断电操作结束后再继续将信号发给系统进行处理。

  故障恢复与扩容

  系统进行故障恢复、扩容操作时,会使得集群节点数量发生变化,进一步导致流量路径发生变化。


  因为已经发生变化的流量到达集群中原有节点时,原有节点都维护一个全局session表,所以这些流量是可以被正常转发的;但当流量到达一个新机器,这台新机器由于没有全局session表,这部分流量会全部被丢弃。


  针对这个问题,MGW在上线后会经历预上线的中间状态,此状态下,MGW不会让交换机感知到自己上线,所以交换机也就不会把流量切过来。


  实现流程是首先MGW会对集群中其他节点发送批量同步的请求,其他节点收到请求以后会将自己的session全量同步到新上线的节点,新上线节点在收到全部session以后才会让交换机感知到自己上线,这时交换机再将流量切入,就可正常被转发。


  这里需要提醒两点:


  由于集群中并没有一个主控节点来维护一个全局的状态,如果request报数据丢失或者session同步的数据丢失的话,那么新上线节点就没办法维护一个全局的session状态。

  但考虑到所有节点都维护着一个全局的session表,因此所有节点拥有的session数量都是相同的,那么就可以在所有节点每次做完批量同步以后发送一个finish消息,finish消息中带着自己拥有的session数量。


  当新上线节点收到finish消息以后,便会以自己的session数量与finish中的数量做对比。当达到数量要求以后,新上线节点就控制自己进行上线操作。否则在等待一定的超时时间以后,重新进行一次批量同步操作,直到达到要求为止。


  在进行批量同步操作时,如果出现新建连接,那么新建连接就不会通过批量同步同步到新上线的机器上。如果新建连接特别多,就会导致新上线机器一直达不到要求。

  因此,需要保证处于预上线状态的机器能接收到增量同步数据,因为新建连接可以通过增量同步同步出来。通过增量同步和批量同步就可以保证新上线机器可以最终获得一个全局的session表。


  2.MGW单机


  自动化测试平台

  单机高可靠方面,MGW研发了自动化测试平台,通过连通性和配置的正确性来判断一个测试用例是否执行成功,失败的测试用例平台可以通过邮件通知测试人员。


  在每次新功能迭代结束以后,都会将新功能的测试用例加到自动化平台里面,这样在每次上线之前都进行一次自动化测试,可以大大避免改动引发的问题。


  自动化测试


  在这之前,每次上线之前都需要进行一次手动的回归测试,回归测试非常耗时并且很容易遗漏用例,但是为了避免改动引发新问题又不得不做,有了自动化测试平台以后,可提升回归测试的效率和可靠性。


  3.应用服务器


  在应用服务器靠性方面,MGW布设节点平滑下线和一致性源IPHash调度器两大功能。


  节点平滑下线

  服务器


  节点平滑下线功能主要是为了解决当用户需要对RS进行升级操作时,如果直接将需要升级的RS下线,那这个RS上存在的所有连接都会失败,影响到业务。


  此时如果调用MGW的平滑下线功能,MGW就可以保证此RS已有连接正常工作,但不会往上面调度新的连接。


  当所有已有连接结束以后,MGW会上报一个结束的状态,用户就可以根据这个结束的状态对RS进行升级操作,升级后再调用上线接口让这个RS进行正常的服务。


  如果用户平台支持自动化应用部署,那就可以通过接入云平台使用平滑下线功能,实现完全自动化且对业务无影响的升级操作。


  一致性源IPHash调度器

  IPHash调度器


  源IPHash调度器主要是保证相同的客户端的连接被调度到相同应用服务器上,也就是说建立一个客户端与应用服务器一对一的映射关系。


  普通源IPHash调度器在应用服务器发生变化以后会导致映射关系发生改变,会对业务造成影响。


  一致性源IPHash调度器,保证在应用服务器集群发生变化时,只有发生变化的应用服务器与客户端的映射关系发生改变,其他保持不变。


  为了保证流量的均衡,首先在Hash环上分配固定数量的虚拟节点,然后将虚拟机节点均衡的重分布到物理节点上,重分布算法需要保证:


  在物理节点发生变化时,只有少数虚拟节点映射关系发生变化,也就是要保证一致性Hash的基本原则。

  因为MGW是以集群的形式存在的,当多个应用服务器发生上线、下线操作时,反馈到不同的MGW节点上就有可能会出现顺序不一致的问题。

  因此无论不同的MGW节点产生何种应用服务器上下线顺序,都需要保证最终的映射关系一致,因为如果不一致就导致相同客户端的连接会被不同的MGW节点调度到不同的应用服务器上,也就违背源IPHash调度器的原则。


  技术展望

  未来,美团点评将主要在这三方面发力:升级自动化、集中式配置管理和降低运维成本。


  升级自动化。最初自研MGW是为解决LVS的性能问题,在这些问题被解决之后,随着业务的快速发展,IDC不断增长,负载集群越来越多,像某个新IDC上线,一般都要上线两套集群,分别用于IDC入口和内部业务。

  这样的情况下,又涌现出更大的问题,如一个新功能发布时,周期会非常长,所以需要实现自动化升级。当然,在完善监控措施方面也要同步,对异常进行监控。


  集中式配置管理。目前业务配置已经实现集中式配置,未来希望机器的配置也能实现。

  更低的运维成本。实现自动化升级,集中式配置最根本的目的就是降低运维成本。


来源:本文由E8运维原创撰写,欢迎分享本文,转载请保留出处和链接!