# 从将 Uber 扩展到 2000 名工程师，1000 个服务和 8000 个 Git 存储库获得的经验教训

> 原文： [http://highscalability.com/blog/2016/10/12/lessons-learned-from-scaling-uber-to-2000-engineers-1000-ser.html](http://highscalability.com/blog/2016/10/12/lessons-learned-from-scaling-uber-to-2000-engineers-1000-ser.html)

<iframe allowfullscreen="" frameborder="0" height="200" src="https://www.youtube.com/embed/kb-m2fasdDY?start=57" width="425"></iframe>

为了了解 Uber 的成长情况，请看上述视频的前几秒钟。 它将在正确的位置开始。 它来自[，Uber 首席系统架构师和](https://www.linkedin.com/in/mranney) [Voxer](http://www.voxer.com/) 的共同创始人 Matt Ranney 的精彩演讲：[我希望将 Uber 扩展到 1000 个服务之前想知道的事情](https://www.youtube.com/watch?v=kb-m2fasdDY)（[[幻灯片](https://gotocon.com/chicago-2016/presentation/What%20I%20Wish%20I%20Had%20Known%20Before%20Scaling%20Uber%20to%201000%20Services)）。

它显示了中国一些城市不断增长的，有节奏的，波动的交通网络。 世界各地的城市都在发生这种爆炸性增长的方式。 实际上，Uber 现在已遍布 400 个城市和 70 个国家/地区。 他们有 6000 多名员工，其中 2000 名是工程师。 仅仅一年半的时间，只有 200 名工程师。 这些工程师已经产生了 1000 多种微服务，这些微服务存储在 8000 多个 git 存储库中。

在短时间内疯狂增长 10 倍。 谁经历过？ 不太多。 就像您可能期望的那样，这种独特的，压缩的，快节奏的，高风险的经验必须教会您一些新知识，比以前理解的要深刻。

马特不是这个游戏的新手。 他是 Voxer 的共同创始人，Voxer 经历了[的快速增长](http://www.marketwired.com/press-release/walkie-talkie-app-voxer-soars-past-billion-operations-per-day-powered-basho-riak-1603652.htm)，但这是不同的。 您可以在观看视频时告诉您 Matt 试图对他们所取得的成就表示满意。

马特是一个有思想的人，这是有根据的。 在[最近的一次采访](https://www.infoq.com/articles/podcast-matt-ranney)中，他说：

> 在 QCon 和其他活动上进行的许多架构讨论使我感到不足够。 和其他人（例如 Google）一样，一切都明白了，但我却没有。

马特（Matt）这次演讲是在大漩涡之外走了一下，试图使自己的经历有意义，并试图弄清一切。 他成功了。 疯狂地。

这部分是智慧的谈话，部分是悔。 马特说：“一路上犯了很多错误，而这些正是从中汲取教训的。

演讲的脚手架挂在 WIWIK（我希望我知道的）设备上，该设备已成为互联网的模因。 这是他建议给自己幼稚的一年半的幼稚自我的建议，尽管当然，像我们所有人一样，他当然不会听。

而且他不会孤单。 很多人批评 Uber（ [HackerNews](https://news.ycombinator.com/item?id=12597232) ， [Reddit](https://www.reddit.com/r/programming/comments/54y5by/what_i_wish_i_had_known_before_scaling_uber_to/) ）。 毕竟，这些数字实在是太疯狂了。 两千名工程师？ 八千个存储库？ 一千个服务？ 一定是很严重的错误，不是吗？

也许。 令人惊讶的是，马特对整个事情没有判断力。 他的询问方式更多是质疑和搜索，而不是寻找绝对值。 他本人似乎对存储库的数量感到困惑，但是他给出了更多存储库与更少存储库的优缺点，而没有说哪个更好，因为考虑到 Uber 的情况：您如何定义更好？

优步正在全球范围内展开激烈的战斗，以构建一个能够占领赢家通吃的市场的行星尺度系统。 那就是商业模式。 成为最后一个服务站。 在这种情况下，更好的意思是什么？

赢家通吃意味着您必须快速成长。 您可能会变慢并显得更有条理，但如果变慢，就会迷失方向。 因此，您可以在混乱的边缘保持平衡，并将脚趾或整个身体浸入混乱中，因为这将成为您扩展成为全球主导服务的方式。 这不是一条缓慢的增长之路。 这敲门，采取一切策略。 认为您可以做得更好？ 真？

微服务非常适合 Uber 想要实现的目标。 塞住你的耳朵，但这是康威定律的事情，你会获得如此多的服务，因为这是那么多人被雇用并提高生产力的唯一途径。

如此多的服务没有技术原因。 没有这么多存储库的技术原因。 这一切都是关于人的。 [老婆婆](https://news.ycombinator.com/item?id=12598893)很好地总结了一下：

> 扩展流量不是问题。 扩大团队规模和产品功能发布率是主要因素。

演讲的一个一致主题是*不错，但存在一些权衡取舍，通常是令人惊讶的权衡，您实际上只是在规模上才能体验到*。 这引出了我从演讲中获得的两个最大想法：

*   **微服务是一种用 API 协调**代替人类交流的方式。 与人们谈论和处理团队政治相比，团队更容易编写新代码。 它使我想起了我很久以前读过的一本书，不记得这个名字了，人们居住在戴森球体内部，并且因为球体内部有太多空间和如此多的自由能，以至于当任何一个团体与另一个团体发生冲突时 他们可能会分裂并适应新的领域。 这是否更好？ 我不知道，但这确实可以并行完成许多工作，同时又避免了很多人的开销。
*   **纯胡萝卜，不粘**。 关于命令和控制的作用如此广泛，这是一个很深的观点。 您会很想执行政策。 *例如，您应该以这种方式记录*。 如果您不这样做，将会有后果。 那是棍子。 马特说不要那样做。 改用胡萝卜。 每当棍棒冒出来都是不好的。 因此没有任何授权。 您想要处理它的方式是提供非常明显且易于使用的工具，以至于人们不会以其他任何方式使用它。

这是您必须真正了解的那些谈话之一，因为除了文本以外，还有很多其他方面的交流。 虽然当然我仍然鼓励您阅读我的演讲掩饰:-)

## 统计信息（2016 年 4 月）

*   优步遍布全球 400 个城市。

*   70 个国家。

*   6000 多名员工

*   2000 名工程师（一年半前有 200 名工程师）

*   1000 个服务（数量近似）

    *   不同服务的数量变化如此之快，以至于很难准确计算生产中的实际服务数量。 许多团队正在建立很多东西。 甚至都不在乎实际的数字。

*   超过 8000 个 git 回购。

## 微服务

*   很高兴将您所有的整体分解成更小的东西。 甚至这个名字听起来也很糟糕。 但是微服务有其不利的一面。

*   事情最有可能破裂的时间就是您进行更改的时间。 即使是在 Uber 最忙的时候，周末 Uber 在工程师不进行更改的情况下也是最可靠的。

*   每当您进行更改时，都有可能破坏它。 永远不要接触微服务是否有意义？ 也许。

*   好

    *   值得质疑，为什么我们要在微服务上投入如此多的精力？ 这不是偶然的，有很多好的结果。

    *   微服务允许团队快速组建并独立运行。 人们一直在被添加。 团队需要迅速组建起来，并在可以推断边界的地方开展工作。

    *   拥有自己的正常运行时间。 您运行您编写的代码。 所有服务团队都在征求他们在生产中运行的服务。

    *   使用最佳工具进行作业。 但是最好的方式是什么？ 最好写？ 最好跑？ 最好，因为我知道吗？ 最好，因为有图书馆？ 当您深入研究时，最好并不意味着什么。

*   明显的成本

    *   运行大型微服务部署的成本是多少？

    *   现在，您正在运行分布式系统，这比使用整体系统更难。

    *   一切都是 RPC。 您必须处理所有这些疯狂的失败模式。

    *   如果中断怎么办？ 您如何排除故障？ 您如何确定中断在服务链中的何处发生？ 如何确保合适的人得到传呼？ 采取了正确的纠正措施来解决问题？

    *   这些仍然是显而易见的成本。

*   不太明显的费用

    *   一切都是权衡，即使您没有意识到自己正在做到。 作为所有这些微服务的交换，您可以获得某些东西，但是您也放弃了一些东西。

    *   通过对所有事物进行超级模块化，我们引入了一些细微而又不明显的问题。

    *   您可能选择构建新服务，而不是修复已损坏的内容。 在某些时候，始终围绕问题解决和清理旧问题的成本已成为一个因素。

    *   **您发现自己为政治**交易很复杂。 您不必编写笨拙的对话，而充满人类的情感，而是可以编写更多的软件而避免说话。

    *   **您可以保持自己的偏见**。 如果您喜欢 Python 以及与您喜欢的节点打交道的团队，则可以使用自己喜欢的语言来构建新的东西，而不必使用其他代码库。 即使对于组织或整个系统而言，这可能并不是最好的事情，但您仍要继续做自己认为最好的事情。

## 拥有多种语言的成本

*   史前史：最初，Uber 被 100％外包。 看来这似乎不是技术问题，所以一些公司编写了移动应用程序的第一个版本和后端。

*   调度：内部开发时，它是用 Node.js 编写的，现在正在迁移到 Go。

*   核心服务：系统的其余部分，最初是用 Python 编写的，现在正在迁移到 Go。

*   Maps 最终被引入内部，这些团队正在使用 Python 和 Java。

*   数据工程团队使用 Python 和 Java 编写代码。

*   内部度量系统用 Go 编写。

*   您开始注意到有很多语言。 微服务使您可以使用多种语言。

*   团队可以用不同的语言编写并且仍然可以相互交流。 它可以工作，但需要付费：

    *   难以共享代码。

    *   难以在团队之间移动。 在一个平台上积累的知识不会转移到另一平台上。 任何人当然都能学到，但是要付出一定的代价。

*   **我希望知道的内容**：拥有多种语言会破坏文化。 通过在任何地方都接受微服务，您最终可以扎营。 这里有一个节点营，一个 Go 营，等等。人们围绕部落组织起来是很自然的事，但是要接受到处都有多种语言的策略是有代价的。

## RPC 的成本

*   团队使用 RPC 相互通信。

*   大量的人很快就真正加入了 HTTP 的弱点。 像什么状态代码？ 标头是做什么用的？ 查询字符串中包含什么？ 这是 RESTful 吗？ 这是什么方法

*   所有这些事情在执行浏览器编程时看上去确实很酷，但是在进行服务器编程时却变得非常复杂。

*   您真正想说的是在那里运行此功能，并告诉我发生了什么。 相反，使用 HTTP / REST 会遇到所有这些细微的解释问题，这一切都非常昂贵。

*   JSON 很棒，您可以用眼球看一下并阅读它，但是如果没有类型，这是一个疯狂的混乱，但不是马上，问题随后就会出现。 当某人更改某些内容并在下游跳了几步时，他们依赖于对空字符串与 null 的某种微妙解释，或者某种语言对另一种语言的某种类型的强制转换，这会导致巨大的混乱，需要花费很长的时间才能解决。 接口上的类型将解决所有这些问题。

*   RPC 比过程调用慢。

*   **我希望知道的内容**：服务器不是浏览器。

    *   当在数据中心中进行交谈时，将所有内容都视为函数调用而不是 Web 请求，这更加有意义。 当您控制对话的双方时，您并不需要所有多余的浏览器内容。

## 储存库

*   最好的回购数量是多少？ 他认为最好的是一个，但许多人不同意。

*   许多人认为很多回购是最好的。 每个项目可能一个，甚至每个项目多个。

*   具有许多存储库是遵循具有许多小型模块的行业趋势。 小型模块易于开源或交换。

*   一个仓库很不错，因为您可以进行跨领域更改。 您想要进行更改，可以轻松找到所有需要更改的代码。 浏览代码也很容易。

*   有很多不好的地方，因为这会给您的构建系统带来压力。 这会损害您浏览代码的能力。 确保正确完成跨领域更改很痛苦。

*   一个不好的原因是，它将变得如此之大，除非您拥有一些疯狂的精心设计的系统，否则您将无法构建或检验您的软件。 如果没有特殊工具，一个仓库可能无法使用。 Google 有一个存储库，但它使用虚拟文件系统，好像您已检出整个存储库。

*   超过 8000 个 git 回购。 一个月前有 7000。

    *   有些人有自己的仓库。

    *   一些团队使用单独的存储库与服务本身分开跟踪服务配置。

    *   但是大多数是生产仓库。

*   很多回购。

## 操作问题

*   事情破裂了怎么办？ 大型微服务部署会带来一些令人惊讶的问题。

*   如果其他团队无法使用您的服务，而该服务尚未准备好发布，那么其他团队是否可以在您的服务中添加修复程序并将其发布？

    *   即使您的所有测试都通过了，您拥有的正常运行时间是否也与其他发布您服务的团队兼容？ 自动化是否足够好，团队可以相互发布软件？

    *   在 Uber，这取决于情况。 有时是的，但通常答案是“否”，团队将只需要阻止此修复程序。

*   大而小的团队，每个人都在快速前进，所有功能都超级快地发布，但是有时您必须将整个系统理解为一台大型机器连接在一起的一件事。 当您花费所有时间将其分解为微服务时，这很难。

    *   这是一个棘手的问题。 希望将更多的时间花在保持上下文关联上。

    *   应该仍然能够理解整个系统的整体功能。

## 性能问题

*   鉴于微服务彼此之间的依赖程度，性能肯定会提高。

*   RPC 昂贵，尤其是当存在多种语言时，如何理解性能的答案完全取决于语言工具，并且工具都是不同的。

*   您已经让每个人都使用自己的语言进行编程，现在了解这些语言的性能是一个真正的挑战。

*   尝试使用 [火焰图](http://www.brendangregg.com/flamegraphs.html) 使所有语言具有通用的分析格式。

*   当您想了解系统的性能时，在试图解决性能问题时，一个很大的摩擦就是工具的差异。

*   每个人都想要一个仪表盘，但是如果没有自动生成仪表盘，团队将只把他们认为重要的东西放在仪表盘上，因此当您要追查一个团队的仪表盘时，问题看上去将与另一个团队完全不同。

*   每个服务在创建时都应该具有一个标准的仪表板，其中包含相同的有用数据集。 应该能够创建一个完全没有工作的仪表板。 然后，您可以浏览其他团队的服务，并且看起来都一样。

*   **我希望知道的内容**：不需要良好的表现，但您需要知道自己的立场。

    *   一个大争论是，您是否应该关心性能。 “过早的优化是万恶之源”的类型思维催生了反对优化的人们非常奇怪的亚文化。 没关系，服务并不那么忙。 我们应该始终针对显影剂速度进行优化。 购买计算机比雇用工程师便宜。

    *   对此有一定道理。 工程师非常昂贵。

    *   问题在于，性能要紧要紧。 有一天，您将遇到绩效问题，如果已经建立起一种无关紧要的文化，那么突然之间变得至关重要很困难。

    *   您希望根据创建的所有内容获得某种性能的 SLA，以便有一个数字。

## 扇出问题-跟踪

*   扇出会导致很多性能问题。

*   想象一个典型的服务，即 99％的时间在 1 毫秒内做出响应。 它在一秒钟内响应的时间为 1％。 还算不错。 用户有 1％的时间会遇到这种情况。

*   现在，我们假设服务开始大张旗鼓，开始调用许多其他服务。 响应时间变慢的机会迅速增加。 至少在 1 秒钟内使用 100 个服务和 63％的响应时间（1.0-.99 ^ 100 = 63.4％）。

*   分发跟踪是您跟踪扇出问题的方式。 如果无法理解整个体系结构中的请求，将很难跟踪扇出问题。

    *   Uber 正在使用 [OpenTracing](https://github.com/opentracing) 和 [Zipkin](https://github.com/openzipkin/zipkin) 。

    *   另一种方法是使用日志。 每个日志条目都有一个公共 ID，该 ID 将所有服务组合在一起。

*   给出了一个棘手的例子。 顶层对所有相同服务均具有大量扇出。 当您查看服务时，它看起来不错。 每个请求都是快速且一致的。 问题是顶级服务获得了 ID 列表，并正在为每个 ID 调用服务。 即使同时进行，也将花费太长时间。 只需使用批处理命令即可。 如果不进行跟踪，很难找到这个问题。

*   另一个示例是进行了数千次服务调用的服务。 尽管每个呼叫都很快，但大量呼叫却使服务变慢。 事实证明，遍历列表并更改属性后，它神奇地变成了数据库请求。 但是数据库团队说，由于每个操作都很快，所以数据库运行良好，但是他们会想知道为什么会有这么多操作。

*   跟踪的开销可以更改结果。 跟踪是很多工作。 一种选择是不跟踪所有请求。 跟踪请求的统计显着部分。 Uber 跟踪约 1％的请求。

*   **我希望知道的内容**：跟踪需要跨语言的上下文传播。

    *   因为所有这些不同的语言都用于所有这些不同的框架，所以获取请求的上下文（例如请求的用户）是经过身份验证的，是在什么地理围栏内，如果没有放置位置，这将变得非常复杂 将会传播的上下文。

    *   服务提出的任何依赖请求都必须传播上下文，即使他们可能不理解上下文也是如此。 如果很久以前添加此功能，它将节省大量时间。

## 正在记录

*   拥有一堆不同的语言，一群团队和许多新人，一半的工程团队已经存在了不到 6 个月，每个人可能都倾向于以完全不同的方式登录。

*   任务授权是一个棘手的词，但这就是您真正想要做的事情，它要求一种通用的日志记录方法。 更为可接受的说法是，它提供了如此显而易见且易于使用的工具，人们不会以任何其他方式来获得一致且结构化的日志记录。

*   多种语言使得难以记录。

*   如果存在问题，日志记录本身可能会使日志记录过多而使这些问题更加严重。 日志中需要背压以在过载时删除日志条目。 希望早些时候已放入系统中。

*   **我希望知道的内容**：关于日志消息大小的一些概念，以便可以跟踪谁在生成过多的日志数据。

    *   所有日志发生的事情是它们被某种工具索引，以便人们可以搜索它们并学习事物。

    *   如果免费记录，则记录的数据量是可变的。 有些人会记录很多数据，使系统不堪重负。

    *   对于计费系统，当将日志数据发送到群集以建立索引时，可以将帐单发送到服务以进行支付。

    *   的想法是给开​​发人员以更大的压力，使他们更聪明地记录日志，而不是更难。

    *   Uber 创建了 [uber-go / zap](https://github.com/uber-go/zap) 用于结构化日志记录。

## 负载测试

*   想要在将服务投入生产之前进行负载测试，但是无法构建与生产环境一样大的测试环境。

*   这也是生成实际测试数据以测试系统所有部分的问题。

*   解决方案：在非高峰时段对生产进行测试。

*   引起很多问题。

*   它炸毁所有指标。

    *   您不希望人们认为负载多于实际负载。 为了解决该问题，它又回到了上下文传播问题。

    *   确保所有测试流量请求都具有表示此测试请求的上下文，因此请以不同的方式处理指标。 这必须贯穿整个系统。

*   **我希望知道的内容**：我们真正想要做的是始终在所有服务中运行负载，因为许多错误仅在流量达到峰值时才会出现。

    *   希望将系统保持在峰值附近，并随着实际流量的增加而退缩。

    *   希望该系统很早以前就已建立，可以处理测试流量并以不同的方式处理它。

## 故障测试

*   **我希望知道的内容**：并非每个人都喜欢混沌猴子那样的失败测试，​​尤其是如果您稍后要添加它时。

    *   如果您不喜欢，我们应该做的是对您进行故障测试。 这只是生产的一部分。 您的服务仅需承受随机的杀戮，操作的减慢和干扰。

## 迁移

*   我们所有的东西都是遗产。 全部都是迁移。 通常，从事存储工作的人们正在做的事情就是从一个旧版迁移到另一个旧版。

*   有人总是在某处迁移某物。 不管人们在会议上怎么说，这就是每个人都在做的事情。

*   旧的东西必须保持工作状态。 业务仍然必须运行。 不再有维护窗口之类的东西。 可接受的停机时间。

*   随着您成为一家全球企业，没有高峰时间。 总是高峰时间在某个地方。

*   **我希望知道的内容**：迁移的要求很糟糕。

    *   没有人希望被告知必须采用某种新系统。

    *   使某人发生变化是因为组织需要进行变化，而不是提供一个更好的新系统，因此显然您需要接受这一新事物。

    *   纯胡萝卜，不粘。 无论何时出现问题，除非与安全性或合规性有关，否则这是不好的，强迫人们做事可能是可以的。

## 开源

*   没有人同意建立/购买权衡。 你什么时候建造？ 你什么时候应该买？

*   属于基础架构的任何东西，看起来像是平台的一部分而不是产品的一部分的任何东西，在某个时候都将成为无差别的商品。 亚马逊（或某人）将提供它作为服务。

*   最终，您花了所有时间在做这件事，其他人会以更便宜和更好的方式来做。

*   **我希望知道的内容**：如果人们正在使用某种平台类型的功能，那么听到亚马逊刚刚发布您的服务即服务听起来并不好。

    *   您仍在尝试合理化为什么应将自己的私人物品用作服务。

    *   事实证明，那些人在这些文本编辑器的另一端。 人们对构建/购买权衡的判断方式存在巨大差异。

## 政治

*   通过将所有内容分解为小型服务，可以使人们玩政治。

*   每当您做出违反此属性的决定时，就会发生政治事件：公司>团队>自我。

    *   您将自己的价值观置于团队之上。

    *   团队的价值高于公司。

*   政治不只是您不喜欢的决定。

*   通过拥抱高度模块化的快速发展，非常快地雇用人员并尽快发布功能，人们开始倾向于违反此属性。

    *   当您重视以较小的个人成就来交付产品时，很难确定对公司有利的优先事项。 令人惊讶的权衡。

## 权衡取舍

*   一切都是权衡。

*   **我希望知道的内容**：如何更好地有意进行这些折衷。

    *   当事情在没有明确决定的情况下发生时，因为这似乎是事情的发展方向，即使没有明确做出决定，也要考虑做出什么权衡。

## 相关文章

*   [关于 HackerNews](https://news.ycombinator.com/item?id=12697006)

*   关于在 HackerNews 和 [上的视频](https://www.reddit.com/r/programming/comments/54y5by/what_i_wish_i_had_known_before_scaling_uber_to/) [的精彩讨论，关于[Reddit]](https://news.ycombinator.com/item?id=12597232)

*   [扩展流量高的 Feed 的设计决策](http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic-feeds.html)

*   [Google On Latency Tolerant Systems：由不可预测的部分组成可预测的整体](http://highscalability.com/blog/2012/6/18/google-on-latency-tolerant-systems-making-a-predictable-whol.html)

*   [Uber 如何扩展其实时市场平台](http://highscalability.com/blog/2015/9/14/how-uber-scales-their-real-time-market-platform.html)

*   [Uber 变得与众不同：使用驾驶员电话作为备份数据中心](http://highscalability.com/blog/2015/9/21/uber-goes-unconventional-using-driver-phones-as-a-backup-dat.html)

*   [Uber 如何使用 Mesos 和 Cassandra 跨多个数据中心每秒管理百万个写入](http://highscalability.com/blog/2016/9/28/how-uber-manages-a-million-writes-per-second-using-mesos-and.html)

*   [与 Matt Ranney 缩放 Uber](http://softwareengineeringdaily.com/2015/12/04/engineering-at-uber-with-matt-ranney/)

*   [InfoQ 播客：Uber 的首席系统架构师，介绍其架构和快速发展](https://www.infoq.com/articles/podcast-matt-ranney)

*   [分布式 Web 架构：Matt Ranney，Voxer](https://gaming.youtube.com/watch?v=pXT0mF9bMyA)

*   [Riak at Voxer-Matt Ranney，RICON2012](https://vimeo.com/52827773)

优步遍布 400 多个城市。 因此，请在帖子中更正此问题。

谢谢

这是我一生中读过的最好的经验教训文章之一。 这是一项毫不废话，诚实和实践的知识共享活动。 许多公司正在努力适应不断变化的新技术，例如带有 Docker 的微服务，CI / CD，Paas，Saas 和 Cass。 正如他在视频中正确指出的那样，这始终是一种思维定势/文化的挑战，每个人对编程语言，方法等都有自己的看法。认识到这一事实并引导每个人实现业务需求的共同目标很重要。

难以置信！ 从头到尾纯粹基于经验的演讲

很棒的文章，有非常有用的信息。

完全基于经验非常坦率非常实用。 他吸取的教训是休息的智慧。