
本文开端发表于 Uber 官方博客网站,经授权,由 InfoQ 中文站翻译并发布。
自 2014 年 10 月起,Uber 走上了规划化扩张之旅,这段旅程终究成为公司最令人形象深入的添加阶段之一。跟着时刻的推移,咱们每个月都在非线性扩展工程团队的规划,并在全球获得了数以百万计的用户。
在本文中,咱们将为读者介绍 Uber API 网关演化的不同阶段,这个网关为 Uber 产品供给了支撑。咱们将经过回忆历史来了解架构的演化史,这些演化是伴跟着高速添加阶段而产生的。咱们将论述这三代网关体系的演化史,讨论它们的应战和职责。
假如你在 2014 年查询 Uber 架构的话,就会发现有两个要害服务:调度和 API。调度服务担任衔接乘客(Rider)和司机(Driver),API 服务是咱们用户和行程的长时刻存储库。除此之外,还有不到 10 个微服务,用来支撑咱们客户运用程序上的要害流程。
乘客运用程序和司机运用程序都运用坐落“/”的单一终结点衔接调度服务。端点的主体有一个名为“messageType
”的特别字段,该字段决议了调用特定处理程序的 RPC 指令。该处理程序以 JSON 有用负荷进行呼应。
在这组 RPC 指令中,有 15 个指令是为要害的实时操作保存的,比方,答应司机同伴开端承受行程、回绝行程和乘客恳求行程。一个特别的messageType
被命名为 “ApiCommand
”,它将一切恳求署理到 API 服务,并供给一些来自调度服务的附加上下文。
在 API 网关的上下文中,看起来ApiCommand
是咱们进入 Uber 的门户。第一代网关是单一的单体服务有机演化的成果,它开端服务于实在的用户,并找到了运用附加的微服务进行扩展的办法。调度服务作为面向大众的 API 移动接口,包括一个具有匹配逻辑的调度体系和署理,用于将一切其他流量路由到 Uber 内的其他微服务。
可是,第一代体系的光辉日子并没有继续很长时刻,由于它在前几年就现已投产了。到 2015 年 1 月,一个全新的 API 网关(能够说是第一个真实的网关)蓝图现已发动,第一个语义 RESTful API 被布置,答应 Uber 乘客运用程序查找目的当地位,每秒查询数(Queries per second,QPS)可达几千次,这是朝着正确方向迈出的第一步。
Uber 在前期就选用了微服务架构。这一架构决议计划终究导致了 2200 多个微服务的添加,到 2019 年,这些微服务为 Uber 一切产品供给了动力。
API 网关曾被命名为 RTAPI,是 Real-Time-API 的缩写。它在 2015 年头以一个单一的 RESTful API 开端,并开展成为具有许多面向公共的 API 网关,并为 20 多个不断添加的移动和 Web 客户端组合供给支撑。该服务是单一的存储库,跟着它继续以指数级的速度添加,被分解为多个专门的布置组。
这个 API 网关是 Uber 最大的 NodeJS 运用程序之一,有一些令人形象深入的统计数据:
-
跨 110 个逻辑端点分组的多个端点;
-
40% 的工程师已将代码提交到这一层;
-
峰值时高达 800000 个恳求 / 每秒;
-
为客户供给 120 万次翻译,以完结数据本地化;
-
在 5 分钟内对每个差异履行 50000 次集成测验;
-
有很长一段时刻,简直每天都会进行一次布置;
-
大约有 100 万行代码处理最要害的用户流;
-
大约 20% 的移动构建是由这一层界说的形式生成的代码;
-
与 Uber 100 多个团队具有的约 400 多个下流服务进行通讯;
第二代网关的方针
公司内部的每一个根底设施都有一组预订的方针要满意。有的方针是开端规划时就开端的,有些则是在规划进程中逐渐完结的。
解耦
100 多个团队并行构建功用。由后端团队开发的供给根底功用的微服务数量呈爆破式添加。前端团队和移动团队正在以相同快的速度构建产品体会。网关供给了所需的解耦,并答应咱们的运用程序继续依靠安稳的 API 网关和它供给的合约。
协议转化
一切移动客户端到服务器的通讯首要运用 HTTP/JSON。在内部,Uber 还推出了一种新的内部协议,旨在供给多路复用双向传输协议。曾经有一段时刻,Uber 的每个新服务都选用了这个新协议。这就使得后台体系的服务在这两种协议之间变得四分五裂。这些服务的某些子集也答应咱们只能经过对等网络来处理这些问题。其时的网络协议栈也处于十分前期的阶段,网关保护咱们的产品团队不受底层网络改变的影响。
流式有用负荷
削减往复
曩昔十年,互联网在处理 HTTP 协议栈的各种缺陷方面取得了开展。削减 HTTP 上的往复是前端运用程序运用的一项众所周知的技能(请记住图画精灵、用于财物下载的多个域等)在微服务架构中,削减拜访微服务功用的往复次数在网关层结合在一同,网关层从各种下流服务中“涣散搜集”数据,以削减咱们的运用和后端之间的往复。这关于咱们在拉美、印度等国家的低带宽蜂窝网络上的用户来说尤为重要。
开发速度
对任何成功的产品而言,开发速度都是十分要害的特征。在整个 2016 年,咱们的新硬件根底设施并未完结 Docker 化,尽管供给新服务很简略,但硬件装备稍显杂乱。网关为团队供给了一个这样美妙的当地,让团队能够在一天之内开端并完结他们的功用。这是由于它是咱们的运用程序调用的体系,服务有一个灵敏的开发空间来编写代码,而且能够拜访公司内部的数百个微服务客户端。Uber Eats 的第一代产品完全是在网关内开发的。跟着产品的老练,部分产品被移出了网关。在 Uber,有许多功用完全是运用其它现有微服务的现有功用在网关层构建出来的。
面对的应战
技能应战
咱们开端的网关方针首要是受 I/O 约束的,而且有一个团队致力于支撑 Node.js。经过一轮又一轮的评定,Node.js 成了这个网关的首选言语。跟着时刻的推移,具有这样一种动态的言语,以及为 Uber 架构中如此要害的层中 1500 名工程师供给自在编码空间,都面对着越来越大的应战。
在某些时分,每一个新的 API/ 代码改变都要运转 5 万个测验,因而,要可靠地创立一个增量测验结构是很杂乱的,由于这个结构根据依靠项,且具有一些动态加载机制。当 Uber 的其他部分转向 Golang 和 Java 作为首要支撑的言语时,跟着新的后端工程师参加网关及其异步 Node.js 形式,工程师的速度慢了下来。
网关变得适当大了。它被贴上了 monorepo(单体式代码库房)的标签(该网关被布置为 40 多个独立服务),并将 2500 个 npm 库升级到较新版别的 Node.js,继续以指数级办法添加作业量。这就意味着咱们无法选用许多库的最新版别。这时,Uber 开端选用 gRPC 作为首选协议,而咱们的 Node.js 版别在这方面却毫无建树。
在代码检查和影子流量期间,指针反常(Null Point exception,NPE)是无法防止的,这会导致要害网关布置阻滞几天,直到 NPE 在一些不相关的、新的、未运用的 API 上得到修正。这样一来,就进一步拖慢了咱们的工程速度。
网关中代码的杂乱性与受 I/O 约束各走各路。由一些 API 引进的功用回归或许会导致网关变慢。
非技能性应战
网关的两个特定方针。“削减往复”和“开发速度”,给这个体系带来了很大的压力。这两个方针是导致许多事务逻辑代码走漏到网关的原因。有时,这种走漏是成心的,有时是无意的。由于代码超越一百万行,因而“削减往复”和许多的事务逻辑之间是适当难以区分的。
跟着网关成为保证客户继续移动的要害根底设施,网关团队开端成为 Uber 产品开发的瓶颈。咱们经过 API 分片布置和涣散检查缓解了这一问题,但成为瓶颈的问题没有处理到令人满意的程度。
这时,咱们不得不从头考虑下一代 API 网关的战略。
到 2018 年头,Uber 现已具有全新的事务线,并有了许多新的运用。事务线的数量再次添加:Freight(优步货运)、ATG(先进技能团队)、Elevate(优步航空)、Groceries(杂货配送)等。在每条事务线中,团队办理者的后端体系和运用需求相互独立,以便快速开发产品。网关有必要能够供给正确的功用集,这些功用实际上能够对它们进行加快,并防止上面说到的技能性和非技能性应战。
第三代网关的方针
第三代网关与第二代网关的规划有很大不同。在回忆一切技能性和非技能性的应战后,咱们开端规划第三代网关,并拟定了一套新方针。
这种新的架构鼓舞公司遵从分层的办法进行产品开发。
边际层:真实的网关体系,它供给了第二代体系的网关部分方针所描绘的一切功用,除了“开发速度”和“削减往复”。
表明层:专门为前端的功用和产品供给后端符号的微服务。这种办法导致产品团队办理自己的表明和编列服务,这些服务能够满意消费运用程序所需的 API。这些服务中的代码是针对视图生成和来自许多下流服务数据的聚合。有独自的 API 来修正以习惯特定顾客的呼应。例如,与规范的 Uber 乘客运用程序比较,Uber Lite 运用程序或许需求更少的与接送地图相关的信息。其间每一个都或许触及不同数量的下流调用,以运用某些视图逻辑核算所需的呼应有用负荷。
产品层:这些微服务被专门符号,以供给功用性的、可重用的 API 来描绘他们的产品 / 功用,这些或许会被其他团队重用来组合和构建新的产品体会。
域层:包括作为叶节点的微服务,为产品团队供给单一的优化功用。
削减边际层的方针
构成杂乱性的要害因素之一是第二代网关中的特别代码,它由视图生成和事务逻辑组成。在新的架构下,这两个功用已被移出到其他微服务,由独立团队在规范 Uber 库和结构上具有和运营。边际层是作为纯边际层运转的,没有定制代码。
要害是要留意,一些刚起步的团队能够具有一个单一服务来满意表明层、产品层和服务层的职责。跟着功用的开展,它能够被解构到不同的层。
这种架构供给了极大的灵敏性,能够从小规划开端,终究构成一个贯穿咱们一切产品团队的北极星架构。
技能构建块
在咱们尽力转移到新想象的架构时,咱们需求要害的技能组件就位。
边际网关
开端由咱们的第二代网关体系服务的边际层被一个独自的 Golang 服务和一个用户界面所替代。“边际网关”是内部开发的 API 生命周期办理层。一切 Uber 工程师现在都能够拜访其用户界面来装备、创立和修正面向产品的 API。用户界面既能够进行简略的装备(如身份验证),也能够进行高档装备(如恳求转化和标头传达)。
服务结构
鉴于一切的产品团队都要保护和办理一组微服务(或许是在这个架构的每一层,用于他们的功用 / 产品),边际层团队与言语途径团队协作,商定了一个名为“Glue”的规范化服务结构,将在整个 Uber 中运用。Glue 结构供给了一个树立在Fx依靠注入结构之上的 MVCS 结构。
服务库
网关中的代码类别归于“削减往复”和“用于前端的后端”这两个领域,需求在 Golang 树立一个轻量级 DAG 履行体系。咱们在 Golang 树立了一个内部体系,称为操控流结构(Control Flow Framework,CFF),它答应工程师在服务处理程序中为事务逻辑编列开发杂乱的无状况作业流。
树立信赖
会集式团队将一些高规划的 API 和要害端点搬迁到新的栈中,以验证尽或许多的用例,并验证咱们能够开端让外部团队搬迁他们的端点和逻辑。
查找一切者
由于有许多 API,咱们有必要清楚地确认一切权。要做成这件事并不简略,由于许多 API 具有跨团队具有的逻辑。关于明晰映射到某个产品 / 特性的 API,咱们会主动分配它们,但关于杂乱的 API,咱们逐一处理并洽谈一切权。
许诺
在将其分红团队之后,咱们将端点团队分红许多组(一般按较大的公司安排结构,例如乘客、司机、付出、安全等),并联络工程领导,以期在 2019 年全年找到一个工程部和项目部的 POC 来带领他们的团队。
训练
会集式团队对工程和项目担任人进行了训练,让他们了解“怎么”搬迁、“需求留意什么”、“何时”搬迁等。咱们树立了支撑途径,来自其他团队的开发人员能够在搬迁进程中寻求问题和帮忙。为了保证团队承当职责,供给进展的可视性,并更新领导才能,咱们还布置了一个主动化的会集盯梢体系。
迭代战略
在搬迁进程中,咱们遇到了一些边际状况,并对假定提出了质疑。有好几次,咱们引进了新的功用,而在其他时分,咱们挑选不运用与某层无关的功用来污染新的架构。
在搬迁进程中,咱们的团队不断考虑技能安排的未来和开展方向,并保证在这一年中对技能指导进行调整。
终究,咱们能够有用地履行咱们的许诺,并朝着自助式 API 网关和分层服务架构的方向跨进。
在 Uber 消耗时刻开发和办理了三代网关体系之后,下面是一些关于 API 网关的高层次调查。
假如有挑选的话,请坚持为你的移动运用和内部服务选用单一协议。由于选用多种协议和序列化格局终究会导致网关体系的巨大开支。具有一个单一协议为你供给了挑选,你的网关层能够有多丰厚的功用。它能够是简略的署理层,也能够是极端杂乱和功用丰厚的网关,能够运用自界说 DSL 完结 graphQL。假如有多个协议要搬迁,网关层就会不得不变得杂乱,以完结将 http 恳求路由到另一个协议的服务的最简略进程。
规划你的网关体系,使其能够横向扩展是十分要害的。关于像咱们第二代和第三代这样杂乱的网关体系来说,更是如此。为 API 组构建独立二进制的才能是咱们第二代网关能够横向扩展的一个要害特性。单一的二进制文件过于巨大,无法运转 1600 个杂乱的 API。
根据用户界面的 API 装备关于现有 API 中的增量更改十分有用,可是创立新的 API 一般是一个多进程的进程。作为工程师,有时用户界面或许会感觉比直接在检查过的的代码库上作业更慢。
咱们从第二代到第三代的开发和搬迁时刻长达 2 年。跟着工程师在项目表里的过渡,继续出资至关重要。最终,每一个新体系不需求支撑来自旧体系的一切技能债款功用。有意识地挑选抛弃支撑对长时刻可继续性至关重要。
回忆咱们网关的演化史,人们会想,咱们是否能够越过一代,抵达现在的架构?任何一家还没有开端该进程的公司或许也会想,是否应该从自助式 API 网关开端?这是一个很难做出的决议,由于这些演化并不是独立的决议。许多工作取决于整个公司的支撑体系的演化状况,比方根底设施、言语途径、产品团队、添加、产品规划等等。
在 Uber,咱们发现了这一最新架构成功的有力目标。咱们在第三代体系中每天的 API 改变现已超越了第二代的数字,这直接关系到节奏更快的产品开产生命周期。转移到根据 Golang 的体系后,咱们的资源运用率和恳求 / 中心衡量现已显著地提高了。咱们大多数 API 上的推迟数都现已显著地削减了。跟着新架构的老练和旧体系在其天然重写周期中被重写到较新的分层架构中,还有很长的一段路要走。
Madan Thangavelu 是 Uber 高档工程司理。在曩昔的 6 年里,他见证了 Uber 令人兴奋的高速添加阶段,并为此做出了奉献。他花了 4 年的时刻领导 Uber 的网关途径团队。现在,他担任 Uber 完结途径的工程主管,该途径为全球实时购物和物流体系供给支撑。
Uday Kiran Medisetty 是 Uber 的高档工程师。。他在第二代 API Gateway 发布不到 10 个 API 时参加了团队,帮忙扩展到 1600 个 API,并帮忙拟定了第三代网关的战略,还领导了根据服务器到客户端的实时移动体会推送音讯的开发。在曩昔的几年里,他正在领导 Uber 中心完结途径的从头架构。
Pavel Astakhov 是 Uber 的高档技能项目司理。在曩昔的两年里,他领导了整个公司的多个大型跨功用根底设施项目,并与 Madan 和 Uday 一同开发和领导了从边际层的第二代到第三代过渡的履行战略 / 搬迁。
原文链接
https://eng.uber.com/gatewayuberapi/
今天引荐文章
点个在看少个 bug
👇