一、背景
随着携程海外酒店业务的发展,遍布全球的海外供应商与携程总部IDC之间的数据传输量快速增长。技术上,这种日益增长的数据量对跨境网络专线的带宽、延迟等提出了更高的要求;业务上,由于当前有限的跨境网络专线资源对业务处理效率及用户体验也造成了一定的影响;成本上,跨境网络专线作为一种昂贵的资源,通过单纯的专线扩容又会给IT成本造成巨大压力。所以我们开始思考是否可以通过公有云结合酒店直连的业务特性来解决日益增长的带宽压力和供应商接口延迟的问题。
酒店直连系统主要是使用自动化接口实现供应商或集团与携程之间的系统对接,实现静态信息、动态信息、订单功能等都通过系统的方式流转交互。目前携程大量海外酒店业务是通过酒店直连系统对接。
想要了解更多亚马逊云科技最新技术发布和实践创新,敬请关注2021亚马逊云科技中国峰会!点击图片报名吧~
本文将主要从携程酒店直连服务迁移部署至亚马逊云科技过程中所进行的应用架构调整及云原生改造,使用亚马逊云科技后取得的技术和业务收益,在部署过程中对Amazon EKS(Amazon Elastic Kubernetes Service)、DNS查询延时和跨AZ流量降低所做的成本优化等几方面进行详细介绍。
二、痛点
携程酒店海外直连对接了上千家海外供应商,所有的接口访问都通过代理出去(见图1),由于酒店直连的业务特性,当一个用户请求过来时会根据人数、国籍、会员非会员等裂变成多个请求,最多的时候可能一个请求会裂变成数十个请求,而且请求报文十分巨大(通常为几十Kb到上百Kb不等),虽然我们可能只需要返回报文中的一小部分信息,但是因为目前架构的限制只能将所有报文全部请求回来再处理,这无疑浪费了大量的带宽。
图1
同时因为供应商遍布全球,所有的请求/响应都需要经过集团的代理出口,导致了部分供应商接口响应受到物理距离的影响延迟变高了,会降低用户的体验。
三、云服务选择及初步方案
本次核心目标之一是为了提高对接全球供应商的网络传输能力和延时改进,提升用户体验,必须选择一个在全球有广泛资源分布的云厂商帮助携程尽量靠近供应商访问数据。经过与多个公有云厂商的多轮交流,综合考虑各厂商技术水平、服务能力、成本价格等多方面因素,我们认为亚马逊云科技无论是在全球覆盖及网络能力(见图2)(亚马逊云科技在全球分布的25个区域和80个可用区提供广泛的服务能力,同时数据中心通过其骨干网互联,提升了未来不同数据中心的数据互访能力),云服务的先进性和成熟度、现场团队的服务能力、响应时间、专业水平都具有明显的优势,最终我们选择亚马逊云科技作为资源部署的云厂商合作伙伴。
图2
为了更好地与云上资源使用集成,我们采用IDC的容器化部署方案,最终考虑到托管容器平台的高可用性设计及SLA保证,及对社区的兼容性,使用亚马逊云科技托管容器平台Amazon EKS作为部署的平台。
资源方面我们对服务进行改造后,大量使用竞价实例作为Amazon EKS工作节点,大幅降低成本并提高效率。
同时利用公有云的网络和平台优势,将原本部署在携程总部IDC的相应业务服务部署到离供应商距离更近的海外公有云站点,实现携程与海外供应商之间高可靠、低延迟的网络直连,并将部分数据预处理逻辑剥离出来前置部署到海外公有云上,实现仅将经过处理的有价值的数据(而非原始、全量的裸数据)压缩后再传输到携程总部数据中心,进而达到降低对跨境网络专线的压力、提升业务数据处理效率、降低成本、优化用户体验等目标。
四、酒店直连上云经验
4.1 云业务应用的云原生改造
为了充分的使用云服务带来的便利和成本优化,经过调研分析,我们如果直接将应用迁移至公有云上,虽然业务上会产生相应的价值,但成本会相对较高,因此我们对酒店直连服务进行了相应的云原生架构优化,相关的主要调整如下:
1 )访问供应商模块上云
要节省带宽需要减少通过从代理出去的请求同时减少每个请求的报文大小。我们的做法是将请求拆分的逻辑搬到亚马逊云科技上,这样每次一个用户请求过来通过代理出去只有一次请求/响应。同时我们在亚马逊云科技上将供应商返回的报文中无用属性剔除,然后再根据业务属性合并相关节点最后再压缩返回,这样就达到了缩减报文大小的目的(见图3)。从目前运行的数据上看,整个代理的带宽流量只用到了之前的30%~40%。
图3
公有云厂商普遍采用按流量收费的价格策略,在设计网络出入站网络访问的技术方案过程中,默认情况下会使用亚马逊云科技NAT网关,这样网络流量费用相对较高。考虑到酒店直连请求有个特性,通常情况下请求报文不到1K,而响应报文平均有10k到100K,利用这个特点,我们在亚马逊云科技上采用了基于Amazon EKS自建Squid代理方案(见图4),这样只有出站的请求报文会产生流量费用,而大量入站的响应报文不收费,从而大大降低亚马逊云科技上产生的网络流量费用。
图4
2)降低网络延迟,利用亚马逊云科技全球数据中心对供应商就近访问
很多海外的供应商服务部署在全球各地,而我们所有的海外访问都统一从代理出去,这样一些服务器部署较远的供应商因为物理距离上的原因导致网络延迟很高。通过亚马逊云科技的在全球各地的数据中心,我们可以将服务就近部署在供应商机房附近,同时利用亚马逊云科技的骨干网络降低各数据中心到代理所在地附近的亚马逊云科技数据中心的延迟,最后通过专线连接该亚马逊云科技数据中心与携程IDC(见图5),整个过程对那些因物理距离对网络延迟影响较大的供应商性能提升较明显,最多可降低50%的响应时间。
图5
4.2 持续的架构改造和性能及成本优化
在目前的方案中,我们为了上云单独开发了一套全新的应用,这样带来的问题就是,当有业务变更时我们同时需要调整携程IDC和亚马逊云科技上部署的两个应用,提高了系统维护成本。主要原因是原应用中大量依赖携程的基础组件,本次上云尝试使用的是完全独立的账号和VPC网络,如果在云上同样部署一套不太现实,一是成本太大,二是一些敏感数据不能放在在云端存储,所以后续我们会对适配器架构再进行优化,在不依赖携程基础组件的情况下复用一套应用以适应不同的云环境。
业务上线后为了验证未来更大规模的负载上云的可能性,我们同时也在对性能,成本,高可用性方面做持续不断的优化。
4.2.1 利用云弹性伸缩能力
以计算资源成本为例:计算实例成本 = 实例运行时长 * 实例价格。如果只是简单粗暴把本地机房的运行模式套用到云上计算,云服务计算资源的费用是高于本地机房的。所以我们需要充分利用云上按需收费的特性,减少闲置资源成本。实例的运行时长和Kubernetes集群内的服务数量,以及分配给这些服务的计算资源成正比,同时服务的数量又是和流量成正比。
酒店直连业务场景存在不可预测的业务流量,比如临近节假日颁布的旅游政策,或者营销直播活动。云原生的弹性特性很好地利用合理的资源应对突发的流量。
Kubernetes的HPA弹性架构会实时采集集群整体的负载指标,判断是否满足弹性伸缩条件和执行pod的伸缩。仅仅是pod的伸缩还不够,我们还需要在集群中使用Cluster Autoscaler组件,监控集群中由于资源分配不足无法被正常调度的pod,自动从云平台的实例池中申请增加节点,同时在流量下降的时候,Cluster Autoscaler组件也会检测集群中资源利用率较低的节点,将其中的pod调度到其他可用节点上,回收这部分闲置节点。
弹性伸缩案例
云原生的弹性特性不仅帮助减少资源使用成本,也提高服务对基础架构故障的容错率,在基础设施部分可用区中断不可用期间,其他可用区域会增加相应数量的节点继续保持整个集群的可用。
Kubernetes支持对pod容器所需的CPU和内存调整,找到一个合理的配额以合理的成本达到最佳的性能。所以我们在服务上云前会做一些接近真实环境的负载测试,观察业务流量的变化对集群性能的影响(业务周期性高峰和低峰的资源使用率,服务的资源瓶颈,合适的余量资源buffer应对尖刺流量等等)。既不会因为实际利用率过高导致稳定性问题,比如OOM或者频繁的CPU throttling,也不会因为过低浪费资源(毕竟,即使你的应用只使用了实例的1%,也要支付该实例100%的费用)。
4.2.2 采用公有云竞价实例
某些云平台会把一些闲置计算资源作为竞价实例,以比按需实例更低的定价出租,顾名思义竞价实例的最终费用是按市场供需出价决定的。按照我们实际使用的体验,如果不是特别热门的机型定价基本在按需实例费用的10-30%左右。低价的竞价实例自然有它的限制,云平台会可能会调整竞价实例池的资源比例回收部分实例,一般回收的概率根据统计通常<3%, 同时在回收前会提前2分钟通知到这些实例。我们通过亚马逊云科技提供的Terminal handler组件在收到回收通知后提前把容器调度到其他可用的实例上,减少了资源回收对服务的影响。下图是某云对竞价实例的资源池划分,我们可以看到,即使相同的实例资源,在不同的可用区也是独立的资源池。
图6
为了能最大限度减少竞价实例的中断影响,包括实例在多可用区的再平衡影响,我们在通过Amazon ASG(Amazon Auto Scaling Group 弹性扩展组)选择不同实例类型的情况下还将不同的实例资源池独立使用Amazon ASG进行管理,这样保证了资源的最大利用效率。
图7
携程酒店直连使用按需实例和竞价实例的混合部署,保证低成本和高可用。一些系统关键组件(比如Cluster Autoscaler),中断就会丢失数据的有状态服务(比如Prometheus)运行在按需实例。而对错误容忍度高,使用灵活无状态的业务应用运行在竞价实例上。通过kubernetes的节点亲和性控制不同类型的服务调度到对应类型标签的实例上。(见图8)
图8
通过 Kubernetes 原生的 HPA 和 Cluster Autoscaler 组件结合 Amazon ASG 及竞价资源的充分利用,可以将成本降低50%-80%。
4.2.3 DNS 解析性能优化
当服务规模逐渐增大的时候,我们发现服务间的调用延时明显上升,平均达到1.5S,高峰达到2.5秒,经过分析发现,主要是因为 DNS 解析负载过高造成的性能解析瓶颈,最终我们采用社区比较主流的 localdns 方式,对热点解析域名做本地缓存,来降低对核心 DNS 频繁的解析请求从而提高性能:
图9
如图9所示,在每个Node部署基于DaemonSet的NodeLocal DNSCache,通过Node LocalDNS缓解CoreDNS服务的DNS查询压力,LocalDNS Cache 会监听所在的 node上每个 Client Pod 的 DNS 解析请求,通过本地的解析行为配置,Local DNS Cache 会尝试先通过缓存解析请求,如果未命中则去 CoreDNS 查询解析结果并缓存为下一次本地解析请求使用。
如下图,通过使用 LocalDNS 方案我们将高峰的延时从 2.5S 降低到 300ms,缩短了80%的响应时间:
未使用LocalDNS前,平均响应在1.5-2.5S。
未优化前
使用LocalDNS 方案后,响应请求降低到300-400ms,延时优化了80%。
优化后
4.2.4 公有云跨可用区流量优化
在使用竞价实例对资源进行大幅优化后,我们注意到跨可用区的流量在服务大幅扩展后占比非常高(60%),这是因为在服务之间调用时,我们将服务单元部署到不同可用区,最大限度提高服务的可用性,同时带来的问题是服务间大量的流量交互带来了跨可用区的流量费用(见图10)。
图10
但是为了整个系统的高可用性,我们并不想将服务部署在单可用区,降低服务SLA。我们需要降低跨可用区流量的同时保证服务的高可用性。
经过不同的方案调研最终我们使用 Amazon NLB 来暴露服务,通过Amazon NLB 的 disable cross-az 功能,对同可用区的上下游服务进行流量可用区管控。同时使用之前提到的 local dns 组件,将上游服务访问Amazon NLB不同可用区的域名解析进行固化,保证了上下游的服务流量只能在可用区内部进行互通。改造后如下图:
图11
后段服务因为会通过 K8s 的 Kube-proxy 进行转发造成跨可用区跨节点,我们选择使用 externalTrafficPolicy 本地策略,将转发流量固化在本地节点的服务上,但是同时本地转发策略也带来了一些问题(见图12):
图12
如上图所示,本地转发策略可能因为后端服务分布不均衡导致了流量黑洞和服务负载的不均衡,所以在这个基础上,我们利用Amazon EKS 弹性扩展组策略对底层节点资源均衡分布到不同的可用区,同时利用 K8s 反亲和性策略,将服务尽量分布到不同可用区的节点上,最大程度的保证了流量的均衡性,同时保证了服务的跨可用区部署的高可用性。
优化后跨可用区流量降低了95.4%。(见图13)
图13
五、后续的优化改进方向
目前的架构虽然解决了我们业务上的一些问题,但还是有一些不足之处可以改进。为了可以就近访问供应商,我们使用了一个独立的VPC网络来部署和测试我们的集群,所以需要单独在云端部署相关的存储依赖以及日志监控组件,这样无疑增加了运维的难度以及服务在不同云上的迁移难度。
在最新的架构设计中针对这个问题我们计划做如下改造,首先将需要在云端计算并且依赖持久化存储数据的功能迁移回携程IDC,这样这部分数据就不用再传到云端。其次因为公司在亚马逊云科技的其他数据中心已经有一套成熟的环境,所以我们只需要配合OPS打通两个亚马逊云科技数据中心之间的VPC网络,便可使用公司的日志和监控框架,减少运维成本。
六、总结
本文通过携程酒店直连在云原生的实践,分享了如何快速在云上搭建一套稳定高效的生产环境实现快速交付、智能弹性,以及在云上的一些成本优化经验。借助云原生体系实现了基础设施自动化,释放一部分的运维工作,可以更多地投入到业务迭代,更敏捷地响应业务需求迭代,通过监控和日志实现快速试错和反馈。希望借此能帮助到更多想上云的团队,少走弯路,拥抱云原生带来的好处。
本篇作者
微末
携程软件技术专家
关注系统架构,致力于高可用高性能的支撑业务系统开发。