两年前,Uber 先前的聊天应用程序开始显示出无法适应我们的发展的迹象。有应用程序崩溃、性能打嗝以及停电中断,削弱了我们公司在线有效沟通的能力。用户满意度一直走低,所以我们需要一个新的解决方案。
我们的运营分布在 620 多个城市,能让 Uber 员工无论处于世界何地都能在台式机和移动设备上可靠地进行通信,这一点非常重要。为此,我们制定了一些核心要求。首先,我们需要一些东西能够扩展以支持不断増长的员工人数,同时也能控制其成本。我们还需要一个可以轻松与各种内部工程、业务和操作工具相集成的平台。
当我们评估互联网中继聊天(IRC)和许多其他流行的聊天客户端时,很明显,没有一个完整的第三方解决方案可以满足 Uber 的核心要求。
所以,在测试了多个现成的替代方案后,我们利用开源平台 Mattermost 和 Puppet 构建了 uChat,它是我们的定制内部消息平台,是用于部署配置管理的 Uber 标准。在本文中,我们将讨论如何在短短三个月内,我们的团队让公司转变到能够在一个统一的聊天环境中每天向数万用户可靠地发送超过一百万条消息的新解决方案。
走向开源
为了加快开发进程,我们决定基于开源平台构建我们的解决方案。这个选择尤其有吸引力,因为我们希望直接影响路线图并控制长期的经常性成本。如果从零开始就会更加困难。
为了充分利用我们的混合构建方法,我们需要一个功能强大的开源构建块,它得有多功能的 API、高质量的代码库和充满活力的开发社区。我们评估了各种 XMPP 、 Erlang 和基于 JavaScript 的选项。由于我们的主要要求是能够支持 Uber 的增长,因此我们特别留意那些可扩展性很好的聊天平台。
作为性能验证的一部分,我们将每个开源产品的性能推到了突破点。例如,我们的初始目标之一就是在一个单一的聊天环境中模拟 50,000 个用户的聊天行为。很快,很多这些平台就无法进行这些基本的负载测试。
图 1a:我们对测试实体线程(Thread)的设计尽可能简单,从而将注意力集中在快速验证产品声明上。
对于其他的性能选择,我们编写了一个测试工具来模拟成千上万的用户。测试集的设计(上图 1a)非常简单,这确保了我们可以用最小的努力来验证产品声明。在这个测试环境中,简单的 Go 结构的 EntityConfig(下图 1b)封装了可以登录、加入渠道和发送消息的用户。结合 Go 的本地协同程序,很容易达到我们的模拟目标。随着时间的推移,测试工具能提供更强大的功能,更好地模拟复杂的用户场景。
图 1b:EntityConfig 代表着平台上用户的基本交流需求。
经过数月的测试和供应商审查,我们选定了 Mattermost 。Mattermost 大大超出了我们的最低性能预期,并与 Uber 现有的技术堆栈很一致。此外,他们的客户端用户界面类似于那些很受Uber 员工喜欢的聊天应用程序界面。
下一个合乎逻辑的步骤是,评估该平台是否能够跟上Uber 的高增长并维持我们对聊天的操作依赖性。仔细考虑了必要的因素之后,我们问自己:Mattermost 能否达到Uber 规模?
为了测试Mattermost 在适应这些条件方面的能力,我们的负载测试旨在识别出可能影响性能的软件架构和服务器代码的主要瓶颈。我们模拟了可变消息发送速率、升高窗口和并发用户峰值以建立基准。我们创建了成千上万的假用户帐户,并编程用以登录、加入聊天室和进行聊天,目的在于触发崩溃和数据库锁定。
图2:在对基于Mattermost 的聊天解决方案测试期间,当主数据库连接达到最大值而且数据库锁定时,消息发送速率下降。
在测试期间,我们并不惊讶地发现,不仅仅是后台显示出了有限的可扩展性。我们测试过的大多数用户界面都不能达到我们积极的目标:譬如,聊天室仅能容纳约一百个用户,而且现有的用户界面不能同时搜索20,000 多个频道。
当在规模测试期间遇到瓶颈时,我们针对最具影响力的性能违规者进行了修复,并从已知的稳定负载水平重复了该过程。同时,我们继续更新测试,以模仿更加现实的用例。我们的初始目标是7 万个并发用户、发送速率为每秒80 到200 条消息。如果能够成功管理这种负载,我们可以确保有足够的空间来支持将来的增长。
与开源社区合作,我们不断剖析日志、识别根本原因并发布新的修复。这里,周转速度至关重要。随着每个新的发现和构建,我们对整体系统的局限和快速适应可扩展需求的能力有了更深入的认识。
渐渐地,我们清楚地看到Mattermost 在当时最能够发展成熟到Uber 规模,我们对他们的平台也有了信心。为了帮助其他人使用我们的新合作伙伴去开发聊天平台,我们把测试工具贡献到了开源社区。
用Puppet 来管理uChat 软件架构
在对Mattermost 平台进行负载测试时,我们需要持续可靠地更改新解决方案的基础架构和应用配置。Mattermost 的高可用性(High Availability)模式仍然处于早期测试阶段,因此我们经常在代码中遇到错误。
在早期的测试和开发阶段,Uber 基础设施团队手动地修改了这些代码。可以预料的是,让新的uChat 构建和服务器配置稳定下来是一个乏味且易于回归的过程,需要频繁地进行更改以修复无意的配置错误。很明显,人工基础设施管理正在放缓我们的速度,于是我们转向了Puppet。
我们使用Puppet 来编码软件架构和服务器配置,为管理支持uChat 快速改进所需的各种服务器和网络环境提供了坚实的基础。 Puppet 可以对数据库拓扑中的多个机器实现一致的和可重复的更改,并允许我们审核更改和执行部署代码审查。
图3:uChat 最初的Puppet 工作流不能达到我们的解决方案所需要的能可靠地迭代和扩大规模的速度。
最初引入Puppet 极大地减少了部署期间的无意错误。然而,即使基本的Puppet 基础架构代码解决了我们的一些重复性和一致性问题,我们仍然没有达到所需要的速度。在这个阶段,我们没有使用不可变的服务器,这意味着改变高可用架构的Puppet 代码带来了意想不到的副作用的巨大风险。此外,我们正在使用一个大型monorepo,其中所有与Puppet 相关的更改必须收敛,从而使得问题更严重。
这种约束意味着我们无法快速地部署新的基础架构和应用程序版本以满足我们的需求,严重限制了我们的迭代速度。因此,更新的Puppet 部署配置可能需要一两天才能安全完成。同时,每小时都可收到无关的uChat 性能提升。我们新的基于Puppet 的工作流程更好,但仍有改进的余地。
图4:uChat 目前的Puppet 部署流为由我们的网站可靠性工程师维护的Puppet 模块集成了一个单独的存储库。
为了加快uChat 部署,我们将基础架构代码转换为单独的存储库作为Puppet 模块。这将允许我们独立地管理版本、隔离和测试与uChat 应用程序特定相关的配置更改,而不用管服务器基础结构配置。
在重构并彻底测试了新的Puppet 模块后,我们依靠 Puppet 代码管理器将基础设施更改推向新建的模拟和生产环境。这种基于模块的方法使我们能够将应用程序配置问题与基础设施 / 服务器配置问题分开,更容易地根据 uChat 应用程序本身的需求和发布时间表来分发更改。
图 5:上面详细介绍的 uChat 软件架构完全由 Puppet 编排。这有利于可靠地部署和微调平台所需的高质量变更控制。
通过 Puppet 模块、Puppet 代码管理器和对 A/B 部署的支持,我们终于实现了所需要的快速而一致的部署变更控制。现在,我们可以在不到一天的时间内可靠地完成整个模拟和生产环境。
创造无缝用户体验
在让基础架构变得成熟的同时,我们还必须建立一套直观的 Uber-fied 网络、桌面和移动应用程序。首先,我们克隆了 Mattermost 桌面应用程序,并开始对内部客户进行简单的白色标签。另一方面,Mattermost 移动应用程序需要进行完整的重组,以实现我们正在寻找的用户体验(UX)类型。
图 6:我们团队的设计批评改进了 Mattermost/uChat 中的用户界面,在使用 UX 识别问题点时没有任何遗漏之处。
原先的基于 iOS 和 Android 的 uChat 应用程序集成了一个简单的网络视图来加载整个 uChat 网页,导致加载时间极慢。另外,网络视图引起刷新,强制不必要的加载、不完整的文件下载和不均匀的体验。为了增强我们的员工并加快建设,我们与 Fullstack Labs 合作,在 React Native 中重写这些应用程序。正如我们与 Mattermost 所支持的平台的做法一样,我们向开源社区贡献了所构建的一切。
目前,uChat 移动客户端通过我们的内部应用程序商店进行部署,通过 Chef 和 System Center Configuration Manager (SCCM)来管理桌面客户端。为了限制移动 uChat 版本数量,并简化持续的支持,我们在 iOS 和 Android 应用程序中构建了自定义机制,提示用户在新的 uChat 版本可用时进行升级。我们还设计了一项功能,用于在需要强制升级的情况下让旧客户端版本实效。
uChat 移动应用程序可以让 Uber 员工轻松在即时和跨设备进行通信。
我们对可扩展性平台的远景确保了我们提供与生态系统中的其他工具相集成的 UX。为了实现这一目标,我们花了几个月的时间将以前的解决方案中的 50 多个旧功能集成到了 uChat。API 和 webhooks 允许现有的内部服务集成和扩展聊天功能,例如 Uber 的内部部署系统 uDeploy ,它在新的构建完成时通知工程师;或者 Envoy ,它支持我们的办公室访客注册服务。
构建用户的信任
在实现任何的企业应用程序时,推动用户采用产品和改变现有行为是很有挑战性的。在将公司转移到诸如 uChat 这样的本土工具的同时,需要额外的关注,以灌输 uChat 比现有的消息平台更可靠的信心。为了建立这种信心,并尽可能无缝地过渡到 uChat,我们预先为所有员工提供了帐户,并迁移了近 20,000 个聊天室,员工不必重新创建或重新加入他们以前用过的任何聊天室。
尽管我们尽了最大努力,但还是有坎坷。随着我们将越来越多的员工集成到 uChat 上,间歇性中断使得一些早期用户不愿意完全采用该应用程序。为了减轻顾虑,在 uChat 逐渐稳定并有更多的时间展示自己的同时,我们也保留了旧版聊天应用程序在线。
为了进一步将 uChat 与员工进行整合,我们提高了透明度。当发现错误时我们就宣布它们、发布修复计划并部署布丁。我们还制作了广泛的监控图表,这样,任何感兴趣的人都可以看到 uChat 的实时健康状况。
一旦我们能够持续显示 uChat 的 99.9%的可用性,我们将传统聊天系统设为 depreciated。我们逐渐禁用房间创建和集成等功能,直到将插件从旧系统中完全剥离出来,从而完成了全面的调整。我们经常公布产品更新、共享使用技巧和整理如常见问题和用户指南等资源,以确保员工得到全方位的支持。我们还开设了一个反馈渠道,员工可以立即获得帮助,也可以建议新的功能。
我们从这次经验中学到的关键一课是,弃用现有聊天应用程序所需的计划和组织调整水平,需要更多的买帐和协调,远远超过我们最初所预期的。但是,通过保持透明、易用和快速的改进,我们与应用程序的早期采用者们建立了良好的关系基础,并随着时间的推移让整个公司得以过渡。
uChat 的未来
在接下来的几个月里,我们将实现新的特征,继续检测用户的反馈,并将 Mattermost, Inc. 公司和开源社区所提供的额外改进整合到产品中。
uChat 只是我们团队为促进 Uber 的协作、沟通和生产力所建立的众多解决方案之一。我们不断开发、部署和维护 Uber 的内部工具包,每年为公司节省数百万的回收生产力和软件许可费用。如果你对在像 Uber 这种快速增长的全球性公司里的下一代内部系统感兴趣,请考虑向 Uber 的员工效率工具团队(Employee Productivity Tools team)申请职位。
关于作者
Marissa Alvarado-Lima 是 Uber 技术服务团队的技术撰稿人,Stanley Chan 和 Chris Duarte 是 Uber 员工效率工具团队的软件工程师,Ed Wolf 是 Uber 员工效率工具团队的资深产品经理。软件工程师 Sameer Patan 和 Josh Schipper、资深网站可靠性工程师 Matt Beard、软件工程经理 Benjamin Booth 和产品设计师 Nayong Park 对此文也作出了贡献。
查看英文原文: THE ROAD TO UCHAT: BUILDING UBER’S INTERNAL CHAT SOLUTION
感谢郭蕾对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论