12Reads资讯
企业管理第一媒体

重写优步工程:微服务带来的商机

重写优步工程:微服务带来的商机

几个月前,我们讨论了优步放弃庞大代码库转向模块化弹性微服务架构的决定。自那以后,成千上万小时的工程时间被投入到优步微服务生态系统的扩展上,数百个微服务在不同框架下以多种语言写就。这一正在进行中的重构是个巨大的工程,因此,我们趁此机会采用了一套新的技术为优步打造微服务。在技术栈和适合SOA(面向服务架构)迁移的标准支持下,我们理顺了优步的服务开发。

创建新服务

在一个快速发展的工程公司里,跟踪所有在建工程是一件很难的事。如此快速的发展需要一个过程来防止各团队之间重复劳动。在优步,我们通过要求新服务作者提交“征求意见文档(RFC)”解决了这个问题。RFC文档是关于新服务的高层提案,描述了新服务的目的、架构、依赖和其他实现细节,供优步工程的其他成员进行讨论。RFC文档目的有两个:1)在开发过程中用于改进服务质量的反馈意见征求;2)防止重复劳动或发掘合作机会。

熟悉相关领域的其他几位工程师会对提交的服务进行审核。一旦反馈意见纳入服务提案,服务打造游戏便正式开启。

实现新服务

Tincup,我们的货币和汇率服务,是优步微服务实现的一个绝佳案例。Tincup是最新货币和汇率数据的接口,有2个主要功能:一是获取货币对象,二是获取给定货币的当前汇率(以美元表示)。优步的国际性注定了这两项功能是必需的。汇率总是在变,而我们要支持近60个国家的交易业务。

无论你身处何处,总能轻点滑块叫车。Tincup保证了你能以所处国家的货币付款。

用新技术自展微服务

在打造Tincup的过程中重写货币和汇率相关的所有逻辑,为重新评估优步之前的某些设计决策提供了很好的机会。我们采用了一系列的新框架、协议和约定来实现Tincup。

MVCS

首先,我们解决了货币和汇率相关代码的总体结构问题。优步最近几年间,我们多次修改了很多数据集的持久层(比如这个货币和汇率数据集)。每次修改都又难又耗时。从这一过程中我们学到了,如果可能的话,最好能将持久层细节从应用逻辑中分离出来。总结起来,我们得到了被称之为MVCS的应用开发方法,也就是扩展常用的MVC方法(模式-视图-控制器),引入服务层囊括应用逻辑。通过将应用逻辑隔绝在服务层,数据持久层便可以在不用重构业务逻辑的情况下进行升级或替换(只有直接处理数据存储/读取的代码需要修改)。

UDR

其次,我们考虑了货币和汇率持久层。在Tincup之前,这些数据存储在PostgreSQL关系数据库中,采用增量整数ID建立记录。然而,这种数据存储方法不支持跨数据中心复制数据,也就不符合我们的全激活架构(所有数据中心的数据都能同时互通有无)。由于货币和汇率需要能从所有数据中心中获取,我们便换出了持久层以采用UDR——优步的全球复制可伸缩数据存储。

微服务增长的预期顾虑

在做出货币和汇率设计修改决策后,我们处理了工程生态系统中微服务增长自然而然会带来的新的问题。

Tornado

网络输入/输出(I/O)阻塞是可能会造成uWSGI服务器工作者线程饥饿的一个严重问题。如果对Tincup之类服务的所有请求都是同步的,一个服务的恶化可能会产生涟漪效应,影响到所有调用者。我们决定采用Tornado,一个基于事件循环的Python异步框架,来防止阻塞。由于我们从用Python 编写的轻量级 Web 应用框架Flask代码库中借用了大量的代码,选择一种能让现有应用逻辑保持原样的异步框架,便对最小化风险有着举足轻重的作用。Tornado既容许看起来像同步的代码,又不会造成I/O阻塞,很符合我们的要求。

TChannel

一旦某个API调用扇出了大量对微服务的调用会是什么情形?为支持在大生态系统中对其他服务的发现和故障点的识别,优步微服务使用了开源的RPC网络复用和成帧协议TChannel+Hyperbahn。TChannel提供了客户端和服务器协议,结合Hyperbahn的智能路由网连接二者。微服务世界中的一些核心问题迎刃而解:

• 服务发现。所有生产者和消费者线程都在路由网中注册自身。消费者通过名字访问生产者,不用知道主机或端口。

• 容错。路由网跟踪故障率和服务等级协议(SLA)违规事件。它能检测不健康的主机,并从可用主机池中删除它们。

• 速率限制和断路。这两个功能确保了来自客户端的不良请求和慢响应不会引起级联故障。

Thrift

由于服务请求的数量增长很快,为每个请求维护一个定义良好的接口便非常必要。我们很清楚需要一种接口定义语言(IDL)来进行管理,而最终我们选择了Thrift。Thrift强制服务所有者发布严格的接口定义,简化服务集成的过程。不遵从接口的调用请求在Thrift层级就被拒绝,不会渗漏进服务在更深的代码中引起故障。公开接口的策略强调了向后兼容的重要性,因为一个服务的多个Thrift接口版本可能在任何时候被使用。服务作者不能做出颠覆性修改,只能逐步在接口定义中添加小改动。

让Tincup成为行业佼佼者:产品

最后,在Tincup实现阶段接近尾声的时候,我们使用了一些很有帮助的工具来构建Tincup的产品环境:

Hailstorm

首先,我们确认,优步的服务是24小时全年无休的,在新年夜、万圣节之类的节假日还会迎来叫车高峰。因此,我们必须保证各项服务在发布的时候能搞定这些突然增加的负载。遵从优步的新服务发布要求,我们使用了内部开发的Hailstorm服务来加载测试Tincup终端,检测其不足和断点。

uContainer

接下来,我们考虑了优步工程的另一个主要目标:更高效地利用硬件。因为Tincup是相对轻量级的服务,它能够很容易地与其他微服务共享机器。共享就是关爱,对吗?好吧,事情并非总是如此——我们依然想确保每个服务都是独立运行的,而且不会影响到同一台机器上运行的其他服务。为防止服务间相互影响,我们使用uContainer(优步自己的Docker应用容易引擎)部署Tincup,隔离和限制微服务资源。正如uContainer这个名字寓意的,它利用了Linux容器功能和Docker来装载优步服务,将服务封装到一个隔离的环境以保障服务能始终如一地运行,无论同一台主机上的其他进程发生什么状况。uContainer通过增加更灵活的构建功能和引入更多的可见性,扩展了Docker容器的能力。

uDestroy

最后,为应对停机和产品中无法避免的网络连接性问题,我们使用了一款名为uDestroy的内部工具来释放受控混乱。通过模拟破坏,我们对系统弹性有所认知。因为我们在开发过程中定期对我们的系统进行目的性的破坏,我们就可以发现漏洞并持续进行改进,提高耐用性。

经验总结

通过借由打造Tincup扩展SOA,我们从中学到了几条经验教训:
1. 迁移消费者是一个长期而又缓慢的过程,因此,应尽可能让这个过程简单易操作。提供代码例子。做出时间规划。
2. 最好从小服务上学习技术栈。Tincup的应用逻辑非常简单,能让开发者专注在学习新的技术栈上,而不是受困于业务逻辑那繁琐的迁移过程中。
3. 初始阶段将时间投入在大量的单元和集成测试上,最终会收获回报的。若是在开发环境中,代码调试问题便会简单许多(也不会那么压力山大)。
4. 尽可能早,尽可能频繁地进行负载测试。没什么事比在花费了几周乃至几个月进行实现之后才发现系统无法搞定高峰流量更糟糕的了。

优步微服务

优步的SOA迁移为很多人提供了拥有服务的机会,甚至那些只有有限产业经验的人都可以。拥有一个服务是一项很重大的责任,但优步的开放式知识分享文化,让汲取新技术,拥有代码库,成为了一份有价值有回报的体验。(翻译:nana,编辑:picar)

文章来源:创业邦
喜欢 (0)
分享到:

评论 抢沙发

登录后发表你的伟大言论!

立即登录