写点什么

数据库连接从 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:002275

评论

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

MySql性能调优:实用的实践与策略

xfgg

MySQL 6 月 优质更文活动

智能坐席助手如何助力保险集团实现客户服务闭环管理?

中关村科金

企业服务 坐席助手

视频编码耗时长、编码帧发送失败…DVPP视频编码问题典型案例分析

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 6 月 PK 榜

全球企业KVM贡献榜公布,腾讯云再添1项核心突破

说山水

了解模型的元学习:Learning to Learn优化策略和Meta-Learner LSTM

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 6 月 PK 榜

NFTScan 成为 Coin98 官方 NFT 数据合作伙伴!

NFT Research

NFT\

重磅!龙蜥社区联合 3 家理事单位发布人才培养计划,推出“龙蜥+”合作模式

OpenAnolis小助手

开源 生态 龙蜥社区 理事单位 人才培养计划

软件测试/测试开发丨Pytest结合数据驱动-Excel

测试人

程序员 软件测试 Excel 数据驱动 pytest

「悦数图数据库」正式登陆西部数据交易中心

悦数图数据库

图数据库 数据交易 数据要素

inBuilder今日分享丨RESTful API动态发布技术

inBuilder低代码平台

Kafka单机搭建(信任认证/口令认证)

Shen-Xmas

kafka zookeeper 测试 搭建 单机

主流文件共享平台的传输加密秘密

镭速

2023-06-16:给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。 我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。 所谓「表现良好的时间

福大大架构师每日一题

golang 算法 rust 福大大架构师每日一题

TS中, Array.reduce提示没有与此调用匹配的重载?

林十二XII

英特尔发布全新量子芯片Tunnel Falls,硅自选量子比特有望更快实现量产

E科讯

分享|基于实时图技术的信用卡申请反欺诈应用

悦数图数据库

金融 图数据库 知识图谱 反欺诈

医疗虚拟仿真和虚拟现实有什么区别?哪个更好?

3DCAT实时渲染

虚拟仿真 实时渲染 云仿真

HMI和SCADA的定义 两者有什么不同

2D3D前端可视化开发

组态软件 工业自动化 SCADA 工业组态 HMI

毕业季618双节狂欢!来华为阅读享品质阅听,0元读好书

最新动态

亚毫秒 GC 暂停到底有多香?JDK17+ZGC 初体验|得物技术

得物技术

ZGC GC jdk17

生态伙伴 | 华秋硬创联合湾加速,共同加速企业发展

华秋电子

Python初学者友好丨详解参数传递类型

华为云开发者联盟

Python 人工智能 华为云 华为云开发者联盟 企业号 6 月 PK 榜

DBA 抓包神器 tshark 测评

爱可生开源社区

MySQL 网络协议 TCP协议 抓包工具

消保评级提升指南!保险公司如何高效开展消保工作?

中关村科金

解决方案

FP&A转型,企业全面预算管理发展的催化剂

智达方通

全面预算管理 企业全面预算管理

Controller Manager原理分析

穿过生命散发芬芳

6 月 优质更文活动

风景如旧

风景壁纸

数据库运维实操优质文章分享(含Oracle、MySQL等) | 2023年5月刊

墨天轮

MySQL 数据库 oracle postgresql opengauss

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