介绍
Uber 是一家全球性企业,其客户群遍布全球。Uber 的客户群分为许多用户角色,主要是乘客、司机、食客、快递员和商家。作为一家全球性企业,Uber 的客户也希望获得全球范围的支持。客户通过各种实时(聊天、电话)和非实时(应用内消息)渠道与我们联系,并期望迅速解决他们的问题。Uber 客户每周都会提出数百万次支持互动(内部称为联系人),我们的目标是在预定义的服务水平协议 (SLA) 内解决这些联系。客户创建的联系可以通过自动化或在客户支持代理的帮助下解决。
对于代理联系人,工单解决成本在 Uber 如何构建其支持渠道以及确定不同实时和非实时渠道的量方面起着重要作用。聊天渠道的每次联系成本 (CPC) 和 FCR(首次联系解决率)在不同的实时渠道中最为有效,因为它们允许代理同时处理多个聊天联系,同时保持比电话等渠道更低的平均成本。这个渠道是 Uber 的最佳选择,因为它具有良好的CSAT分数(客户满意度评级,在 1 到 5 的范围内衡量),同时通常可以降低 CPC。这个渠道允许更高的自动化率、更高的人员配备效率(因为代理可以同时处理多个聊天)和高 FCR,这些都对 Uber 有利,同时为客户提供高质量的支持。
从历史上看,从 2019 年到 2023 年初,1% 的联系人通过实时聊天渠道提供服务,58% 的联系人通过应用内消息渠道(非实时渠道)提供服务,其余联系人通过电话等其他实时渠道提供服务。为了实现更高的 CSAT 和 FCR,工程团队需要扩展聊天基础设施以满足 Uber 不断增长的业务需求,并促进大量应用内消息和电话渠道联系人迁移到聊天渠道。在本文中,我们将重点介绍聊天实时渠道。
挑战
为了扩展聊天渠道以支持路由到代理的 40% 以上的 Uber 联系量,以下是团队面临的一些主要挑战:
- 从后端系统向客服人员浏览器传递消息的可靠性问题
- 46% 的客户尝试联系客服人员时发生的事件未能及时送达,导致客户和客服人员的带宽浪费。请注意,46% 不是指此处唯一联系人的数量,而是指所有聊天联系人的事件总数。
- 缺失的洞察
- 无法观察聊天联系人的健康状况。
- 由于代理长时间处于空闲状态,但队列也不是空的,因此 Ops 开始怀疑是人员过剩还是技术问题导致数量不成比例(称为技术与人员问题)。
与遗留架构相关的挑战
我们的原有架构是使用WAMP 协议构建的,该协议主要用于消息传递和通过 WebSockets 的 PubSub 将联系信息传递到代理的机器。
图 1:描述了聊天联系人从创建到路由到前端代理的先前高级流程。
注意:这与客户与 Uber 支持之间通过 HTTP 服务器发送事件 (SSE) 交换聊天消息的数据路径不同。为此,Uber 将 Ramen 用作内部服务,在控制和数据路径中扮演双重角色。在控制路径中,Ramen 为客户端到移动用例提供双向支持,从而实现有效沟通。同时,在数据路径中,Ramen为客户端到 Web 用例提供SSE功能。
然而,在数据路径上出现了一个值得注意的区别,特别是对于客户端到 Web 的用例,其中 Ramen 的成功交付率为 94.5%。它以单向方式运行,这促使人们需要新的控制流。这些新的控制流对于检测和管理客户端不再响应的情况至关重要,从而解决数据路径中的单向限制。在本博客中,我们将介绍新的控制流,以将事件从后端传递到代理的浏览器(Web),以使代理能够进行首次回复。
团队在生产环境中推出了 E2E 架构,并开始发现问题。问题不是立即出现的,但随着流量超过几张票,团队意识到该架构无法轻松扩展其初始功能,生产管理也不是那么简单。下面列出了其中一些核心问题:
可靠性
我们的流量增加了 1.5 倍,导致可靠性问题,后端有多达 46% 的事件未传送到代理的浏览器。这增加了客户与代理通话的等待时间。
规模
除了 RPS 低于约 10 的情况外,由于内存使用率过高或文件描述符泄漏,系统从后端传递联系人的性能显著下降。由于使用旧版 WAMP 库的限制,不支持水平可扩展性,升级 WAMP 库需要付出巨大努力。
可观察性/可调试性
以下是与可观察性相关的主要问题:
- 很难追踪聊天联系人的健康状况,例如,如果聊天联系人由于工程相关问题或人员配备相关问题而缺少 SLA。
- 聊天联系人未在基于队列的架构上加入,导致超过 8% 的聊天量由于代理的属性匹配流程而未路由到任何代理。
- 使用的WAMP 协议和库(eg1、eg2)已被弃用,无法提供太多有关内部工作原理的见解,导致调试变得更加困难。此外,我们尚未端到端地实施聊天联系人生命周期调试,并且我们无法准确检测平台上的聊天 SLA 缺失。
有状态的
这些服务都是有状态的,维护和重启变得复杂,导致消息传递时间激增和丢失。添加了 WebSocket 代理来执行授权,而且由于服务总体上都是有状态的,但这极大地增加了延迟。当任何一端断开连接时,双套接字代理都会导致问题。
技术要求
以下是技术团队正在努力实现的一些目标:
- 到 2023 年底,将聊天流量从总体联系量的 1% 提高到 40%(每周 150 万张票)
- 加入并扩展队列上的聊天流量,以支持与队列相关的洞察
- 到 2024 年底,将处理 Uber 80% 以上的总联系量(每周 300 万张票)。
- 通过代理管道(称为推送管道)进行的预约(在确定代理后,第一次尝试将客户连接到代理)成功率应> = 99.5%
- 在整个聊天流程中端到端构建可观察性和可调试性。
- 无状态服务,如果水平扩展或实例因任何原因发生故障,则无需重新校准
解决方案
新的架构需要简单,以提高内部运作的透明度,并使团队能够轻松扩展。团队决定继续使用 Push Pipeline,这将是一个简单的、无冗余的 WebSocket 服务器,代理机器将连接到该服务器,并能够通过一个通用套接字通道发送和接收消息。
高级架构
现今的新架构如下所示:
图 2:描述了聊天联系人从创建到路由到前端代理的整个过程的新的高级流程。
该架构包含以下部分:
前端
前端 UI 是客服人员与客户互动的界面。客服人员可以使用小工具和不同的操作来调查客户并采取适当的措施。
联系预订
路由器是寻找代理与联系人之间最合适匹配的服务。找到代理最合适的联系人后,联系人将被推送到代理的保留状态。
推送管道
成功为代理预留联系人后,匹配的信息将发布到 Apache Kafka®。通过 GraphQL 订阅通过套接字接收此信息后,前端将加载代理的联系人以及所有必要的小部件和操作,使代理能够响应用户。
代理状态
任何需要开始工作的代理都需要通过前端的切换上线,触发后会使用相关代理的新状态更新代理状态服务。
边缘代理
客户端浏览器和后端服务之间的任何连接都通过 Edge Proxy 进行,它作为防火墙和代理层保护 Uber 服务。
操作简便、洞察更深入
以下是重点:
- 在队列中加入了聊天流量,订阅的代理将根据代理配置文件的并发集接收联系人。并发定义了代理可以同时处理的聊天联系人的数量。
- 代理人员到队列的配置在本质上具有决定性,并且默认支持基于 SLA 的路由(根据队列 SLA 对聊天联系人进行优先排序)、粘性路由(坚持与代理重新建立联系)和优先级路由(根据队列上定义的不同规则进行优先排序)等功能。
- 通过队列加入,仪表板被重新利用/增强,以便 Ops 团队查看聊天队列 SLA 和代理可用性及其实时状态,包括联系人生命周期状态、队列流入/流出、代理的会话计数等。
GQL 订阅服务
与 GraphQL 订阅相关的主要亮点是:
断线重连
我们在 GraphQL 订阅套接字上启用了 ping pong,以确保在连接不可靠的情况下自动断开套接字。当套接字断开时,相应的代理将不再有资格接收新联系人。Web 套接字重新连接会自动重试。成功重新连接后,将获取所有保留/分配的联系人,以便代理可以接受它们。
推动管道可靠性
对于为给定代理预留的联系人,如果前端未向聊天服务发回确认,我们会尝试为另一个可用的代理预留相同的联系人。我们通过 GraphQL 订阅发送心跳来检查代理浏览器的 Web 套接字和 http 协议是否正常工作,并通过代理浏览器的 HTTP API 调用发送响应以检查代理是否在线。
技术选择
下面概述了我们为提高聊天系统的可靠性和稳定性而做出的一些技术选择,同时还考虑了我们的选择对用户感知等待时间的端到端延迟影响。为此,我们需要保持此系统的简化,同时启用部分产品增强功能。
通过 WebSocket 和 GraphQL 订阅使用 GraphQL
前端团队广泛使用 GraphQL 对其前端服务进行 HTTP 调用。这促使团队选择 GraphQL 订阅来将数据从服务器推送到客户端。客户端将通过订阅请求向服务器发送消息,服务器在匹配查询后将消息发送回代理机器。有关 GraphQL 订阅的更多信息将在以下部分中介绍。
graphql -ws库给了我们信心,因为它的每周下载量达到 230 万次,受到Apollo 的推荐,并且没有未解决的问题。它还以标准的GraphQL over WS 协议为模型,并完全遵循该协议的选项,使其成为此处使用的理想选择。
无状态服务
创建的新服务必须是无状态的,才能水平扩展,而不需要时不时地重新平衡。
无 HTTP 回退的 Websocket
由于系统需要代理机器和代理层之间的双向通信,因此 HTTP 回退实际上不会对系统的 SLA 产生任何影响。因此,团队专注于通过以下方式提高与代理的套接字连接的可用性:
- 双向乒乓消息可防止套接字挂起
- 断开连接后停止重新连接,以防止并发重新连接导致服务不堪重负。
- 单一代理连接套接字,无需任何切换
使用 Apache Kafka® 作为后端的消息服务
联系信息在到达代理层之前已经通过 Kafka 流经了各种服务。我们决定继续并扩展使用 Kafka,因为它可靠、快速且支持广播 (PubSub) 功能。
测试与发布
我们进行了功能性和非功能性测试,以确保为客户和代理提供端到端的最佳体验。为了预测性能,我们在发布前进行了一些测试:
负载测试
可以从一台机器建立约 10K 个套接字连接,随着我们添加更多机器,它将进一步实现水平扩展。我们成功测试以旧堆栈的 20 倍速度推送事件。
影子交通流
现有流量通过旧系统和新管道进行传输,以测试其每天 40,000 个联系人和 2,000 名代理的容量。此过程没有发现任何问题,数据指标显示延迟和可用性令人满意并达到所需的阈值。
反向影子流量
现有流量通过新系统与旧的代理用户界面进行引导,作为一项关键的可靠性测试。这是新系统的首次使用,它成功地管理了流量,同时将延迟保持在定义的 SLA 范围内。
在此过程中,我们遇到了独特的系统和代理行为问题,并进行了一些修复以提高可靠性并减少管道整体的延迟。一些主要问题包括:
从浏览器中删除 Cookie
清除浏览器 cookie 会导致与身份验证和后续 API 故障相关的问题,从而阻止前端对推送的事件采取行动。在这种情况下,代理过去一直保持在线状态,但不处理任何联系人。
自动注销流程中的错误
代理过去通常不会因为诸如故障或事件丢失等问题而被注销。完成当天工作的代理如果只是关闭标签,则仍会在系统中保持在线。这导致客户等待时间增加,因为管道试图将事件推送给这些不在线的代理。然后,我们开始根据最近的确认遗漏自动注销代理,并将注销全部追溯到正确的原因,以提高对系统的信心。
结果
聊天渠道已经能够扩展到路由给客服人员的 Uber 整体联系量的约36%,未来几个月还会有更多。看来团队已经重新获得了扩展聊天渠道的信任,并改善了整体客户体验。该团队还能够大幅提高可靠性,旧堆栈中传递联系的错误率约为 46%,而新堆栈中约为 0.45%。每次传递失败后,客户的工单都会在 30 秒的延迟后反弹,之后会重新尝试传递,将这个数字在规模上降低到 0.45% 以下,对于客户和客服人员的整体体验来说意义重大。
我们在这个领域还取得了其他胜利,其中最好的可能就是简单性。新架构的服务更少,协议更少,系统内置的可观察性更好,可以查看联系传递指标、系统内的延迟以及端到端延迟。
结论和后续步骤
新的推送管道使团队能够加入其他推送用例,并通过为代理提供实时信息来改善用户体验。一些与 Greenlight 预约和代理工作重叠相关的用例将很快作为下一阶段的一部分转移到这个新堆栈上。
聊天频道的用户体验也将整体进一步改善,重点是增强功能和系统架构调整。这将基于从产品扩展中吸取的经验教训以及解决客户和代理报告的问题来实现。
作者:
Avijit Singh
Avijit is a Staff Software Engineer within the Customer Obsession org at Uber. He is currently working on building efficient contact routing that scales across different channels. He is passionate about solving large scale problems and worked across different problem spaces related to Last Mile Delivery, Contact Routing, etc. to scale business.
Vivek Shah
Vivek is an Engineering Manager (former Staff FE Engineer) on the Agent experience team at Uber. He’s worked on improving the overall agent experience on Bliss and currently leads efforts on large-scale tool experience migrations including improving channel experiences for agents. He is passionate about the world of front-end tech & lives to build meaningful & seamless experiences for users.
Ankit Tyagi
Ankit is an Engineering Manager on the Customer Obsession team at Uber, focused on building efficient, effective routing and escalation tech to improve the quality of support. He has more than a decade of experience in the industry and loves building scalable, antifragile distributed systems for real-world problems.
出处:https://www.uber.com/en-JP/blog/building-scalable-real-time-chat/