场景形容
很多企业会遇到数据库降级、或数据库迁徙的状况,尤其是在自建数据库服务向云数据库服务、自建机房向云机房、旧数据库向新数据库迁徙等场景。然而,咱们须要在整个移植过程中保障其稳定性、防止数据遗失、服务宕机等状况,最常见的移植办法之一就是数据库双写移植操作。
解决方案
如下图所示,这个双写移植的过程为:
- 原始阶段,程序只对一个旧数据库进行读写。
- 在现有的读写旧数据库的代码程序根底上,须要增加读写新数据库的代码。例如,在某个表中插入一条数据时,咱们须要把这条数据同时插入到新旧两个数据库中。通常状况下,咱们会并行执行这两个插入操作,以尽可能放弃服务的原有调用解决工夫。
- 当一个写数据库申请进来,咱们将其写入旧数据库的同时,将一个很少的百分比流量写入新的数据库。
- 将写入新数据库的流量比迟缓进步,直到 100% 为止。在这个过程中如果呈现问题,能够及时回滚,并在不影响生产环境服务的状况下进行修复。
- 写移植实现后,开始逐渐放量从新的数据库中读取数据返回给服务,如先容许 10% 的流量在新数据库做读操作。在这个过程中测量性能的同时对比后果,如果在读操作中遇到问题,能够马上回滚新数据库的读流量,并在不影响生产环境服务的状况下进行修复。
- 直到在新数据库实现 100% 的读写操作一段时间没有问题后,就能够进行与旧数据库相干的代码服务了。
在实际操作过程中,不止新旧数据库的操作流量要逐步凋谢,实际上新的数据库的读写代码也须要逐渐的更新到生产环境服务中,以确保可迭代的稳固平滑移植。
实际办法与工具
整个过程中,除了本身零碎架构的设计外,有两个特地的工具在其中起到重要环节:
- 负责可灵便、实时、稳固放量、回滚的 Feature Flags 服务 (FeatBit)。
- 在整个过程中全方位(反对无侵入和针对性埋点模式)的监测服务异样与及时报警的可观测服务 (观测云)。
应用 FeatBit 实现实时的数据库移植申请流量管制
如下代码所示,为某一个服务的数据库读取操作分流的示例伪代码:
- 第 6 行代码,调用 _fbService.BoolVariation(“read-sport-olddb”) 办法取得流量管制返回值,如果为 true,则将读取旧数据库的 Query 函数增加到并行任务执行队列中。
- 第 9 行代码,调用 _fbService.BoolVariation(“read-sport-newdb”) 办法取得流量管制返回值,如果为 true,则将读取新数据库的 Query 函数增加到并行任务执行队列中。
- 第 19 行代码,为应用 FeatBit Feature Flags SDK 同时运行两个数据库读取操作,并将后果进行比照验证,依据执行状况返回正确值,并向观测云发送相干异样数据。
public async Task<List<Sport>> GetSportsByCityAsync(int cityId, int pageIndex, int pageSize)
{var tasks = new List<Task<List<Sport>>>();
// 当读取 Sport 相干业务的旧数据库开关返回 true 时,则增加读取工作到执行工作队列
if (_fbService.BoolVariation("read-sport-olddb"))
{tasks.Add(GetSportsByCityQueryAsync(_oldDbContext, cityId, pageIndex, pageSize));
}
// 当读取 Sport 相干业务的新数据库开关返回 true 时,则增加读取工作到执行工作队列
if (_fbService.BoolVariation("read-sport-newdb"))
{tasks.Add(GetSportsByCityQueryAsync(_newDbContext, cityId, pageIndex, pageSize));
}
// 同时执行两个读操作(为了防止新增数据读取减少申请工夫),并将后果进行比照并返回
// 如果后果不统一,则返回旧数据库读取后果,并进行记录
return await _fbService.RunAndCompareDbTasksAsync(
tasks,
timeoutDelayForNewDB: 3000, // 设定新数据库的最长等待时间,防止不良体感
(timeoutInfo) => { }, // 当新数据库调用超时,发信息至观测云
(unMatchInfo) => { }, // 当返回后果不统一时,发信息至观测云
(exception) => {} // 当出现异常时,发信息至观测云);
}
在把相似于上述的代码逐渐的集成到咱们的我的项目中之后,就能够通过 FeatBit 提供的 Feature Flags 控制中心来管制每一个对应的数据库移植的双写双读放量工作了。例如咱们先将 feature flag read-sport-from-newdb 放量调整到 5%,若在一段时间未在观测云中察看到异样情况,增大放量百分比至 10%(如下图)。
应用观测云观测移植全过程,及时发现潜在问题
在整个的数据迁徙过程中,自动化的、及时发现谬误问题并回滚,是极为重要的。他能够最无效的帮咱们防止诸多问题,如:
- 新数据库操作带来微小的系统资源耗费时,咱们须要第一工夫晓得并通过 Feature Flags 零碎立即回滚。
- 当某个写操作或读操呈现工夫操作超时数量超过预估阈值时,咱们能够疾速定位问题,回滚的同时进行疾速的修复,进步移植的速度。
- 当某个写操作或读操作呈现信息谬误时(如后果不统一、申请工夫过长、程序异样等),咱们能够依据观测零碎具体定位错误信息,从而减速 debug 的速度。
- 等等
实现这些,咱们只须要:
- 依据《观测云文档:疾速入门》,抉择与本人业务相符的技术栈,进行小白式的在 15 分钟内实现配置和装置。
- 运行你已有的服务程序,开始你的数据库系统移植。
- 关上观测云控制台的「利用性能检测」页面,定位到链路,你将看到所有服务的运行状况。
通过「链路」与「谬误追踪」疾速定位移植谬误
通过「链路」页面,咱们发现在移植过程中,呈现了一些红色项(即 Error),通过资源列能够轻松的看到咱们在对新数据库的读取操作中呈现了谬误异样,如下所示:
点击对应的 Error,咱们能够疾速查看其对应的调用链路火焰图。如下图所示,依据火焰图的解释:
- 如下图 ①地位的 Span 所提醒,在这个中央呈现了数据库移植的 Timeout 谬误,即新数据库的读取工夫超出了咱们能够承受的申请响应工夫阈值。
- 如下图 ②地位中,指出谬误产生在 Feature flag read-sport-newdb 为 true 的状况上面。也就是说咱们能够疾速定位可能须要回滚或关掉的 Feature Flags,从而防止移植危险。
- 而依据 ③地位 Span 能够疾速定位呈现超时景象的服务端 API 服务,并且依据捕捉到的 API 的参数与 Header,能够帮忙咱们前面去更好的调试解决问题。
通过 Feature Flags 实时将读操作回滚至无超时状态
依据下面的「链路」查找形式,咱们疾速定位到了出现异常的数据库读操作。那么,咱们只须要回到 FeatBit 的后盾界面,找到下面发现的开关 read-sport-newdb,并将其放量为 true 的百分比向后回滚即可。如下图所示,将 true 的百分比从 10% 回滚到之前未呈现读数据异样的 5% 的流量调配。
回滚后,上面代码所示的 _fbService.BoolVariation(“read-sport-newdb”) 返回值,只会将有 5% 的比率为 true。
// 当读取 Sport 相干业务的新数据库开关返回 true 时,则增加读取工作到执行工作队列
if (_fbService.BoolVariation("read-sport-newdb"))
{tasks.Add(GetSportsByCityQueryAsync(_newDbContext, cityId, pageIndex, pageSize));
}
总结与后续
这篇文章介绍了应用观测云与 FeatBit 通过双写双读的操作形式实现了升高数据库移植危险的根底办法。
在理论运行中,咱们可能有大量的业务须要解决,人为的染指和操作会因为各种起因造成反馈不及时的问题。在后续的文章中,咱们将介绍更多的内容,如:
- 应用观测云的指标服务与 FeatBit 的 Trigger 服务,实现移植时自动化实时回滚避灾与报警计划。
- 应用观测云的指标服务与 FeatBit 的 Scheduler 服务,实现自动化的放量与回滚计划。