数百万用户在全球每天使用优步的应用程序,在按下按钮时访问无缝运输或膳食送餐。为了以缩放实现此类可访问性,无论客户使用我们的服务,我们的移动应用程序都需要低延迟和高度可靠的网络通信。
优步所有移动应用程序的网络通信都由edge和移动网络基础设施提供动力。edge基础设施为从移动应用程序发送到后端服务的HTTPS流量提供安全连接。优步的edge基础设施结合了公共云平台的全球存在,帮助减少应用程序延迟,当需要提高可靠性时,还可以回退到我们自己管理的数据中心。
在移动端,我们的网络堆栈的核心组件是故障处理程序,它智能地将所有移动通信从我们的应用程序路由到边缘基础设施。优步的故障处理程序被设计成有限状态机(FSM),以确保通过云基础设施发送的流量最大化。当云基础设施不可达时,故障转移处理器动态地将流量直接重新路由到优步的数据中心,而不会显著影响用户的体验。
在优步推出故障转移处理程序后,我们发现与以前的解决方案相比,HTTPS流量的尾部延迟减少了25% - 30%。故障转移处理程序还确保了在公共云基础设施面临中断期间,HTTPS通信的错误率相当低。综合起来,这些性能改进为全球市场带来了更好的用户体验。
在本文中,我们分享设计Uber应用程序的移动故障转移处理程序所面临的挑战,以及设计如何在全球用户在用户中运行系统时进化。
优步的边缘基础设施
优步的边缘基础设施包括终止安全TLS的前端代理服务器TCP.要么QUIC来自移动应用程序的连接。然后,使用这些连接的移动应用程序的HTTPS流量将使用现有的最近数据中心的后端服务转发到后端服务连接池。edge基础设施跨越公共云和私有管理的基础设施,如下图1所示,前端代理托管在公共云区域和优步管理的数据中心:
在公共云上托管边缘服务器使我们能够利用其广泛部署的网络存在点或持久性有机污染物。终止通常更靠近用户的Quic / TCP连接导致性能更好,转化为HTTPS流量的降低延迟和错误率。此外,云的前端服务器还支持更新,更多高性能协议在网络条件不足期间,进一步降低了延迟。因此,我们至关重要,我们通过云区域最大化来自移动设备的HTTPS请求的数量,以确保最佳的用户体验。
但是,如果App请求始终路由到云,则在本地和全局级别中断期间,我们会危险具有重要的服务中断。这种连接问题可以是由于到公共云的各种组成部分或中间ISP。由于DNS服务,负载均衡器,BGP路由,网络中间盒,云推出等的MIS配置导致的问题可能导致DNS或Quic / TCP连接超时。发生中断时,优步的平台必须具有动态故障转移和重新路由传入请求的能力,以确保不间断服务。
云和数据中心托管的前端服务器已注册为不同域名。通过选择最合适的域名,移动应用程序可以通过云区域或直接向超级数据中心路由请求。
移动故障转移处理
为促进用户对用户的高度性能和可靠的应用体验,我们构建了一个内部故障转移处理程序,该处理程序驻留在移动网络堆栈中,作为放置在核心HTTP2 / Quic层上方的拦截器。随着HTTPS请求从应用程序生成,它们通过故障转移处理程序,在核心HTTP库处理之前重写域名(或主机名)。这可确保HTTPS流量可以动态路由到适当的边缘服务器。
异步,故障转移处理程序不断监视域的运行状况,并根据从HTTPS响应所需的错误来切换域。确定何时切换域的逻辑是故障转移处理程序的核心组件,以及本文中的讨论的主要主题。
故障转移处理程序使用网络错误进行HTTPS响应作为检测到域的可达性问题的信号。设计故障转移处理程序时的根本挑战在用户端的错误之间区分由于移动连接失败和由于边缘基础设施不可用或无法访问而导致的错误。由于Uber应用程序的蜂窝/ LTE网络的高度使用,特别是在全球范围内,因此该问题进一步加剧。移动网络是不那么可靠和稳定比他们有线同行,容易发生间歇性失败,连接问题和拥堵。
接收我们主域的临时DNS错误或Quic / TCP连接超时(云区内托管的边缘服务器的域名)并不一定意味着它不可用;在大多数情况下,这种故障实际上是由于连通性间歇性损失。例如,想象一下,进入隧道并失去移动服务。在这样的场景中,将域从主域切换到备份域并没有帮助,可能导致降低连接恢复后的性能。
基于Robin的故障转移处理程序
我们测试的一些直率解决方案未能有效地解决这一挑战。我们的故障转移处理程序的早期迭代使用了一个基于Robin的系统,配置了一个域列表。第一域是提供最佳性能的主要域。主域之后是备份域,通常是Uber的托管数据中心服务器,以确保当主域不可用时退回的能力。在接收特定的网络错误 - DNS错误,超时,TCP / TLS错误等,因此系统将域切换到列表中的所有后续HTTPS请求中的下一个。
虽然这款循环解决方案满足了我们的可用性要求,但它有一些关于性能的缺点:
- 积极的主机开关:一些间歇网络错误导致系统切换域。过度切换域可能导致不必要的DNS查找和连接设置导致额外的延迟。
- 大量请求路由到非性能域:如果在网络错误的情况下,系统在网络恢复后,系统将在列表中的一个域中置于列表中的一个域。尽管正在提供主要领域,我们看到显着的会话在较低的备用域中定居。在另一轮网络错误之后,该系统将仅转回主域。
基于阈值的故障处理程序
为避免过度域切换,我们还尝试了基于阈值的故障转移处理程序。而不是基于单个网络错误触发故障转移,而是基于阈值的解决方案仅在遇到最小数量的网络错误之后切换域。但是,它证明很难找到跨越不同应用,地区和网络类型(LTE,WiFi等)有效工作的阈值。将值设置得太低导致不必要的切换,但在主域实际上不可用的情况下将其设置过高延迟恢复。此外,该系统并未完全解决先前方法的缺点。
Edge-driven故障转移处理
优步的边缘基础架构具有自动恢复机制来缓解域故障,例如DNS重新映射。在这种情况下,我们的主域上的过度错误触发了域名的重新配置到受影响域的IP地址映射。DNS传播不是瞬间,因为修改后的映射必须在全局所有DNS名称服务器上传播。
通常,主域的不可达性也仅限于一个小地区、一个城市或特定的移动运营商,仅通过DNS映射更新无法有效缓解。移动应用程序有更好的连接条件上下文,可以实时作出反应。因此,我们确定除了边缘驱动的故障转移处理机制外,还需要设备本地故障转移处理程序来确保连接性。
故障处理程序设计
在设计UBER的故障转移处理程序时,我们希望确保我们达到我们评估的现有解决方案缺乏的三个主要标准:
- 最大限度地使用主域:我们需要我们的故障转移处理解决方案来以优先路由到主要域的流量的方式运行,这通常提供最佳性能。最大化通过这些域的HTTPS流量的量可确保降低延迟和更好的用户体验。
- 有效区分网络错误和主机级中断:系统需要一个强大的机制,可以自信地识别实际域故障,并由于间歇移动网络连接问题而降低交换到备用主机的概率。
- 减少主域中断期间的降级体验:我们的故障转移处理系统还需要最大化备份域的使用,当主主机不可用或无法访问时。
为了满足这些需求,我们将故障转移处理程序设计为有限状态机(FSM),如下图2所示:
系统努力在两种稳定状态下运行:primary_state.,其中主域用于路由HTTPS流量,以及BACKUP_STATE,其中使用其中一个备用域。系统努力始终运行primary_state.,除非有可能是主要领域停机的可能性。两个中间状态,FAILOVER_STATE和Recovery_state.,确保过渡primary_state.至BACKUP_STATE(反之亦然)是非常有信心的。
primary_state.
primary_state.是默认和期望的状态。在此状态下,主域用于所有HTTPS请求。如果没有故障,或者只有几个间歇性失败,则不会发生状态更改。虽然在这种状态下,跟踪持续失败计数以帮助过渡到FAILOVER_STATE。这里的失败是指HTTPS响应所接收的错误,例如DNS错误,TCP / QUIC连接错误或超时。
该FAILOVER_STATE达到故障转移条件(即,“x”连续故障超过“Y”间隔)。在此状态下,所有HTTPS请求仍然在主域上发送。为了确保系统对阈值的值(“x”和“y”的值不敏感,并提高识别域故障的置信对设备连接错误,我们利用了金丝雀请求。金丝雀请求是对健康端点的专用HTTPS请求(休息边缘服务器的API。金丝雀请求通过备份域列表发送,直到第一个成功,此时系统转换到BACKUP_STATE。
当处于FAILOVER_STATE时,如果从使用主域的常规请求接收到成功响应,则状态会变回primary_state.。如果主域上的错误是由于移动网络中的连接问题造成的,则很可能发生这种情况。引入canary请求降低了在网络连接较差期间故障转移到备份域的可能性。
BACKUP_STATE
如果系统改为接收到成功的金丝雀响应FAILOVER_STATE,它转换到BACKUP_STATE,并开始为所有HTTPS请求使用备份域。如果主域不可用或对该用户会话不可达,系统通常会达到这种状态。
当系统在Backup_State中运行时,在它可能已恢复的情况下连续检查主要域的运行状况非常重要。因此,在Backup_state中,系统维护一个恢复计时器,过渡到了Recovery_state.当定时器超时时。在Recovery_state.,Canary请求被触发到主域,而常规的HTTPS流量仍然在备份域中发送。如果金丝雀请求成功表示主域已恢复,系统会转回primary_state.,将所有流量路由到主域。
什么时候在BACKUP_STATE,系统还将最后使用的备份域存储在持久缓存中,在返回时清除该缓存primary_state.。在App Launch启动时,系统可以从此缓存中读取域,如果可用并开始BACKUP_STATE。这确保我们总是从备份域开始,用户在以前的会话中面临着与主域有关的问题。避免让系统在每次新发布应用时都发现问题,可以降低延迟,并在连续的会话中获得更好的体验。
金丝雀的请求
我们所做的一个关键选择之一是使用金丝雀的请求。我们的金丝雀要求的使用是通过使用的启发健康检查用于确定后端实例的运行状况。通过在将常规流量切换到备份域之前触发备份域的canary请求,当流量面临与主域的连接问题时,我们增加了备份域活跃度的信心。如果主域的连接问题是由于移动网络造成的,那么备份域的监听也应该失败。
我们不得不在执行金丝雀请求的两个选项之间进行选择:向专用的健康端点发送请求或捎带现有的应用程序请求作为金丝雀请求。
由于第一个方案相对简单,我们选择使用它。专用的canary请求允许系统按需触发canary请求,而不是依赖于应用程序请求,从而避免触发canary请求时出现不必要的延迟。它还避免为每个应用程序维护请求的白名单,以防由于严格的sla,一些关键的HTTPS请求不应该用作金丝雀。此外,它还减轻了后端处理延迟,使系统调试变得更容易,并允许在将来进行更容易的优化,例如触发多个“金丝雀”来增加域处理请求的机会的可信度,或者从几个选项中选择特定的域。
故障转移处理在现实世界中
在现实世界中,优步的应用程序面临着无数有趣但富有挑战性的情况。虽然我们的故障转移处理程序的第一次迭代有效地管理了大多数场景,但我们需要改进我们的初始设计,以确保我们的系统能够成功设置。
用户进入电梯或隧道
考虑一种具有良好网络条件的用户进入电梯或隧道的场景。这只是移动网络服务的暂时中断,但如果系统积极地反应并转移到使用备份域,则该应用程序可能会遇到子达性能。
在大多数与我们的故障转移处理程序中的实例中,状态更改为FAILOVER_STATE,但是在备份域上的提示请求成功之前,对主域的请求将恢复,并将状态切换回primary_state.。但是,在某些情况下,由于在网络恢复时,该状态由于在机器人响应的竞争条件而导致的resup_state。虽然这种情况很少,但我们将恢复超时调整为小初始值,以确保系统努力过渡回到primary_state.尽快。
主域不可用
在其他几个实例中,我们的用户使用特定移动载体的用户在流量使用主域时遇到了连接错误。虽然在某些运营商中,错误是由于DNS超时,在其他情况下,我们看到错误归因于TLS / TCP连接故障。在这种情况下,我们难以确切地针对问题的根本原因,无论是DNS提供商,移动载体还是云提供商都是一个问题,因为中间基础架构不在我们的控制下。但是,为了提供无缝应用体验,我们的系统证明有效地检测到失败并成功转换到BACKUP_STATE在加入备份域的金丝雀请求后,已成功返回。
面对这样的场景,我们必须在设计中添加一些内容。例如,我们只有一个条件来触发故障转移到FAILOVER_STATE当我们在特定时间段内达到最小故障数量时。但是,在我们的应用因用户活动较低而产生低流量的某些情况下,我们注意到故障转移的触发器中的滞后。要解决这种情况,我们添加了另一个超时阈值:达到此超时后,状态机转换为FAILOVER_STATE不需要达到最小失败次数。
主要领域恢复
除了限于较小区域或运营商的连接问题外,我们在公共云中也遇到过几次区域性中断的情况。通常,这种中断是短暂的,但在此期间会影响大量用户。在这种情况下,系统需要迅速故障转移到备份域,然后在云基础设施恢复时重新路由到主域。
如果您从设计部分中记得,我们的故障转移处理程序维护了一个恢复计时器在里面BACKUP_STATE和进入Recovery_state.在定时到期,以验证主要域的运行状况。随着云基础架构恢复,此流量可确保我们的移动应用程序将其交换回主域。
在生产中,我们必须重新评估机制的设计,以更新恢复超时的值,以确保始终如一的性能。如果恢复超时的值降低,它有助于更快地转换到主域。然而,当主要域仅在其间歇性地使用时导致子最佳用户体验,因为它导致之间的过度切换primary_state.和BACKUP_STATE。为避免过度切换状态,我们将每次转换都线性提高恢复超时的值BACKUP_STATE。这可确保系统在尝试第一个周期的主要域时具有激进的,但降低了其在每个后续循环上的探测速率。
衡量成功
我们展示了证明故障转移处理程序在满足我们的关键设计目标方面的有效性的关键指标。为了进一步阐明现有解决方案的缺点,我们比较了故障转移处理程序(Uber-FH.)与基于循环的故障转移处理程序(RR)我们在上一节中解释了。
最大限度地使用主域
我们的第一个目标是确保我们优先通过公共云网络路由我们的流量,以最大限度地提高较低网络延迟的性能。图1a显示了不同故障转移策略的主要和备份域中的流量分发。Uber-FH.使用主域路由几乎99%的流量。然而,RR向备份域路由超过20%的流量,因为它无法有效地区分移动网络引起的错误和实际主域中停电。
如果是RR,当我们持续缓存备份域,以确保在主域不可达的情况下,新的应用程序从备份域启动时,我们发现问题进一步恶化。每次系统在切换到备份域的过程中出现错误时,它不仅仅是惩罚本届会议,以及以后的会议。
为了量化由于主要域的使用量增加,图1B显示了HTTPS请求的尾端延迟减少百分比Uber-FH.反对RR。虽然我们在IOS和Android中的所有应用中看到了显着的收益,但我们确实看到某些应用程序的更高收益。较高收益的主要原因是由于蜂窝网络使用率较高,由高度移动用户访问的一些应用程序,他们面临更加间歇连接。
通过增加主要域的使用量可以归因于两个因素:(i)近距离终止Quic或TCP连接可提高传输协议对无线网络的性能,并且(ii)由于我们目前依赖的情况而增加了Quic的使用情况在云前端服务器上用于判断。如下面的图2所示,我们看到了Quic的使用增加了大约5-25%Uber-FH.与之相比RR。
从域中有效地区分网络错误
金丝雀请求的使用显着帮助Uber-FH.在出现网络错误时,可靠地检测域的可用性,并避免不必要地切换到替代域。下面的图3比较了故障转移事件的数量Uber-FH.和RR。当用于路由流量的域从主域切换到备份域或反之亦然时,故障转移事件被定义为单个事件。该图绘制了跨用户会话的故障转移事件的数量。具体地说,骑手会话是骑手进行的一次旅行,或者eats会话是食客放置的单一食物订单。此外,我们根据网络条件对会话进行分组,即根据这些会话中HTTPS通信的错误率或失败率。
从图中可以清楚地看到,RR即使在导致少量网络错误的平均网络条件下,基于故障转移也在切换域中过于无功。在更严重的条件下,RR由于它遇到多个网络错误,因此导致了重要的域交换机。代替,Uber-FH.证明,即使在严重的网络条件下,也会有效地降低故障转移事件的数量,而不会影响延迟或可用性。
我们确实看到了一些实例Uber-FH.在高网络错误率时,不必要地切换到备份域。在这种情况下,我们看到,当网络恢复时,canary请求的成功会先于常规请求的成功处理,从而导致转换到BACKUP_STATE。但是,此类实例现在很少见,故障转移处理程序有效快速返回primary_state.在恢复超时的初始值之后。
在主要领域中断期间减少退化经验
图4:(左)图描绘了在特定国家/地区使用8个载波的用户的主要和备份域的流量分发。(右)图表在同一8个载波中绘制HTTPS请求的错误率。
欣赏设计的设计Uber-FH.,重要的是要测量它在主要域间歇性不可用的时期工作。在特定实例中,我们在特定国家/地区使用特定运营商(AS C4)的用户在大多数情况下为我们的主要域显示大多数DNS错误C。图4(左)使用来自国家的8个移动运营商的主要和备用域来绘制流量的分布C。从图中可以看出Uber-FH.有效确保交通返回到载体C4的备份域,这些域正在面临主要领域的可用性问题。更重要的是,我们的设计选择确保了用户体验对来自载波C4的用户没有受到影响。在图4(右)中,我们在同一时间段内绘制所有载波的错误率。错误率被定义为失败的HTTPS请求的数量除以总HTTPS请求。显然,我们从运营商C4的流量的错误率在同一国家的其他运营商中看到的错误率范围内。
前进
我们的故障转移处理程序已成功向Uber平台上的所有用户推出,导致应用响应时间更快,更好的整体客户体验。展望未来,我们计划利用所有的学习和从生产中的数据来进一步提高系统的可靠性。具体地,我们正在评估可以使用历史数据来预测区域,网络类型,载波中的用户的性能和可靠性的系统,以进一步增强移动设备的决策。通过选择利用多个云提供商的选择,我们的目标是在每个用户会话的基础上实时使用最佳云提供商或内部基础设施来解决挑战,以便进一步减少延迟,同时潜在节省成本。
致谢
我们要感谢Vinoth Chandar和Jatin Lodia对此项目的贡献。








