系统运行了很长时间后,使用更新的技术来提高性能,可维护性或添加新功能的情况并不少见。这些更改之一可以是使用哪个数据库。这可能是最困难的一种更改。在迁移期间,有两个数据源,这使其成为一个分布式系统。在分布式系统下使数据一致非常困难,而且很容易出错。在本文中,我们将探索一种在迁移过程中保持数据一致并同时保持较低停机时间的方法。
可以使用一致的视图转储源数据库,并在数据更改日志中标记位置。
客户端仅在给定时间写入数据库之一。因此,我们可以避免容易出错且速度较慢的分布式事务。
我们通过设置数据库权限来切换数据库。它比切换客户端代码更快,并且更容易确保切换所有客户端。
首先,我们需要使用一致的视图转储源数据库。并标记我们已转储的位置。例如,在MySQL中,可以将mysqldump与--master-data一起使用以转储带有bin日志位置的数据库。 (有关用法的文件)。从源数据库获取所有数据后,可以将它们插入目标数据库。
由于这是第一步,因此很容易处理失败:只需从头开始即可。因此,在导入转储的数据时捕获任何错误非常重要。
下一步是使用源数据库中的捕获数据更改。例如,在MySQL中,您可以使用bin日志捕获更改并将其插入目标数据库。由于我们具有从上一步开始的位置,因此我们知道从哪里开始解析并导入更改。
导入时保持更改顺序非常重要。因此,最好只使用一个过程来解析和导入更改。这部分具有挑战性:这里的性能很重要。同步所有更改的时间是我们迁移所需的停机时间。
我们还需要确保即使系统出现故障,也不会遗漏任何更改或多次导入任何更改。因此,记录更改日志位置非常重要。使用导入数据的同一事务将头寸写入目标数据库很方便。因此,该位置将与我们导入的数据同步。
保持数据一致性的简单方法是只有一个事实来源。到现在为止,我们将源数据库用作真相源,并将更改同步到目标数据库。我们不想用其他写操作弄乱目标数据库。因此,我们需要设置目标数据库权限以拒绝来自客户端的所有写操作。例如,在MySQL中,您只能为客户端授予对该表的选择权限,并拒绝其他操作。我们允许读取权限,以便我们可以在下一步比较读取结果。
下一步是使客户端读取和写入源数据库和目标数据库。
我们要先读/写源数据库。如果没有权限错误,请使用此结果,否则请使用目标数据库的读/写结果。
在切换到目标数据库之前,我们可以通过比较读取结果和写入操作来验证目标数据库是否按预期工作。请注意,目标数据库可能无法同步,因此结果可能并不总是相同。但是我们可以基于相同结果的百分比来了解正确性。
切换到目标数据库后,读/写结果将用作实际结果。
如果要确保目标数据库可以处理负载,建议您允许一段时间对目标数据库进行读/写操作,但这只是一个验证,之后目标数据库中的数据将不一致。 。因此,在确认目标数据库可以处理流量之后,我们需要清理目标数据库并再次从步骤1开始。 (在这些步骤中,我们不需要修改客户端代码)。
如果源数据库中存在权限错误,则仅使用目标数据库结果。从源数据库引发其他错误。
如果未使用结果,请忽略目标数据库的错误,但请确保将其记录下来,以免影响当前操作,同时确保切换前没有错误。
1db_operation(){2试试{3 source_result = source_db_operation()4} catch(PermissionException e){5 return target_db_operation()6} 7 async {8 //异步执行以下操作,因此不会影响性能9 try {10 target_result = target_db_operation()11 compare_result(source_result,target_result)12} catch(Exception e){13 log_error(e)14} 15} 16 return source_result 17}
5.拒绝客户端访问源数据库,并等待同步更改
在对目标数据库的读取和写入充满信心之后,我们可以进行切换。我们通过更改数据库权限来切换数据库。首先,我们拒绝客户端对源数据库的所有访问。然后,我们等待更改完全同步到目标数据库。在此期间,系统已关闭。因此,更改从源数据库到目标数据库的同步速度决定了停机时间。
目标数据库完全同步后,我们可以为所有客户端启用目标数据库权限。此后,系统应再次联机并且数据库已完全切换。
到目前为止一切都很好,这很好。但这并非总是如此。也许目标数据库无法处理新流量(这就是为什么在步骤4中对其进行测试很重要的原因)。在这种情况下,我们需要回退到源数据库。
如果在迁移期间丢失已提交的数据很好,则回退相对容易:
允许访问源数据库。此后,客户端应再次使用源数据库。
如果保存提交的数据并确保它们一致是至关重要的,那么在步骤5之前,我们应该建立一种机制来捕获从目标数据库到源数据库的更改,并在步骤6之后标记更改位置。 :
从目标数据库同步到源数据库(确保在完全同步后停止它)。
从目标数据库到源数据库的同步非常危险且难以测试,因此测试目标数据库可以处理步骤4中的操作非常重要。
一旦数据库切换到目标数据库,我们就可以清理访问源数据库的代码。然后数据库将完全迁移,您可以加入它!