如何在不造成停机的情况下更新生产代码库/数据库架构?


42

在不导致任何停机的情况下,用于更新生产服务器的代码库/数据库架构的一些技术是什么?


1
好问题,因为我看到很多人忽略了这一点。时间就是金钱,而停机对于最终用户而言从来都不是一件好事,无论原因有多合法。
Dan McGrath

@Dan McGrath:假设您实际上可能会有停机时间,我为一个(通常)每年仅停机4次(​​季度停机)并且每次最多停机15分钟(在此期间将流量排队)的系统工作。 ..数据库更改受到严格审查:)
Matthieu M.

2
这将是一个很大的问题dba.stackexchange.com,它进入公开测试在几个小时。
拉里·科尔曼

Answers:


20

通常,我处理过的有这种要求的网站都位于负载平衡器后面,或者有单独的故障转移位置。在此示例中,我假设您只有一个负载均衡器,2个Web服务器(A和B)和2个数据库服务器(M和N-通常是通过日志传送链接数据库服务器-至少在SQL Server世界中如此) )。

  1. Web服务器A将与负载均衡器断开连接(因此所有传入流量都流向B)。
  2. 日志传送已停止(DB Server M将首先进行更新)。
  3. 更新Web服务器A。将配置指向DB ServerM。
  4. 测试并验证更新是否有效(通常是人们直接点击IP地址)。
  5. 设置负载平衡器,以使现有会话继续转到B。新会话转到A。
  6. 等待B上的所有会话都过期(可能是半小时或更长时间,通常我们会观察流量并安排1小时的休息时间)。
  7. 更新B和N。
  8. 测试并验证更新是否有效。
  9. 再次设置日志传送并进行测试。
  10. 将负载均衡器设置为正常运行。

在一个非常复杂的Web应用程序中,第1-5步描述的过程可能需要整夜,并且是一个50页的Excel电子表格,其中包含时间和紧急联系电话。在这种情况下,将系统的一半更新计划在下午6点至凌晨6点进行,同时使系统可供用户使用。通常在第二天晚上安排处理DR站点的更新-希望第一天一切都好。

如果需要正常运行时间,则首先在质量检查环境中测试补丁,理想情况下,该硬件应与生产环境相同。如果它们没有受到干扰,则可以按常规时间表(通常在周末)进行应用。


7
您如何建议合并来自DB M和DB N的新数据?它们都将具有彼此没有的新的,更新的和删除的记录。
sixtyfootersdude

@Tangurena,你能回答以上评论吗?
sino

9

对于典型的数据库(例如Oracle),可以在仍然并行运行查询的同时更改数据库架构。但是,这需要一些前瞻性的计划。

它们是要应用更改的一些限制:

  • 它应与现有代码一起使用,这意味着该代码应同时处理模式的旧版本和新版本
  • 它不会在数据库上产生如此大的负担,以致交易会停止(我在看着你CREATE INDEX
  • 它不应该导致数据丢失(您不能删除并重新创建表)

为了使架构向后兼容,通常可以添加或修改列,如果现有代码不再使用它,则只能删除某些内容。

如果您的代码不能透明地处理更改,请在更改数据库之前更改代码。

关于预先计划的简单建议:始终在数据库请求中明确列名(不要使用SELECT * FROM)。这样,您就不会在旧请求中显示新列。


1
实际上,出于前瞻性计划和适应性的考虑,选择* from绝对比手动列出各列更好。在大多数情况下,使用显式列名会导致很多技术负担。如果您的代码从新列中断开,则您的代码已损坏。
Morg。

@Morg:不是。为了安全起见,您需要使用绑定变量,在我使用的框架中(至少),它要求提供要写入的变量,并且变量的数量必须与输出列的数量一样多,因此select *,如果添加了新列(由于缺少要写入的变量)。当然,这可能是使用强类型语言的结果。
Matthieu M.

是的,的确,避免选择*并没有增加安全性。它与强类型语言无关,而与非常糟糕的设计无关。如果您的框架无法无缝处理更改,那就没用了。当我更改列时,我的应用程序永远不会停止工作。当您这样做时,它会中断。我认为关于哪个更可靠或更安全没有问题。
Morg。

@Morg .:我看不到如何select *更可靠和安全。如果您曾经拥有过,select one, two from ...那么您仅使用onetwo; 如果third已将其添加到表中,那么您将无用(此处),因此没有理由对其进行检索。而且,如果您需要突然使用它,那么您将修改代码,因此您最好在此时修改查询!
Matthieu M.

@Morg .:好吧,似乎我们在互相交谈,可能是因为我们的经历不同。我致力于性能是至高无上的产品,这意味着select需要尽可能有选择性(并由索引覆盖),否则我敬酒(甚至在强制性加入之前)。我很遗憾地说,但是您所描述的方法是这些产品的完全失败。
Matthieu M.

5

并非所有系统都可以,它必须以支持它的方式进行设置。

例如,几年前我帮助升级的主要系统之一应该是24/7可用的。它由多层组成,包括非现场用户界面层和业务层之间的纯通信层。由于通信层的编码方式,将来可以对业务层或数据库模式进行的任何更改都可以实现,而不会造成实际中断。在最坏的情况下,更改生效后,用户将经历10到30秒的暂停。

如果更改纯粹是对业务层的代码更改,则可以将它们排队,并仅在几毫秒的延迟内“循环”。

之所以可以这样做是因为:

  • 通信层可以保存消息。这使我们可以在除UI层之外的任何其他层上实际中断,而无需降低UI。
  • MVDB处理的业务层称为UniData。这会将所有代码保存在内存中。编译代码后,您可以使用命令将新的目标代码强制插入内存,从而替换旧的目标代码。

其他技术涉及将事务复制到现有系统的另一个镜像。通过将更新应用于一个,切换并重放在更新和切换之间完成的所有事务。YMMV取决于您的系统。


1

与嵌入式数据库系统和嵌入式系统的世界不同。嵌入式系统包括各种网络/电信基础设施设备,在这个领域中,它们通常谈论99.999%(五个9s)的正常运行时间。

我们(McObject)是eXtremeDB嵌入式数据库系统产品家族的供应商,其中包括eXtremeDB High Availability。

首先,要了解“嵌入式数据库”是指数据库系统是一个已编译并与您的应用程序代码链接的库。从这种意义上讲,它“嵌入”在您的应用程序中。

使用eXtremeDB High Availability,您的应用程序有一个MASTER实例(可能是一个或多个进程),而您的应用程序有一个或多个REPLICA实例。当副本建立与主数据库的连接时,它通过称为“初始同步”的过程接收主数据库的副本。这可以在主应用程序继续其工作的同时完成。一旦同步,它将通过复制接收主服务器的事务。因此,副本始终具有当前数据,并且在主服务器发生故障的情况下可以接管副本(通过称为故障转移的过程)。

初始同步的一个特征称为“二进制模式演化”。用简单的英语来说,这意味着填充副本数据库的过程将适应副本数据库模式与主数据库模式之间的差异。

实际上,这意味着您可以构建应用程序的较新版本(具有新的/删除的表,新的/删除的/更改的字段,新的/删除的索引),然后将应用程序的新版本附加到主版本,然后导致较新的副本成为新的主副本(即,将故障转移到新副本,使其成为主副本,而旧的主副本将自身关闭)。瞧,您已经将应用程序从版本N迁移到了N + 1,而不会中断系统的可用性。现在,您可以将旧的主数据库和任何其他副本升级到版本N + 1。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.