AI 年度盘点与2025发展趋势展望,50+案例解析亮相AICon 了解详情
写点什么

一次几乎不可能的数据库迁移

Brad Fitzpatrick、David Crawshaw

  • 2021-03-07
  • 本文字数:3693 字

    阅读完需:约 12 分钟

一次几乎不可能的数据库迁移

最初,我们把一个文件当作数据库,将数据转化为 JSON 大对象写入进去,后来,它的速度越来越慢,我们决定进行数据库的迁移,这个过程中我们遇到了一些问题和障碍,但最终我们成功完成了这一次不太可能的数据库迁移。

Brad 加入一家初创公司

大约一年前,当我刚加入 Tailscale(https://tailscale.com/)时,我问 Crawshaw(https://github.com/crawshaw)的第一件事是:“嗯……你们使用的是什么数据库呢?MySQL、PostgreSQL、SQLite?“我知道他喜欢 SQLite。

 

“一个文本文件,”他回答道。

“嗯?”

“是的,我们将一个大型 JSON 对象写入一个文本文件。”

“怎么写?什么时候写?写什么?”

“嗯,无论什么时候,只要有什么东西一变,我们都会在我们的单进程中获取一个锁,然后重写这个文件!”他高兴地笑着说。


听起来很疯狂。其实就是很疯狂。的确,它很容易测试,但是,不能扩展。这些,我们都知道。但是,当时它还行得通。

 

后来,它不行了。


即使使用高速 NVMe 驱动器,并且将数据库分成两部分(重要数据和 tmpfs 上的可能丢失的临时数据),有些事情也会变得越来越慢。我们知道这一天终将到来。文件达到了 150MB 的峰值,我们正在以磁盘 I/O 允许的最快速度写入它。这已经到了极限。

 

那么,迁移到 MySQL 或 PostgreSQL,如何?或者是 SQLite?


不,Crawshaw 另有主意。

聊聊大卫的背景故事

Tailscale 的协调服务器(我们的“控制面板”)以控制 CONTROL(https://getsmart.fandom.com/wiki/CONTROL闻名遐迩。它目前是单个 VM 上的单个 Go 进程。它最早的原型使用的是 SQLite。我们最初的设计与最终的设计有非常大的差异,包括同步到客户端机器上的配置数据库,以及所有我们最终不再需要的其他概念。在这个过程中,我们每周都要对 SQL 数据模型进行非常大规模的重组,这需要大量的键盘输入工作。SQL 已经得到了广泛使用,它持久、有效,但将其引入到任何编程语言中几乎都需要做大量的粘合。(通常大家都试图用 ORM 来避免这种情况,用令人生厌的大量魔法字和效率损失来取代那些同样令人生厌的键盘输入工作。)


一天,我厌倦了重构,就把它彻底丢在一边,建了一个内存数据模型进行实验。这样,迭代速度更快了。几周后,一位客户想要试用一下。我还没有做好提交数据模型和用 SQL 来完成它的准备,所以我选择了一条捷径:将持有所有数据的对象包装在一个 sync.Mutex 中。所有访问都要经过它,在编辑时,将整个结构传递给 json.Marshal,然后写入磁盘。这就是我们用大约 20 行 Go 实现的数据模型持久层。


我们本来计划要迁移为别的语言的,但忙着忙着就给忘记了。

JSONMutexDB 的后面是什么?

下一步显然是迁移到 SQL。我最喜欢的仍然是 SQLite,但是我不能说服自己把一个快速增长的服务迁移到它上面。它当然是可行,尤其是我们的控制面板的设计并不需要典型的 web 服务高可用性:短时间停机的无非就是使新节点无法登录而已,正在工作的网络可以保持正常工作。


其后是 MySQL(或 PostgreSQL)。我对 1998 年以后的 MySQL 不是特别熟悉,但我确信它是可以的。不过,开源数据库的 HA 情况有些令人惊讶:您可以使用传统的滞后副本,也可以提交到具有令人非常惊讶的事务语义的无主副本集群。我对试图在这些语义之上设计一个稳定的 API 或良好的网络图计算并不感兴趣。CockroachDBhttps://github.com/cockroachdb/cockroach#what-is-cockroachdb 曾经看起来很有前途,而实际上现在仍然很有前途!但对于一个数据库来说,它还是相对比较新的,我不太放心把一些特性附着在一个新的 DBMS 上,因为如果我们需要将这些特性中迁移出来时,可能很难做得到。


让我们的控制服务器依赖于 MySQL 或 PostgreSQL 还意味着我们对控制服务器的测试将变得缓慢和丑陋。Brad 与 Perkeephttps://perkeep.org/)曾就此有过争论,他之前写过perkeep.org/pkg/test/dockertest,它的确可行,但我们不想要求未来的员工都这么做。它需要在你的机器上部署 Docker 环境,速度不是特别快。


后来有一天我们看到一份 Jepsen 写的 etcd 报告(https://jepsen.io/analyses/etcd-3.4.3)。这篇报告不似 Jepsen 之前那种满篇吐槽的风格,里面还指出了一些 etcd(https://etcd.io/)的优点。结合 Dave Anderson(https://github.com/danderson)的一些正面体验,我们开始考虑是否可以直接使用 etcd。由于是它用 Go 编写的,我们可以直接将它连接到我们的测试中,并直接使用它。无需 Docker,无需 mock,就可以测试我们在生产环境中实际使用的东西。


事实上,我们写入到磁盘的核心数据模型严格遵循了以下模式:

type AllTheData struct {	BigLock    sync.Mutex	Somethings map[string]Something	Widgets    map[string]Widget	Gadgets    map[string]Gadget}
复制代码

这很好地映射到了 KV-store 上。因此,我们将 etcd 作为一个“最小可行的数据库”。它做了我们当前所需要的最关键的事情,那就是 1)将 BigLock 拆解成更类似于 sync.RWMutex 的东西。2)减少 I/O,只写改变的数据,而不是整体都写。


(我们会谨慎避免使用任何难以映射到 CockroachDB 的 etcd 特性。)


这样做的缺点是,etcd 虽然在 Kubernetes 中很流行,但是数据库系统的用户相对较少。作为一家公司,Tailscale 正致力于在其上打造一款创新代币(https://mcfunley.com/choose-boring-technology)。但这款数据库从概念上讲非常小,以致于我们不必把它当作一个黑盒。当我们在 etcd 3.4 中遇到一个异常缓慢的主键分页的极端情况时,我能够阅读它的源代码并在一个小时内编写出一个修复程序。(后来,我发现 etcd 的下一个版本也已经做了一样的修复(https://github.com/etcd-io/etcd/commit/26c930f27d46776da5fedae69267ba0b69c31185),所以我们将其反向移植了过来。)

我们的 etcd 客户端包装器

我们用于 etcd 的客户端是开放源码的,网址是 github.com/tailscale/tailetc(https://github.com/tailscale/tailetc)。它围绕了两个概念:1)DB 中的总数据量足够小,可以放入服务器的内存中;2)读比写更常见。鉴于这一点,我们希望降低读取成本。

我们的方法是对 etcd 注册一个监控。每次更改都被发送到这个客户端,这个客户端在一个 sync.RWMutex 后面维护一个庞大的缓存 map[string] interface{}。当你创建一个 Tx 并且做一次 Get 时,这个值从这个缓存中读出(这个缓存可能在 etcd 之后,但是通过跟踪 modrev 来保持事务一致性:即一个全局递增的 ID, etcd 使用它来界定键-值对的修订)。为了避免缓存中的混叠错误,我们将对象复制出来,但是通过对缓存中的对象实现更有效的克隆调用,避免了每次 Get 时的 JSON 解码。


最终结果是,从 etcd 获取一个值不需要任何网络流量。


当我在设计一个包时,我感受到了编写 Go 时它的类型系统的局限性,这样的感受并不多,它是其中之一。如果我使用的是一种具有各种花哨功能的语言,那么我可以在离开缓存的对象上放置某种 const 限定符,从而避免对内存进行克隆。即便如此,在我们的服务器上执行的性能分析却表明,复制并不是一个性能问题,所以该例可能说明,我实际上并不需要那些心心念念的更复杂的类型系统。通常情况下,假设很可能并不正确,性能分析才更具启发意义。

一个障碍:索引

选择最小可行的“nosql”的最大问题是缺乏每个标准 SQL DBMS 所提供的出色的索引系统。我们要么在 etcd 中存储索引,要么在客户端的内存中管理索引。

我们使用 JSONMutexDB 在内存中生成它们,因为更改数据模型要容易得多。使用 etcd 的一个简单做法是将它们写入数据库,但这将产生非常复杂的数据模型。不幸的是,如果我们想要同时运行多个控制进程以实现高可用性和更好的发布管理,就意味着我们不再只有一个管理数据的进程,因此我们的索引需要支持事务(以及回滚)。因此,我们投入了大约两到三周的工程时间来设计事务一致的内存索引。这一点描述起来有些复杂,所以笔者将在后续的博客文章中专题解释,敬请期待。

迁移

而迁徙本身却没什么特别值得注意的,这其实件好事。我们这两个系统并行运行了一段时间,并在某个时间点停止了旧系统的使用。最令人兴奋的是,当我们关闭 JSON 写入时,提交延迟降低了很多。在管理面板中编辑网络时这一点尤为明显。我们有漂亮的 Grafana 图表,在切换之前我们就调整了 Prometheus 配置以保持更多的历史纪录。不论在哪种情况下,写操作都能从几乎一秒(有时更糟!)的时间缩短到毫秒级。刚开始的时候,写入并不是我们的第二目标。永远不要低估“临时”起意会产生多么长久的影响!

未来

在这项工作中,除了确保 Tailscale 控制面板可以在可预见的未来扩展外,最令人兴奋的事情是我们发布过程的改进。我们可以轻松地将多个控制面板实例附加到一个一致的数据库中,这意味着我们可以切换为蓝绿部署(https://en.wikipedia.org/wiki/Blue-green_deployment)。这将让 Tailscale 的工程师们有信心去尝试部署特性,因为变更所能造成的最差结果是有限的。我们的目标是将开发速度保持在接近 JSONMutexDB 早期的水平,当时我们可以在不到一秒的时间内重新编译并在本地运行,每天部署上 10 几次。


原文链接:An unlikely database migration


译者简介:冬雨,小小技术宅一枚,从事研发过程改进及质量改进方面的工作,关注编程、软件工程、敏捷、DevOps、云计算等领域,非常乐意将国外新鲜的 IT 资讯和深度技术文章翻译分享给大家,已翻译出版《深入敏捷测试》、《持续交付实战》。

2021-03-07 12:003651

评论 1 条评论

发布
用户头像
原型数据库和生产数据库的选型要慎重
2021-03-15 08:34
回复
没有更多了
发现更多内容

长安链源码分析之网络模块 net-liquid(3)

5个技巧让CIO最大化提升IT项目投资回报率

雨果

CIO ROI

如何将 SAP Business Application Studio 里开发的 Java 应用部署到 SAP BTP 上

汪子熙

云原生 Cloud 云平台 SAP 10月月更

CentOS下搭建Gitea-自己的git服务器

麦洛

git Gitea

年度大促将至,企业如何进行性能压测

阿里巴巴云原生

阿里云 云原生 性能压测 PTS

解React框架核心原理

夏天的味道123

React

利器| Cypress 强大全新的 Web UI 测试框架应用尝鲜

霍格沃兹测试开发学社

欧美开源法案频出,你准备好了吗?

安势信息

出海 #开源 SBOM 软件供应链安全 开源合规

人人能读懂redux原理剖析

夏天的味道123

React

React-Hook最佳实践

xiaofeng

React

保10万涨薪、保Offer、保大厂,1V1私教服务上线啦!

霍格沃兹测试开发学社

推荐|海泰信创浏览器安全解决方案 全面适配安全可靠

电子信息发烧客

几个你必须知道的React错误实践

xiaofeng

React

哪些数据类岗位不容易失业?

雨果

开发数据 数据科学 数据工程师

企业云安全的6个最佳实践

HummerCloud

10月月更

React-hooks+TypeScript最佳实战

xiaofeng

React

【荣耀云调试FAQ】一个帐号可以同时使用多部手机吗?

荣耀开发者服务平台

开发者 手机 安卓 荣耀 honor

2022年10月中国数据库排行榜:达梦冲刺IPO热度不减,PolarDB立足创新夺锦才

墨天轮

数据库 opengauss tdsql TiDB 国产数据库

Redis 底层数据结构说明

water

微服务是开发架构对三高场景的妥协吗?

NoGirlfriendDeFoundException

架构 微服务 单体架构 云平台

STM32 HAL库串口同时收发,接收卡死?

矜辰所致

串口 STM32L051 10月月更

推荐|海泰政务移动办公系统密码应用解决方案 打造移动办公安全

电子信息发烧客

OPPO 引力计划全方位升级,与开发者共建折叠屏上繁荣生态

Geek_2d6073

redis实现分布式锁(二)

zarmnosaj

10月月更

安势清源SCA助力超大规模高科技企业加速开源风险治理

安势信息

开源 腾讯 SCA SBOM 软件供应链安全

保10万涨薪、保Offer、保大厂,1V1私教服务上线啦!

测吧(北京)科技有限公司

测试

经常被问到的react-router实现原理详解

夏天的味道123

React

议程剧透!1个主论坛4场Workshop,龙蜥操作系统峰会盛大来袭 | 2022 云栖大会

OpenAnolis小助手

开源 报名 云栖大会 论坛 龙蜥操作系统峰会

云管平台常见问题汇总解答-行云管家

行云管家

云计算 企业上云 云管理

自定义注解判断参数为空

派大星

Gartner 权威解读: SBOM 采用率将于2025年达到60%

SEAL安全

DevSecOps Gartner SBOM 软件供应链安全

一次几乎不可能的数据库迁移_语言 & 开发_InfoQ精选文章