【AICon】探索八个行业创新案例,教你在教育、金融、医疗、法律等领域实践大模型技术! >>> 了解详情
写点什么

数据库连接从 15000 降到 100 以下:DigitalOcean 如何解决技术债

  • 2020-03-14
  • 本文字数:3226 字

    阅读完需:约 11 分钟

数据库连接从15000降到100以下:DigitalOcean如何解决技术债

本文最初发布于 DigitalOcean 官方博客,经原作者授权由 InfoQ 中文站翻译并分享。


最近,一位新员工在午餐时问我:“DigitalOcean 的技术债务是什么情况?”


听到这个问题时,我忍不住笑了。软件工程师询问一家公司的技术债务就相当于询问其信用评分。这是他们衡量一家公司过去的遗留问题以及他们所要背负的包袱的方法。DigitalOcean 对技术包袱并不陌生。


作为云提供商,我们管理着自己的服务器和硬件,我们面临着许多其他初创公司在这个云计算的新时代尚未遇到的复杂性。这些艰难的情况最终迫使我们不得不早做权衡。任何快速成长的公司都知道,你早期做出的技术决定往往会在以后影响到你。


盯着桌子对面的新员工,我深吸了一口气,然后开始说。“让我告诉你,我们有 15000 个与数据库的直接连接……”



我给这位新员工讲的故事是 DigitalOcean 迄今为止最大的技术重组。这是整个公司多年来的努力,教会了我们很多东西。我希望,讲述这个故事可以帮助未来的 DigitalOcean 开发者——或任何发现自己陷入棘手的技术债务问题的开发者。

故事缘起

DigitalOcean 从一开始就痴迷于简单性。这是我们的核心价值观之一:力求简单而优雅的解决方案。这不仅适用于我们的产品,也适用于我们的技术决策。这一点在我们最初的系统设计中最为明显。


与 GitHub、Shopify 和 Airbnb 一样,DigitalOcean 也是在 2011 年从一个 Rails 应用程序开始的。我们内部称为 Cloud 的 Rails 应用程序管理着 UI 和公共 API 中的所有用户交互。Rails 服务有两个 Perl 编写的辅助服务:调度器和 DOBE(DigitalOcean 的后端)。调度器将调度并分配 Droplet 给管理程序,而 DOBE 负责创建实际的 Droplet 虚拟机。Cloud 和调度器作为独立的服务运行,而 DOBE 则运行在 fleet 中的每台服务器上。


无论是 Cloud、调度器,还是 DOBE,彼此之间都不能直接对话。他们通过 MySQL 数据库通信。这个数据库有两个作用:存储数据和代理通信。这三个服务都使用单个数据库表作为消息队列来传递信息。


每当用户新建一个 Droplet 时,Cloud 就会向队列插入一个新的事件记录。调度器每秒一次不断地在数据库中轮询新的 Droplet 事件,并将它们的创建工作安排给一个可用的管理程序。最后,每个 DOBE 实例将等待新调度的 Droplet 创建并完成任务。为了能检测到所有新的更改,这些服务器都需要在数据库中轮询表中的新记录。



虽然在系统设计方面,无限循环和让每个服务器直接连接到数据库可能比较低级,但它很简单,而且很有效——特别是在人手短缺的技术团队面临紧迫的期限和快速增长的用户群时。


四年来,数据库消息队列一直是 DigitalOcean 技术的支柱。在此期间,我们采用了微服务体系结构,用 gRPC 代替 HTTPS 进行内部通信,并取消了 Perl,代之以 Golang 作为后端服务。然而,所有的方法都指向 MySQL 数据库。


值得注意的是,不能仅仅因为某些东西是“遗产”就认为它功能不完善,应该被取代。Bloomberg 和 IBM 都有用 Fortran 和 COBOL 编写的遗留服务,这些服务产生的收入超过整个公司。另一方面,每个系统都有一个扩展限制。我们就要达到这个限制了。


从 2012 年到 2016 年,DigitalOcean 的用户流量增长超过了 1000%。我们在目录中添加了更多的产品,在基础设施中添加了更多的服务。这增加了数据库消息队列上进入的事件。对 Droplet 需求增加意味着调度器要加班加点地把它们分配到服务器上。不幸的是,对于调度器,可用服务器的数量不是静态的。



为了满足 Droplet 需求的不断增长,我们不断地增加服务器来处理流量。每个新的管理程序都意味着一个新的数据库持久连接。截至 2016 年初,该数据库拥有超过 1.5 万个直接连接,每一个连接每 1 到 5 秒就查询一次新事件。如果这还不够糟糕的话,每个管理程序用来获取新 Droplet 事件的 SQL 查询也变得越来越复杂。它已经变成了一个巨人,有 150 多行,18 张表关联在一起。令人印象深刻的是,它不稳定,而且很难维持。


不出所料,正是在这个时期,问题开始显现。单点故障和成千上万的依赖关系攫取了共享资源,不可避免地导致了一段时间的混乱。表锁和查询积压会导致停机和性能下降。


由于系统的紧耦合,我们没能找到一个清晰简单的解决方案来解决这个问题。Cloud、调度器和 DOBE 都是瓶颈。如果只修补其中一两个组件,就会将负载转移到其余的瓶颈组件上。因此,经过深思熟虑,工程师们想出了一个三管齐下的方案来解决这个问题:


  1. 减少数据库上直接连接的数量;

  2. 重构调度器的排名算法,改进可用性;

  3. 移除数据库的消息队列职责。

开始重构

为了解决数据库依赖,DigitalOcean 的工程师创建了事件路由器。事件路由器充当区域代理,代表每个数据中心中的每个 DOBE 实例轮询数据库。这样,就只有少数代理在做查询,而不是数以千计的服务器。每个事件路由器代理将获取特定区域中的所有活动事件,并将每个事件委派给适当的管理程序。事件路由器还将庞大的轮询查询拆分成更小、更容易维护的轮询查询。



当事件路由器上线后,数据库连接的数量从 15000 个减少到不足 100 个。


接下来,工程师们把目光投向了下一个目标:调度器。如前所述,调度器是一个 Perl 脚本,它决定哪个管理程序将托管一个创建好的 Droplet。它使用一系列查询来对服务器进行排序。每当用户创建一个 Droplet 时,调度器就用最好的机器更新表行。


虽然听起来很简单,但该调度器有一些缺陷。它的逻辑很复杂,很难处理。它是单线程的,在流量高峰期间性能会受影响。最后,该调度器只有一个实例,却必须为整个 fleet 服务。这是一个不可避免的瓶颈。为了解决这些问题,工程团队创建了调度器 V2。


更新后的调度器彻底修改了排名系统。它不从数据库中查询服务器指标,而是从管理程序中聚合它们,并将它们存储在自己的数据库中。此外,调度器团队使用并发和复制保证新服务的负载性能。


事件路由器和调度器 V2 取得了许多了不起的成果,消除了当时的许多架构缺陷。尽管如此,还是有一个明显的障碍。到 2017 年初,集中式 MySQL 消息队列仍然在使用——甚至还很频繁。它每天处理 40 万条新记录,每秒更新 20 次。


遗憾的是,移除数据库消息队列并不容易。第一步是避免服务直接访问它。数据库需要一个抽象层。它还需要一个 API 来聚合请求并代它执行查询。任何服务想要创建一个新事件,都需要通过 API 来实现。于是,Harpoon 诞生了。


不过,为事件队列构建接口这部分比较容易。事实证明,从其他团队那里获得支持更加困难。与 Harpoon 集成意味着团队将不得不放弃他们的数据库访问,重写他们的部分代码库,并最终改变他们一直以来做事的方式。这可不是件容易的事。


Harpoon 的工程师们逐个团队、逐个服务地将整个代码库迁移到他们的新平台上。这花了差不多一年的时间,但到 2017 年底,Harpoon 成为数据库消息队列的唯一发布者。


现在真正的工作开始了。对事件系统的完全控制意味着 Harpoon 可以自由地重新设计 Droplet 工作流了。


Harpoon 的第一个任务是将消息队列职责从数据库提取到自身。为此,Harpoon 创建了自己的内部消息队列,由 RabbitMQ 和异步 worker 组成。当 Harpoon 在一侧把新事件推入队列时,worker 在另一侧拉取它们。由于 RabbitMQ 取代了数据库队列,worker 可以方便地直接与调度器和事件路由器交互。因此,调度器 V2 和事件路由器不是通过轮询从数据库获取新变化,而是由 Harpoon 直接将更新推送给它们。截止到 2019 年本文撰写时,这就是 Droplet 事件架构所处的位置。


一路向前

在过去的 7 年里,DigitalOcean 已经从一家小型创业公司成长为今天这样的成熟的云提供商。与其他转型中的科技公司一样,DigitalOcean 会定期处理遗留代码和技术债务。无论是拆分单体应用、创建多区域服务,还是消除单点故障,我们 DigitalOcean 的工程师们始终致力于打造优雅而简单的解决方案。


这就是我们的基础设施如何随着用户群的发展而扩展的故事,希望你觉得这是个有趣而又有启发性的故事。我很乐意在下面的评论中看到你的想法!


原文链接:


From 15,000 database connections to under 100: DigitalOcean’s tale of tech debt


2020-03-14 10:001938

评论

发布
暂无评论
发现更多内容

Python With 关键字和语句

HoneyMoose

区块链与隐私计算保护数据产权,让个人隐私不再“裸奔”

CECBC

区块链

最简单的JVM内存结构图

叫练

JVM 堆栈 Java虚拟机 堆栈溢出 内存优化

【数独问题】入门题:判断一个数独是否有效 ...

宫水三叶的刷题日记

面试 LeetCode 数据结构与算法

微软的各种考试,不知道是不是真的“香”

IT蜗壳-Tango

3月日更

云边协同类型

lenka

3月日更

数字经济时代,区块链能否担当产业数字化转型核心赋能者?

CECBC

数字经济

二分查找以及变体

一个大红包

3月日更

网页设计指南

张鹤羽

28天写作 3月日更

62图带你入门Docker

我是程序员小贱

容器 面试 3月日更

手机高端化,需要不同却被认同

脑极体

Flink的状态编程和容错机制

五分钟学大数据

大数据 flink 28天写作 3月日更

推荐一款小众且好用的 Python 爬虫库

星安果

Python 爬虫 RoboBrowser

高效处理日均超 1000 亿次广告请求!Mobvista 是如何做到的?

亚马逊云科技 (Amazon Web Services)

DCache 分布式存储系统|List 缓存模块的创建与使用

TARS基金会

MySQL nosql 微服务 分布式缓存 TARS

算法攻关 - 验证二叉搜索树 (O(n))_098

小诚信驿站

刘晓成 小诚信驿站 28天写作 算法攻关 验证二叉搜索树

翻译:《实用的Python编程》05_00_Overview

codists

CloudQuery, 一款基于WEB的数据库客户端(转自杨建荣的工作笔记)

BinTools图尔兹

【技术干货】如何评价一款App的稳定性和质量?

性能优化 App 应用崩溃 anr 友盟

分销的智能变局,华为好望云服务的铁索连环

脑极体

多元化:为什么会产生不良资产?

boshi

战略思考 七日更 创业失败启示录

Wireshark 数据包分析学习笔记 Day8

穿过生命散发芬芳

Wireshark 数据包分析 3月日更

【最新】2021年Hive阶段最全面试真题-附答案

大数据技术指南

大数据 hive 面试 28天写作 3月日更

有钱人为什么配置加密货币?

CECBC

货币

神了!终于有人把困扰我多年的Spring Boot讲明白了

架构 微服务 框架

喜讯 | 音视频云服务商拍乐云荣登「2021值得关注的中国教育公司」榜单

拍乐云Pano

音视频 在线教育 互动课堂 白板 教育科技

如何与下属沟通?

石云升

程序员 28天写作 职场经验 管理经验 3月日更

数据湖到底是什么?有什么用?这篇文章告诉你

关二爷大数据笔记

大数据 数据湖 实时数仓

互联网人一天24小时在做些啥《打工人的那些事》

谙忆

10 个解放双手超实用在线工具,有些代码真的不用手写

比伯

Java 编程 架构 计算机 技术宅

公平

ES_her0

28天写作 3月日更

数据库连接从15000降到100以下:DigitalOcean如何解决技术债_数据库_Sunny Beatteay_InfoQ精选文章