« 短 ID hash 映射的问题 | 返回首页 | 今年玩的一些游戏 »

SQL Server 向 MySQL 的迁移方案

昨天做内部晋升评审时听到候选人介绍他即将开始的一个项目。大致是我们公司从韩国买过来一个游戏(有全部源码)打算自己运营。该游戏服务器全部用 C++ 编写,使用 SQL Server 做数据库。我们这个项目,除了需要根据市场做二次开发外,还希望把 SQL Server 迁移到 MySQL 上。成本是最主要的原因,如果可以迁移成功,成本将减半甚至更多。该成本差异主要在 SQL Server 的使用执照费用,以及同等任务所需要的云成本。

我在反复确认了这项工作是否真的有做的价值(从 SQL Server 改为 MySQL)后,讨论了一下具体实施方案。

移植的难点在于该项目大量使用了 SQL Server 的存储过程。几乎所有的业务逻辑都是人肉写在 SQL Server 的存储过程中的,大约有 20 万行。虽然 SQL Server 的存储过程和 MySQL 的差异不是特别大,但再靠人一点点重写成本上也不划算。

负责的这个同学说他考虑用 ChatGPT 来做翻译工作,并做了一点点预研工作。结论是,AI 可以辅助这件事,提高开发效率,但是,翻译结果还是需要人工来审校。工作量并不小,而且一旦出错,损失会很大。

我对 SQL Server 和 MySQL 都不熟悉,但我觉得既然都是 SQL 数据库,那么一一对译应当问题不大。但我认为应该选择一条渐进的路线,让项目可以一步步推进,每步都能直接看到结果。据此,我设想了这么一个方案:

  1. 先将 C++ 代码中所有涉及的 20 万行存储过程全部定位出来,改造这部分代码,为每个已有的存储过程都赋予一个唯一的 hashtag ,并把它们提取到单独的文件中。事后,我们可以根据 hashtag 直接定位到想干某件特定的事务。

  2. 做一个中间层,放在游戏服务器和 DB 之间,把所有的存储过程请求都串行化。改造通讯协议,将 hashtag (以及相关参数)放在协议层,让中间层可以了解每个请求想干什么,而不是直接让存储过程和数据库通讯。

  3. 同时启动 SQL Server 和 MySQL 两套数据库,中间层和两套数据库保持连接。一开始,可以把所有 SQL Server 的存储过程,根据 hashtag 转发到 SQL Server 上。然后,把 SQL Server 的数据同步到 MySQL 。因为有源码,我们还可以优化后一步的同步流程。比如事先在每个请求上标注该请求大致会影响到数据库中哪些数据,让同步更高效。因为游戏业务比较容易分类,所以标注也只是一个分类问题,工作量并不大。而数据查询,则在 MySQL 数据库上进行。

  4. 找到高频的存储过程,翻译成 MySQL 的存储过程。经过翻译的新版本,则由中间层转发到 MySQL 上运行,运行完毕后,再把结果从 MySQL 同步到 SQL Server 。

  5. 新业务在 MySQL 上开展。

不断迭代第 4 步,直到覆盖绝大多数需求,最后只保留很少的 SQL Server 资源,这样也可以达到降低成本的目的。


在这个方案中,实际上保留了两份完全相同的数据库,一份在 SQL Server ,另一份在 MySQL 中。我们把修改数据的操作集中在中间层做,以单个储存过程为单位对数据集做修改。假设有 A B C D E 五次修改,其中 A B C 是 MySQL 版本的,D E 是 SQL Server 版本的,我们并不需要每次操作都做结果同步。A B C 这三步连续修改是在 MySQL 上完成的,它们可以(并行)完成后再把结果同步到 SQL Server 再进行 D E 操作。

随着翻译工作的进展,越来越多的事务可以直接在 MySQL 上完成,这些事务也不再需要严格串行,对用户的影响也就越来越小。而保留在 SQL Server 上进行的操作只是增加了用户请求的延迟,并没有增加服务器的压力。整体来说,SQL Server 的配置可以逐步减少,达到削减成本的目的。

而在测试期间,一直可以通过增加一些额外手段(将事务在两侧都运行一次),从而可以以比对两个数据库数据的一致性的方式来检验过去一个阶段的工作的正确性。比起把 20 万行代码全部移植完再跑新版本来说,心里也会比较踏实。


对于这个方案,我并不想让它变成一个通用的数据库中间层,透明的对待 MySQL 和 SQL Server 两种服务器。它更像是一个迁移数据库的脚手架,会根据业务需要动态做调整。而且我们可以在源码层次做辅助配合,比如增加 hasgtag 这样的高阶信息,直接表明每个操作到底想做什么,会影响哪些数据等等。而且迁移是单向的,一旦一个 SQL Server 的存储过程被顺利移植到 MySQL 上,就不会再改回去。新业务也永远不会在 SQL Server 上开发。

Comments

感觉这个方案不太可行,如何保证事务问题,但是思路还是很有价值就是测试翻译的是否正确, 其实这种可以写一个翻译器来完成。 而且可以通过对翻译器覆盖UT来最大可能的确保翻译是准确无误的。当然也可以使用形式化证明去做。

一个字:稳

确实,几年前和韩国一家公司合作的时候,他们要求是尽可能的把业务逻辑放存储过程里,感觉有什么大病

讽刺的是国内大部分程序员每天做的都是CRUD,对数据库可熟悉了^_^

几年我之前也碰到过一个韩国人做的项目,数据库一样也用SQLServer,逻辑写在存储过程里,而且全是同步执行,经常被数据库卡住主线程,简直是弱智到极点。
而且还是个挺有名的项目,叫奇迹。

1.重中之重是梳理,抽象出功能模块,再定义成一个一个的方法,最好一个存储过程一个方法(最少要两次,第二次是功能加业务的梳理);

2.抽象存储层.步骤1梳理的结果,涉及到数据库打交道的,都用这个层.
3.数据迁移和校验: 在数据存储层做双写双读等数据比对.
4.之后通过流量控制,部分迁移,验证没问题后再全量.

个人偏向梳理出关键表和存储过程, 先改造这部分降低sql server费用;
新需求评估是否继续迁移; 这里就是基于人力和资源成本的评估了;

修改代码和sql翻译可以同步进行,一步到位是不是更好?减少后期的维护和开发投入,sql server 和mysql之间的转换应该没那么复杂,体力活,越改越熟练。

忍不住想问下为啥不直接转到postgresql呢?

在一边做完任何操作,如果下一个操作在另一边,就必须等中间的同步完成。

两个数据库操作时的一致性会不会有问题。
比如写入之后立即读取,由于写入在一个数据库,读取在另一个,有可能不是强一致的。
更不用说如果一部分写操作在MySql时。此时同一个事务中的读写依赖都无法保证一致性。

开发期就应该找到最频繁调用的那些操作做移植。并不是在生产环境从 0 开始一点点迁移的。频率最重的储存过程肯定是集中在 20 万行代码中很少的一部分。这些都是在上线之前就应该完成的。

线上保留 SQL Server 作为低频操作的备份,自然是削减配置的,而代价是用户需要走这些 SQL Server 时会遇到更高的延迟。但只要在长时间内 SQL Server 能处理的重请求数量小于它能承载的吞吐量,从成本考虑,当然是配置越低越好。

简单说,最后 SQL Server 需要承载的任务,只求最终可以完成,不要求实时响应。如果某类请求的延迟为用户不可接受,那么就把它翻译到 MySQL 。

非常稳妥的、渐进式的方案👏

另对于
「SQL Server 的配置可以逐步减少,达到削减成本的目的」
有些疑问:
SQL Server 降配是灵活的吗,每次操作是否也需要数据备份迁移等方案,如果操作成本高,是否意味着整个迁移期间都要支付全套SQL Server费用

Post a comment

非这个主题相关的留言请到:留言本