ES业务数据迁移遇到的BUG精度问题

目录
  • 前言
  • 01 问题发现过程
  • 02 问题的根因是什么
  • 03 类似的问题有哪些
  • 04 小结

前言

最近在协助团队完成 ES 数据的切换(业务数据迁移),过程中遇到一个比较好玩的 BUG ,和大家分享并作为经验记录。

01 问题发现过程

通过前期的方案设计和比较,我们决定通过 elasticdump 工具来做 ES 的数据迁移,这个也是比较普遍的迁移方案,于是就动手实施了,过程中也没遇到什么问题。在最后的数据验证环节,发现有一个 ID 对应不上了,如下图所示,通过对比工具,发现一个长度较大的 ID 发生了偏移,其他的数据都没有问题。这是为什么呢?一头雾水。

根据二分法的排错思路,我们需要先确认是导出数据的问题,还是导入数据的问题。查看导出过程的中间文件,发现在导出的时候就出现了错误。于是怀疑是 elasticdump 导出功能的问题。因为这个出错的字段,主要的特征就是长度比较长(18 位),于是怀疑是精度的问题。就去查了下 elasticdump 的源码,一番查找后,果然发现有人遇到过同样的问题,并已经修复了这个 BUG,并给出了解决方案和一些猜测的原因。于是这个问题就得到了解决。在 elasticdump 的导出命令中,加上--support-big-int 参数,就可以了。

好像也很简单嘛,不是么。其实排错的过程也走过很多弯路,只是现在回顾起来看着比较轻松而以。

02 问题的根因是什么

只解决问题并不是我的风格,总得看看让我绕这么大圈才解决的问题根因是什么嘛。于是查了相关资料(结合上面 GIT 上的对话),可以确认,是因为 elasticdump 中有部分功能是用 JS 写的,而 Js 遵循 IEEE754 规范,采用双精度存储,占用 64 位,从左到右的安排位第一问表示符号位,11 位表示指数,52 位来表示尾数,因此 Js 中能精确表示的最大整数是 253(十进制 为 9007199254740992),那么大于这个数(本文中数值长度 18 位)就可能会丢失精度,因为二进制只有 0 和 1,数值太大,于是就出现了精度丢失的问题。可以在 Chrome Console 里面试了一下,果然是这样,(不是超过了能表示的最大值,而是超过了能精确表示的最大值),和 elasticdump 导出的数据变化基本类似。

再往深了想,为什么用 double 类型会出现这个问题,其他的数据类型是否会有同样的问题呢?这就涉及了数据精度的问题,在这里篇幅有限,就不再展开,有兴趣的同学可以自己去查看相关资料,本质上还是十进制小数与二进制小数相互转换产生的误差。

03 类似的问题有哪些

因为这个问题比较好玩,就又找了一些资料看了下,发现还有两个精度有关的 BUG,还蛮好玩的。

千年虫问题:这个问题相信很多人 IT 人都听说过,简单来说,就是由于前期计算机的存储资源较为昂,在表达时间时,为了节约空间,有位科学家提出了一个方案,把1960年8月11日,简写成 600811。但这样会有一个问题,就是当时被缩写掉的是 19XX 年中 19,如果时间来到 2000 年,程序就无法准确表达时间。比如:2000年1月1日,简写成六位数是 000101。计算机就会怀疑人生,怎么时间倒流了呢?然后就会导致计算机系统发生紊乱。当时大家都觉得自己的程序不会运行到 2000 年,所以就没太放在心上,而大多数后来人习惯了这种记录方式,就忘记了这回事,结果引发了千禧年的大 BUG,造就了多少程序员的不眠之夜。

2038 年问题:现在很多时候,我们在处理时间问题时,都喜欢用时间戳来记录,因为简单方便,不需要考虑时区问题(时区问题很让人头疼的,一不小出就容易出错)。但是这里面会有一个小 BUG 哟。什么是时间戳呢?简单来说就是:以1970年1月1日0 时 0 分 0 秒为起点,然后通过计算秒数来算出当前时间。比如:2021年5月7日15:00:00,换算一下就是 1620370800 秒。但是由于 32 位操作系统所能计算的秒数有限,到2038年1月19日3:14:07,就会达到极限。二进制:01111111 11111111 11111111 11111111,其后一秒,二进制数字会变为 10000000 00000000 00000000 00000000,发生溢出错误,造成系统将时间误解为1901年12月13日20 时 45 分 52 秒,然后系统就会发生各类错误,是不是和上面的千年虫一样?理论上到了 2038 年,人们应该淘汰掉了 32 位操作系统, 64 位操作系统就不存在这个问题。但是从前面的 “千年虫” 事件来看,人类从历史中吸取的唯一教训,就是人类不会吸取任何教训。

04 小结

对于发现的缺陷,不能仅停留在把问题解决了就完事。有时间和精力,还是需要更深层次的去了解缺陷背后的逻辑和根因是什么,触类旁通。以避免更多类似的问题发生。

在写这篇文章的时候,又想起了自己以前做报表相关的业务时,对于时间的精度特别敏感,也会遇到一些关于精度上的取舍问题,这需要我们和业务方面讨论并确认清楚,是精确到秒,还是毫秒,以避免出现数据边界的小问题。

以上就是ES业务数据迁移遇到的BUG精度问题的详细内容,更多关于ES数据迁移精度BUG的资料请关注我们其它相关文章!

(0)

相关推荐

  • SQL Server数据迁移至PostgreSQL出错的解释以及解决方案

    问题重现: 1.PG客户端: postgres=# create table text_test (id int,info text); CREATE TABLE postgres=# insert into text_test values (1,E'\0x00'); ERROR: invalid byte sequence for encoding "UTF8": 0x00 2.SQL Server产生数据 create table test_varchar(id int,name

  • ES业务数据迁移遇到的BUG精度问题

    目录 前言 01 问题发现过程 02 问题的根因是什么 03 类似的问题有哪些 04 小结 前言 最近在协助团队完成 ES 数据的切换(业务数据迁移),过程中遇到一个比较好玩的 BUG ,和大家分享并作为经验记录. 01 问题发现过程 通过前期的方案设计和比较,我们决定通过 elasticdump 工具来做 ES 的数据迁移,这个也是比较普遍的迁移方案,于是就动手实施了,过程中也没遇到什么问题.在最后的数据验证环节,发现有一个 ID 对应不上了,如下图所示,通过对比工具,发现一个长度较大的 ID

  • 浅谈Ruby on Rails下的rake与数据库数据迁移操作

    不知道你有没有把数据迁移写入Migration文件的经历,相信无论是老鸟还是新手都这样干过吧.事实上,这样做并不是行不通,只不过这样的实践慢慢会给你引入一些不必要的麻烦. 一般认为db/migrate文件夹里的内容是关于你数据库Schema的演变过程,每个新的开发或线上环境都要通过这些Migration来构建可用的数据库.但如果这里装入了,负责细节的业务代码,比如一些历史遗留数据的迁移代码之类的,当一段时间后,数据库的结构变化了,但Migration没有跟着变化,渐渐的曾经的辅助代码,就成了垃圾

  • 简述MySQL分片中快速数据迁移

    推荐阅读:MySQL 数据库跨操作系统的最快迁移方法 mysql 备份与迁移 数据同步方法 操作实践背景: travelrecord表定义为10个分片,尝试将10个分片中的2个分片转移到第二台MySQL上,并完成记录, 要求最快的数据迁移做法,中断业务时间最短 思路一利用mysqldump: 在这里我们只针对mysql innodb engine,而且配置bin-log的数据库进行分析.因为是将10个分片中的两个分片进行迁移,其实就是数据库的迁移过程,就是将10个数据库中的两个数据迁移到另外一台

  • Python中MySQL数据迁移到MongoDB脚本的方法

    MongoDB简介 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. MongoDB是一个文档数据库,在存储小文件方面存在天然优势.随着业务求的变化,需要将线上MySQL数据库中的行记录,导入到MongoDB中文档记录. 一.场景:线上MySQL数据库某表迁移到MongoDB,字段无变化. 二.Python

  • IOS 数据库升级数据迁移的实例详解

    IOS 数据库升级数据迁移的实例详解 概要: 很久以前就遇到过数据库版本升级的引用场景,当时的做法是简单的删除旧的数据库文件,重建数据库和表结构,这种暴力升级的方式会导致旧的数据的丢失,现在看来这并不不是一个优雅的解决方案,现在一个新的项目中又使用到了数据库,我不得不重新考虑这个问题,我希望用一种比较优雅的方式去解决这个问题,以后我们还会遇到类似的场景,我们都想做的更好不是吗? 理想的情况是:数据库升级,表结构.主键和约束有变化,新的表结构建立之后会自动的从旧的表检索数据,相同的字段进行映射迁移

  • oracle 数据库数据迁移解决方案

    去年年底做了不少系统的数据迁移,大部分系统由于平台和版本的原因,做的是逻辑迁移,少部分做的是物理迁移,有一些心得体会,与大家分享. 首先说说迁移流程,在迁移之前,写好方案,特别是实施的方案步骤一定要写清楚,然后进行完整的测试.我们在迁移时,有的系统测试了四五次,通过测试来完善方案和流程. 针对物理迁移,也即通过RMAN备份来进行还原并应用归档的方式(这里不讨论通过dd方式进行的冷迁移),虽然注意的是要将数据库设为force logging的方式,在用RMAN做全备之前,一定要执行: 否则可能会产

  • Docker版的MySQL5.7升级到MySQL8.0.13,数据迁移

    1.备份旧的MySQL5.7的数据 记得首先要备份旧的数据,防止升级失败导致数据丢失.备份的方式有两种,一种是在宿主机直接执行导出命令,另外一种是先进入Docker环境下进行操作.主要的导出命令如下: #方式一,直接在宿主机器进行数据备份 # 0df568 是docker的id ;-uroot -p123456 是用户名和密码;dbA dbB是要备份的数据,--databases 后面可以接多个数据库名,导出的sql到/root/all-databases3306.sql docker exec

  • oracle取数据库中最新的一条数据可能会遇到的bug(两种情况)

    记一次 开发中遇到的坑: 第一种情况 rowid select * from table where rowid=(select max(rowid) from table ) 这种方式是取最大的rowid作为最新的数据,但是有一个隐患 :数据库一旦有删除操作,rowid不能保证每次都是递增的!即max(rowid)并不一定就是最新的数据,尽管可能不会每次复现 但这个问题是绝对存在的! 第二种情况 使用rownum (或相同思路) select t.* from (select ti.sysno

  • 如何把sqlserver数据迁移到mysql数据库及需要注意事项

    在项目开发中,有时由于项目开始时候使用的数据库是SQL Server,后来把存储的数据库调整为MySQL,所以需要把SQL Server的数据迁移到MySQL.下面是小编日常整理的一种sqlserver数据库迁移的方法. 一.SQL Server中常用数据类型与MySQL不同的地方 二.将SQL Server数据迁移到MySQL需要注意的一些问题 1.唯一索引的不同,sql server的唯一索引的字段只能允许存在一个null值,而mysql,一直oracle中唯一索引对应的字段都允许存在多个n

  • Oracle数据库升级或数据迁移方法研究

    一.数据库升级的必要性 数据库升级是数据库管理员经常要面对的问题,如果你的应用要使用新版本数据库的新特性:如果数据库运行负载过重,而通过软硬件调整又不能有根本性的改善:如果要更换操作系统平台:如果要增强数据库的安全性:还有一个原因是随着新版本数据库的出现与成熟,oracle停止了对旧版本数据库的技术支持,升级到高版本,可以继续获得oracle的支持,还可以利用新版本数据库的新特新,可以改善系统的性能,健壮性,可扩张性和可用性,等等,面对这些问题,需要通过数据库升级才得以解决.不过,如果你的系统运

随机推荐