我定期需要对表(tables)进行更改……主要是添加列(columns)。
这种更改其实只是简单的`alter table`操作……
但是我这张表目前有4000万行数据,而且他们正在快速地增长……
所以这种情况下`alter table`操作将会花费数小时时间,
因为我使用的是亚马逊RDS[sic],
我没有办法部署我地从服务器,因而也没有办法改善主服务器。
所以我的问题是,是否有办法在停机时间最小化的情况下做到这一点呢?
我不介意一个小时或甚至几天的操作,如果用户仍然可以使用DB…
(译者:如何在不停机的情况下修改表结构及数据)

—— Stack Overflow serverfault 1

上面的问题在2010年发布,但是关于模式改变的停顿的焦虑仍然存在。

当我们在设计CockroachDB的模式改变引擎(schema change engine)的时候,我们希望更好地构建它。

我们希望提供一种更新表模式(只需运行alter table命令)的简单方法,而不必让应用程序遭受任何负面后果——包括停机时间。

我们希望模式更改是CockroachDB的内置特性,不需要额外的工具、资源或操作的自组织排序;

并且所有这些,对应用程序的读/写延迟没有影响。

在这篇文章中,我将解释我们的在线模式改变策略。

我将讨论如何管理对架构元素(如列和索引)的更改,而不必强制停机。

这就是我们所做的

模式更改涉及更新模式以及添加或删除与该更改相关联的表数据。

两个基本的分布式数据库特性使得这一点特别棘手:

  1. 高性能:为了优化数据库性能,必须采用跨数据库节点缓存架构。保持分布式缓存一致性是有挑战性的。
  2. 大表:数据库中的表可以非常大。与模式改变相关联的回填或清除表数据需要时间,并且正确地执行,而与此同时,不禁用对数据库的访问是具有挑战性的。

我们用于 维护一致的分布式模式缓存以及一致表数据 拥抱着 同时发生的模式的多个版本,我们可以在使用旧模式的同时推出我们的新的模式。

(译者的理解:他可能是先继续维护旧的模式,然后新建一个新的模式,然后再一步步地往新的模式里面填旧的模式里面的数据,当然这个时候新的模式里面的数据也会变动,反正就是一点一点的往旧的模式靠,等到某一个时间点和旧的模式保持同步了,好!立马抛弃旧的模式,启用新的模式。)

它在不持有锁的情况下回填(或删除)基础表数据。

这个解决方案是由谷歌F1团队所做的工作得出的。

安全模式展开(Safe schema rollout)

一个schema元素(它可以是索引或列,虽然在这篇文章的其余部分,我们将重点放在索引的情况下),有相关的数据,这些数据可以被SQL DML命令删除、写入或读取(例如,插入INSERT、更新UPDATE、删除DELETE、选择SELECT)。

CockroachDB采用的策略是首次展现(rollout)一个新的索引,包括对这些DML命令进行删除、写入和读取功能,一个接一个地以分级的方式,而不是同时进行。

添加一个新的索引遵循如下所述的离散阶段:

  1. 授予删除(DELETE)功能。
  2. 授予写入(WRITE)功能。
  3. 回填索引数据。
  4. 授予读取(READ)功能。

在新版本的架构中,一个能力与所有先前授予的能力一起被授予。

为了正确起见,只有在整个集群使用包含所有先前授予的能力的架构之后,才可以授予新的能力。

因此,该过程在每个阶段之前暂停,允许先前授予的功能在下一个功能可以被授予之前传播到整个集群。

删除索引按照相反的方向进行:

  1. 撤销读取(READ)功能。
  2. 撤销写入(WRITE)功能。
  3. 清除索引数据。
  4. 撤销删除(DELETE)功能。

类似地,只有在前一个功能在整个群集上的撤销传播完之后才撤销当前的功能。

删除能力(Delete capability):避免虚假索引条目

通过将索引置于 DELETE_ONLY 状态,来赋予这种功能。

拥有这种能力,SQL DML命令限制了他们自己:

  • 删除(DELETE)是完全有效的删除行连同基础索引数据。
  • 更新(UPDATE)删除旧索引条目,但限制自身不写入新的条目。
  • 插入(INSERT)和选择(SELECT)忽略索引。

在下一阶段授予索引的写入能力的节点可以信任整个集群使用索引的删除能力。

因此,当它接收到插入命令并插入一个行的索引条目时,另一个只有删除能力的节点在看到同一行的删除命令时,将正确删除行的索引条目。

该索引将避免因悬空索引条目而中毒。

当模式改变丢弃索引时,仅在成功地将写入能力撤回群集之后清除关联索引数据;

整个集群只有删除能力,允许安全清除。

写入(Write capability)能力:避免丢失索引条目

这种能力是通过将索引放置在 WRITE_AND_DELETE_ONLY 状态,授予删除和写入能力来实现的。

  • 插入(INSERT)、更新(UPDATE)和删除(DELETE)命令正常运行,根据需要添加或删除索引项。
  • 另一方面,选择(SELECT)需要读取能力,而忽略索引。

索引回填仅在整个群集能够写入之后才运行。

在回填过程中,在任何节点上接收的插入命令创建具有合法索引项的新行,并且不依赖于单独的回填过程来创建行的索引条目。

回填完成后,将不会有缺失的索引条目。

读取能力(Read capability)

这最后一个能力是通过使索引激活而授予的,并通过所有命令打开索引的完整使用。

快速模式展开(Fast schema rollout)

在模式更改过程的每个阶段之间,允许整个集群收敛到表模式的最新版本。

一个简单的模式缓存机制可能会使用5分钟的TTL,但是这会迫使模式改变过程等待许多分钟,然后才相信最新的版本是唯一的一个具有活跃状态的和完全授予/撤销的能力的版本。

在 CockroachDB 中,我们在模式版本上开发了租约(leases),以加快集群收敛到最新的模式版本,这又加速了模式改变过程。

在使用SQL DML命令的表模式之前,运行该命令的节点自一段重要的时间内获得该模式的读取租约(以分钟为单位)。

当更新的表架构版本变为活动时,它将在整个集群上广播,向新版本通知节点并使它们主动释放旧版本上的租约。

如果某些节点不健康并且不主动释放它们的租约,则 rollout 将等待租约过期,并将被延迟。

我们通过遵循以下两条规则来让模式更改策略变得简单:

  • 新租约只授予最新的模式版本。
  • 有效租约只在两个最新的模式版本上。

有关表租约的更详细讨论,请参见我们在Github仓库上的RFC文档。

可靠的模式展开(Reliable schema rollout)

模式更改由执行模式更改SQL命令的节点引导完成。

由于模式更改操作可能长时间运行,所以当执行它们的节点死亡时,它们需要重新启动。

每个节点运行一个模式转换器 goroutine,它能够运行任何不完整的模式更改。

在执行模式更改之前,模式更改器 goroutine 首先获取表上的独占写入租约,使其成为唯一指导模式更改的许可。

总结

在 CockroachDB 中,在线模式更改使用起来是很简单的,模式更改展开的处理也是方便、快速和可靠的。

改变是不可避免的,现在是你不必担心的时候了!

我们要感谢来自谷歌F1团队的人们发布 在线模式更改 的类似实现,从中我们获得了很多灵感。


Apptree. Stack Overflow. “Modifying columns of a very large mysql table with little or no downtime.” August 26, 2010.

CockroachDB学习笔记——[译]在CockroachDB中如何让在线模式更改成为可能的更多相关文章

  1. CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储

    CockroachDB学习笔记--[译]CockroachDB中的SQL:映射表中数据到键值存储 原文标题:SQL in CockroachDB: Mapping Table Data to Key- ...

  2. CockroachDB学习笔记——[译]如何优化Go语言中的垃圾回收

    原文链接:https://www.cockroachlabs.com/blog/how-to-optimize-garbage-collection-in-go/ 原作者:Jessica Edward ...

  3. CockroachDB学习笔记——[译]Cgo的成本与复杂性

    原文链接:https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/ 原作者:Tobias Schottdorf 原文日期:D ...

  4. CockroachDB学习笔记——[译]为什么Go语言是CockroachDB的正确选择

    原文链接:https://www.cockroachlabs.com/blog/why-go-was-the-right-choice-for-cockroachdb/ 原作者:Jessica Edw ...

  5. CockroachDB学习笔记——[译]The New Stack:遇见CockroachDB,一个弹性SQL数据库

    原文链接:https://www.cockroachlabs.com/blog/the-new-stack-meet-cockroachdb-the-resilient-sql-database/ 原 ...

  6. CockroachDB学习笔记——[译]CockroachDB是如何进行分布式原子事务的

    原文:How CockroachDB Does Distributed, Atomic Transactions 原文链接:https://www.cockroachlabs.com/blog/how ...

  7. CockroachDB学习笔记——[译]Scaling Raft

    原文链接:https://www.cockroachlabs.com/blog/scaling-raft/ 原作者:Ben Darnell 原文日期:Jun 11, 2015 译:zifeiy 在Co ...

  8. CockroachDB学习笔记——[译]Hello World

    原文链接:https://www.cockroachlabs.com/blog/hello-world/ 原作者:Spencer Kimball 原文日期:Jun 4, 2015 译:zifeiy 数 ...

  9. CockroachDB学习笔记——对此的选择

    无意间了解到TiDB,然后知道了他是一款国产团队开源的NewSQL数据库, 看了一下官网,有很多中文的文档和技术分享挺不错的. 但是安装起来好像挺麻烦的说. 测试的硬件环境 也吓死我了,我只有一台笔记 ...

随机推荐

  1. 版本问题---cuda和tensorflow的版本对应关系

    cuda和tensorflow的版本有对应关系 https://tensorflow.google.cn/install/source#linux

  2. python3 基础一

    一.python基本运行 1.python特点:(1)python使用C语言开发,但是python不再有C语言中的指针等复杂数据类型,(2)python有很强的面向对象特性,而且简化了面向对象的实现, ...

  3. springboot中使用cache和redis

    知识点:springboot中使用cache和redis (1)springboot中,整合了cache,我们只需要,在入口类上加 @EnableCaching 即可开启缓存 例如:在service层 ...

  4. [唐胡璐]Selenium技巧- Highlight页面元素

    大家都知道QTP的对象高亮显示功能特别强大, Selenium Webderiver也可以实现此功能。 高亮显示有时候对Debug还是相当有用的。 解决脚本: 调用脚本: 结果显示:

  5. ln -s /usr/local/jdk1.8.0_201/bin/java /bin/java

    ln -s /usr/local/jdk1.8.0_201/bin/java /bin/java

  6. 通过Chrome控制台详细查看ajax请求

    1.F12打开浏览器开发者工具 2.如图所示

  7. nginx location if 的匹配规则

    cation匹配命令 ~      #波浪线表示执行一个正则匹配,区分大小写~*    #表示执行一个正则匹配,不区分大小写^~    #^~表示普通字符匹配,不是正则匹配.如果该选项匹配,只匹配该选 ...

  8. SpringBoot+JTA+Mybatis

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/sinat_36596988/article ...

  9. 3、python--第三天练习题

    #1.简述普通参数.指定参数.默认参数.动态参数的区别 #1.普通参数就是传入的函数,没有默认值 def f(a): a = a + 1 return a print(f(3)) #2.指定参数 de ...

  10. Oracle 后台进程(四)CKPT进程

    一.CKPT简介 检查点是一个数据库事件,它把修改数据从高速缓存写入磁盘,并更新控制文件和数据文件.检查点分为三类:1)局部检查点:单个实例执行数据库所有数据文件的一个检查点操作,属于此实例的全部脏缓 ...