在 Amazon DocumentDB 里处理 Decimal128类型数据的解决方案

0
0
{"value":"#### **一道简单的数学题**\n\n在开始今天的内容之前,我们先计算一道简单的数学题。0.1 X 0.2 =?我相信很多人都笑了,0.02,这是一个孩童都可以回答得出的答案。我们用这道数学题问一下计算机,看看结果又是怎样。\n\n欢迎第一位选手 Java 入场\n\n```\\nJava Code:\\nclass Main {\\n public static void main(String[] args) {\\n System.out.println(0.1 * 0.2);\\n }\\n}\\n```\n\n计算机给出了答案:\n\n0.020000000000000004\n\n怎么样,是不是手心开始出汗了!我们再欢迎第二位选手 Node.Js 入场:\n\n```\\nNode.Js Code:\\n> 0.1\\n0.1\\n\\n> 0.2\\n0.2\\n> 0.1 * 0.2\\n0.020000000000000004\\n```\n\n还是0.020000000000000004。难道是乘法不行?那我们换加减法!\n\n有请最后一位选手 Golang 入场:\n\n```\\nGolang Code:\\na := 1024.1\\nb := a * 100\\nfmt.Println(b)\\n\\n102409.99999999999\\n\\nc := 2.6\\nfmt.Println(a - c)\\n\\n1021.4999999999999\\n```\n\n这是 Java 亦或是 Golang 的问题吗?当我们继续在 Python,Ruby 等主流语言上得到相同的结果时,是否会让你感觉世界观遭到了颠覆?\n\n不用怀疑自己,错的是计算机。为什么这么简单的数学题,强大如 Intel/AMD/Graviton 的 CPU 却不能给出正确答案呢?\n\n我们来看下真正的原因。其实是因为在十进制的数学体系中,二进制浮点类型并不适合用来表现或者描述数据本身。譬如0.1这个数字,如果使用二进制浮点类型来描述它时,它会被表现为0.0001100110011001101,这导致了很多数值在计算中会产生精度丢失或者结果偏差。\n\n当然,这在我们的日常生活中,并不会带来太大的问题。譬如天气预报中的温度与湿度指标,数值仅用作体感的参考,35.79999992摄氏度并不会让你感觉比36摄氏度更凉爽或者比35.5摄氏度更酷热;您在超市购物时,收银员也不会非要让你支付12.133333元相比12元多出来的0.133333元,但是在一些高精度计算的场景中,数值精度的丢失,会对最终的结果产生严重甚至完全相反的结果。那我们应该如何在保留数值精度的前提下,对数值进行计算呢?\n\n#### **Decimal 数据格式**\n\n与我们常见的 Float,Double 等近似保存的数据类型不同,Decimal 保存了精确的原始数值。可以说 Decimal 专门为十进制数学体系设计,弥补了二进制转述小数部分的缺憾,我们通过一张示意图来理解 decimal 的原理。\n\n![image.png](https://dev-media.amazoncloud.cn/dfbac84e49444919a845e007f2197749_image.png)\n\n#### **MongoDB 中的 Decimal**\n\n作为广泛使用的文档型数据库,MongoDB 也受到数值精度问题的困扰。为了能够实现高精度数值的存储与还原,decimal128应运而生,可以在特别微小数值的保存场景上,提供技术层面的支持。\n\n亚马逊云科技推出了托管的兼容 MongoDB 的云原生文档数据库 [Amazon DocumentDB](https://aws.amazon.com/cn/documentdb/),依托计算与存储分离的架构,在很多不同的场景下,帮助客户实现了集群快速扩容,自动流式备份,计算层扩缩容,存储层自动扩容等诸多云原生数据库的功能,简化了数据库运维工作与提高了工作效率。不过截至到2022年7月,DocumentDB 暂不支持 Decimal128格式的数据,该如何解决这个问题呢?\n\n**通过现象看本质,大家都是”String”**\n\n数字 与小数,本身也属于字符的一种,所以 Decimal 本身也是基于字符格式的一种延展。Decimal128(14.999999)与 Decimal(’14.999999’)存在什么本质上的不同,留给各位技术小伙伴们思考了。下面我们通过一个解决方案来解决 DocumentDB 与 Decimal128的兼容问题。大家一起来吧!\n\n本方案描述了如何短暂停机,将 Decimal128数据格式转换为 String 的步骤,这解决了存量数据的格式转换问题,并通过 Amazon Data Migration Service 实现了 MongoDB 向 DocumentDB 的离线迁移。\n\n```\\nCode 部分:\\n##MongoShell Statement,于 MongoDB 执行\\n##切换至 poc 数据库\\nuse poc;\\n\\n##创建 origin 数据表并插入两条测试数据,value 字段为 Decimal128\\ndb.origin.insertMany( [\\n{\\"_id\\": 1, \\"item\\": \\"Byte\\", \\"value\\": Decimal128(\\"1.333333\\") },\\n\\n{ \\"_id\\": 2, \\"item\\": \\"Bit\\", \\"value\\": Decimal128(\\"2.666666\\") }\\n] )\\n\\n##结果返回为插入成功\\n{ acknowledged: true, insertedIds: { '0': 1, '1': 2 } }\\n\\n##验证一下数据是否存在\\ndb.origin.find();\\n##返回结果确认数据创建成功;\\n[\\n { _id: 1, item: 'Byte', value: Decimal128(\\"1.333333\\") },\\n { _id: 2, item: 'Bit', value: Decimal128(\\"2.666666\\") }\\n]\\n\\n##转换开始,将 value 字段的 Decimal128格式转换为字符串 String 并另存新字段/列,取名为 newvalue,并将聚合之后的新表输出保存为 poc 数据库下以 newtable 为名的新表\\n\\ndb.getSiblingDB(\\"poc\\").origin.aggregate( [\\n{\\n\$addFields: {\\nnewvalue: { \$toString: \\"\$value\\" }\\n}\\n},\\n{ \$out : \\"newtable\\" }\\n] )\\n\\n##确认一下输出是否成功,在看到原始表 origin 之外,增加了一张新表 newtable\\nshow tables;\\n\\n##得到结果\\nnewtable\\norigin\\n\\n##查看一下转换之后新表 newtabl e里面的数据\\ndb.newtable.find();\\n\\n##结果返回可以看出除了原始表 origin 里的_id,item,value 三个字段之外,新增了一个字段 newvalue,其值与原始 decimal128格式的 value 字段,数值相等,且为字符串 String\\n\\n[\\n {\\n _id: 1,\\n item: 'Byte',\\n value: Decimal128(\\"1.333333\\"),\\n newvalue: '1.333333'\\n },\\n {\\n _id: 2,\\n item: 'Bit',\\n value: Decimal128(\\"2.666666\\"),\\n newvalue: '2.666666'\\n }\\n]\\n\\n#经过比对后,数据无误,我们删除原始 decimal128格式的 value 字段\\ndb.newtable.updateMany(\\n{ \\"_id\\": { \$gt: 0 } },\\n\\n{ \$unset: { value : \\"\\" } \\n}\\n)\\n\\n##并将 string 格式的 newvalue 重命名为 value\\ndb.newtable.updateMany(\\n{ \\"_id\\": { \$gt: 0 } },\\n\\n{ \$rename: { \\"newvalue\\": \\"value\\"}\\n }\\n)\\n\\n##返回两条数据修改完成,本段代码为控制台返回,无需执行\\n{\\n acknowledged: true,\\n insertedId: null,\\n matchedCount: 2,\\n modifiedCount: 2,\\n upsertedCount: 0\\n}\\n\\n##我们确认一下数据\\ndb.newtable.find();\\n\\n##返回数据中 value 字段已经是 string 格式,本段代码为控制台返回,无需执行\\n[\\n { _id: 1, item: 'Byte', value: '1.333333' },\\n { _id: 2, item: 'Bit', value: '2.666666' }\\n]\\n##使用 Mongo Shell 原生客户端登录 Amazon DocumentDB\\n##Bash Statement,其中 YOUR_DOCUMENTDB_ENDPOINT 请使用您环境的##DocumentDB 终端节点地址替换,YOUR_USER_NAME 请使用您环境的 DocumentDB 用户##替换,本操作使用了 DocumentDB 自定义参数组并关闭了 TLS,在您生产环境,建议保留##TLS 处于启用状态\\nmongosh --host YOUR_DOCUMENTDB_ENDPOINT -u YOUR_USER_NAME -p\\n\\n##输入用户密码登陆\\nEnter password: *************\\n\\n##DocumentDB Statement\\n##切换至 poc 数据库\\nUse poc;\\n\\n##查看数据表\\nshow tables;\\n\\n##返回为空,当前我们的数据库中没有数据表存在;\\n```\n\n#### **MongoDB 向 DocumentDB 迁移**\n\n除了可以使用 MongoDB 原生的 mongodump/mongorestore 进行数据的迁移,我们还可以使用 Amazon Data Migration Service(DMS)以 MongoDB 为数据源,以 [Amazon DocumentDB](https://aws.amazon.com/cn/documentdb/) 为数据目标,进行数据迁移,本例采用后者\n\n1.通过控制台找到 DMS 服务,并点选进入 DMS 控制台\n\n![image.png](https://dev-media.amazoncloud.cn/7b8d9f6e94c14ee6871ada5e5f666a93_image.png)\n\n2.点击左侧菜单栏的【子网组】,然后点击右上角的【创建子网组】\n\n![image.png](https://dev-media.amazoncloud.cn/3dbbdd1a24e54dc18fab191bcf5dbd0c_image.png)\n\n3.创建一个自定义子网组。如果您的环境是 MongoDB 与 DocumentDB 之间,存在有专线或者 VPN 构建的私有网络环境,您可以如图所示创建一个位于私有子网的自定义子网组,否则,请创建一个位于公有子网的自定义子网组。\n\n![image.png](https://dev-media.amazoncloud.cn/969253ad146c40a189af5513e69d4367_image.png)\n\n4.点击【创建子网组】,完成子网创建\n\n5.创建复制实例\n\n![image.png](https://dev-media.amazoncloud.cn/64f5736c3b324136aafc6a7012214513_image.png)\n\n![image.png](https://dev-media.amazoncloud.cn/dcbddb6897a14b64888389a964ddbec2_image.png)\n\n6. 如果您的环境是 MongoDB 与 DocumentDB 之间,存在有专线或者 VPN 构建的私有网络环境,您可以如图所示反选【公开访问】功能,否则,请勾选【公开访问】功能。\n\n![image.png](https://dev-media.amazoncloud.cn/dee1831cd7da46e99578421f60300fef_image.png)\n\n7.创建终端节点\n\n![image.png](https://dev-media.amazoncloud.cn/d8884138806f434ea156186efce9b7a0_image.png)\n\n7.1 创建以 MongoDB 为引擎的源终端节点\n\n![image.png](https://dev-media.amazoncloud.cn/d2b7cfaaf94443c19c5b6e4f62f0424d_image.png)\n\n7.2 按照您的实际情况替换红框内容\n\n![image.png](https://dev-media.amazoncloud.cn/134e9df8a6004752be84c7a13f4ca365_image.png)\n\n7.3 创建以 [Amazon DocumentDB](https://aws.amazon.com/cn/documentdb/) 为目标的目标终端节点\n\n![image.png](https://dev-media.amazoncloud.cn/c9f16c23a16b480d95c25b8d64b27246_image.png)\n\n![image.png](https://dev-media.amazoncloud.cn/ef993ee2ac944d7a8bf2dfc95b1d2cbc_image.png)\n\n7.4 使用 Secret Manager 来管理 DocumentDB 的账号信息(可选)\n\n详情可以阅读另一篇专题 blog,请点击[这里](https://aws.amazon.com/blogs/database/manage-your-aws-dms-endpoint-credentials-with-aws-secrets-manager/)\n\n8. 创建迁移任务\n\n![image.png](https://dev-media.amazoncloud.cn/1938f76350bc497b9e6db4eb3eaa147e_image.png)\n\n8.1 使用我们之前创建的复制节点,源终端节点,目标终端节点创建一个迁移任务\n\n![image.png](https://dev-media.amazoncloud.cn/f03e87bb2ea943d8801b3dbd45c121c3_image.png)\n\n8.2 在表映像部分,我们创建一个选择规则,对 poc 数据库下的newtable 数据表做选中,然后点选创建任务。\n\n![image.png](https://dev-media.amazoncloud.cn/e813d4e550744aadb19ad475d7d680cb_image.png)\n\n8.3 等待迁移任务加载完成,进度到达100%\n\n![image.png](https://dev-media.amazoncloud.cn/81d8c355af434eddbc254b4426a9edc1_image.png)\n\n至此存量数据已经通过本方案结合DMS全部迁移至 DocumentDB 下,并且完成了 Decimal128向 string 数据格式的转换。我们来做一个验证。\n\n```\\n##登陆到 DocumentDB\\n##DocumentDB Statement\\nmongosh --host YOUR_DOCUMENTDB_ENDPOINT -u YOUR_USER_NAME -p\\n\\n##输入用户密码登陆\\nEnter password: *************\\n\\n##切换至 poc 数据库\\nuse poc;\\n\\n##查看数据表\\nshow tables;\\n\\n##数据表已经由 DMS 同步到了 DocumentDB\\nnewtable\\n\\n##验证一下数据\\ndb.newtable.find();\\n\\n##结果返回符合我们预期\\n[\\n { _id: 1, item: 'Byte', value: '1.333333' },\\n { _id: 2, item: 'Bit', value: '2.666666' }\\n]\\n```\n\n#### **将 Decimal128转换为 Java BigDecimal**\n\n通过之前的解决方案,我们已经成功的把 Decimal128转换成为 String 存储在数据库中,实现了精度的保留,但是 string 格式保存的数值无法参与计算,我们应该如何解决这个难题?\n\n在 Java 语言中,Decimal128并不能被直接使用,需要专为 BigDecimal 之后,再进行各类处理与运算。我们知道 Decimal128是基于 String 的一种延展,那 String 能否按照这个思路进行处理呢?\n\n答案是可以的,我们可以借助 Java 的一个公共类 BigDecimal 实现我们的需求。以下为 Java 的示例代码,展示我们如何利用这个公共类,进行格式的双向转换,可供参考。\n\n```\\n##Java Code\\n##Transfer String to Java BigDecimal\\n##引用 BigDecimal 公共类\\nImport java.math.BigDecimal;\\n##定义公共类 String2BD\\nPublic class String2BD{\\n\\tpublic static void main(String[ ] args){\\n\\tString inputstring = “12.3456”;\\n\\tBigDecimal bd = new BigDecimal(inputstring);\\n\\tSystem.out.printIn(bd);\\n}\\n}\\n\\n```\n\n将输入字符串“12.3456“转换得到数字12.3456,可用于从数据库中读取字符串格式数据后转换为 Java 的 BigDecimal 格式。\n\n```\\n##Java Code\\n##Transfer Java BigDecimal to String\\n##引用 BigDecimal 公共类\\nImport java.math.BigDecimal;\\n##定义公共类 BD2String\\nPublic class BD2String{\\n\\tBigDecimal inputbd = new BigDecimal(65.4321)\\n\\tString outputstring = inputbd.toString();\\n\\tSystem.out.println(outputstring);\\n}\\n\\n```\n\n将 BigDecimal 格式65.4321转换得到字符串“65.4321“,可将结果以字符串格式存回数据库。\n\n#### **总结**\n\n用本方案使用 String 替代了 Decimal128,完成了存量数据的迁移,对于新增数据,在保证效率的前提下,通过 Java 的 BigDecimal 公共类实现 String 与 BigDecimal 的双向转换,解决了 DocumentDB 中需要使用 Decimal128格式的需求。DocumentDB 新功能持续发布中,敬请关注。\n\n参考链接:\n\n1.快速理解 Decimal\n\n[https://www.splashlearn.com/math-vocabulary/decimals/decimal](https://www.splashlearn.com/math-vocabulary/decimals/decimal)\n\n2.使用 Secret Manager 来管理 DMS Endpoints\n\n[https://aws.amazon.com/blogs/database/manage-your-aws-dms-endpoint-credentials-with-aws-secrets-manager/](https://aws.amazon.com/blogs/database/manage-your-aws-dms-endpoint-credentials-with-aws-secrets-manager/)\n\n3.Java Public Class BigDecimal from Oracle\n\n[https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html)\n\n#### **本篇作者**\n\n![image.png](https://dev-media.amazoncloud.cn/d62a355a564f4524baa410364184db43_image.png)\n\n#### **付晓明**\n\n亚马逊云解决方案架构师,负责云计算解决方案的咨询与架构设计,同时致力于数据库,边缘计算方面的研究和推广。在加入亚马逊云科技之前曾在金融行业IT部门负责互联网券商架构的设计,对分布式,高并发,中间件等具有丰富经验。","render":"<h4><a id=\\"_0\\"></a><strong>一道简单的数学题</strong></h4>\\n<p>在开始今天的内容之前,我们先计算一道简单的数学题。0.1 X 0.2 =?我相信很多人都笑了,0.02,这是一个孩童都可以回答得出的答案。我们用这道数学题问一下计算机,看看结果又是怎样。</p>\n<p>欢迎第一位选手 Java 入场</p>\n<pre><code class=\\"lang-\\">Java Code:\\nclass Main {\\n public static void main(String[] args) {\\n System.out.println(0.1 * 0.2);\\n }\\n}\\n</code></pre>\\n<p>计算机给出了答案:</p>\n<p>0.020000000000000004</p>\n<p>怎么样,是不是手心开始出汗了!我们再欢迎第二位选手 Node.Js 入场:</p>\n<pre><code class=\\"lang-\\">Node.Js Code:\\n&gt; 0.1\\n0.1\\n\\n&gt; 0.2\\n0.2\\n&gt; 0.1 * 0.2\\n0.020000000000000004\\n</code></pre>\\n<p>还是0.020000000000000004。难道是乘法不行?那我们换加减法!</p>\n<p>有请最后一位选手 Golang 入场:</p>\n<pre><code class=\\"lang-\\">Golang Code:\\na := 1024.1\\nb := a * 100\\nfmt.Println(b)\\n\\n102409.99999999999\\n\\nc := 2.6\\nfmt.Println(a - c)\\n\\n1021.4999999999999\\n</code></pre>\\n<p>这是 Java 亦或是 Golang 的问题吗?当我们继续在 Python,Ruby 等主流语言上得到相同的结果时,是否会让你感觉世界观遭到了颠覆?</p>\n<p>不用怀疑自己,错的是计算机。为什么这么简单的数学题,强大如 Intel/AMD/Graviton 的 CPU 却不能给出正确答案呢?</p>\n<p>我们来看下真正的原因。其实是因为在十进制的数学体系中,二进制浮点类型并不适合用来表现或者描述数据本身。譬如0.1这个数字,如果使用二进制浮点类型来描述它时,它会被表现为0.0001100110011001101,这导致了很多数值在计算中会产生精度丢失或者结果偏差。</p>\n<p>当然,这在我们的日常生活中,并不会带来太大的问题。譬如天气预报中的温度与湿度指标,数值仅用作体感的参考,35.79999992摄氏度并不会让你感觉比36摄氏度更凉爽或者比35.5摄氏度更酷热;您在超市购物时,收银员也不会非要让你支付12.133333元相比12元多出来的0.133333元,但是在一些高精度计算的场景中,数值精度的丢失,会对最终的结果产生严重甚至完全相反的结果。那我们应该如何在保留数值精度的前提下,对数值进行计算呢?</p>\n<h4><a id=\\"Decimal__58\\"></a><strong>Decimal 数据格式</strong></h4>\\n<p>与我们常见的 Float,Double 等近似保存的数据类型不同,Decimal 保存了精确的原始数值。可以说 Decimal 专门为十进制数学体系设计,弥补了二进制转述小数部分的缺憾,我们通过一张示意图来理解 decimal 的原理。</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/dfbac84e49444919a845e007f2197749_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"MongoDB__Decimal_64\\"></a><strong>MongoDB 中的 Decimal</strong></h4>\\n<p>作为广泛使用的文档型数据库,MongoDB 也受到数值精度问题的困扰。为了能够实现高精度数值的存储与还原,decimal128应运而生,可以在特别微小数值的保存场景上,提供技术层面的支持。</p>\n<p>亚马逊云科技推出了托管的兼容 MongoDB 的云原生文档数据库 Amazon DocumentDB,依托计算与存储分离的架构,在很多不同的场景下,帮助客户实现了集群快速扩容,自动流式备份,计算层扩缩容,存储层自动扩容等诸多云原生数据库的功能,简化了数据库运维工作与提高了工作效率。不过截至到2022年7月,DocumentDB 暂不支持 Decimal128格式的数据,该如何解决这个问题呢?</p>\n<p><strong>通过现象看本质,大家都是”String”</strong></p>\\n<p>数字 与小数,本身也属于字符的一种,所以 Decimal 本身也是基于字符格式的一种延展。Decimal128(14.999999)与 Decimal(’14.999999’)存在什么本质上的不同,留给各位技术小伙伴们思考了。下面我们通过一个解决方案来解决 DocumentDB 与 Decimal128的兼容问题。大家一起来吧!</p>\n<p>本方案描述了如何短暂停机,将 Decimal128数据格式转换为 String 的步骤,这解决了存量数据的格式转换问题,并通过 Amazon Data Migration Service 实现了 MongoDB 向 DocumentDB 的离线迁移。</p>\n<pre><code class=\\"lang-\\">Code 部分:\\n##MongoShell Statement,于 MongoDB 执行\\n##切换至 poc 数据库\\nuse poc;\\n\\n##创建 origin 数据表并插入两条测试数据,value 字段为 Decimal128\\ndb.origin.insertMany( [\\n{&quot;_id&quot;: 1, &quot;item&quot;: &quot;Byte&quot;, &quot;value&quot;: Decimal128(&quot;1.333333&quot;) },\\n\\n{ &quot;_id&quot;: 2, &quot;item&quot;: &quot;Bit&quot;, &quot;value&quot;: Decimal128(&quot;2.666666&quot;) }\\n] )\\n\\n##结果返回为插入成功\\n{ acknowledged: true, insertedIds: { '0': 1, '1': 2 } }\\n\\n##验证一下数据是否存在\\ndb.origin.find();\\n##返回结果确认数据创建成功;\\n[\\n { _id: 1, item: 'Byte', value: Decimal128(&quot;1.333333&quot;) },\\n { _id: 2, item: 'Bit', value: Decimal128(&quot;2.666666&quot;) }\\n]\\n\\n##转换开始,将 value 字段的 Decimal128格式转换为字符串 String 并另存新字段/列,取名为 newvalue,并将聚合之后的新表输出保存为 poc 数据库下以 newtable 为名的新表\\n\\ndb.getSiblingDB(&quot;poc&quot;).origin.aggregate( [\\n{\\n\$addFields: {\\nnewvalue: { \$toString: &quot;\$value&quot; }\\n}\\n},\\n{ \$out : &quot;newtable&quot; }\\n] )\\n\\n##确认一下输出是否成功,在看到原始表 origin 之外,增加了一张新表 newtable\\nshow tables;\\n\\n##得到结果\\nnewtable\\norigin\\n\\n##查看一下转换之后新表 newtabl e里面的数据\\ndb.newtable.find();\\n\\n##结果返回可以看出除了原始表 origin 里的_id,item,value 三个字段之外,新增了一个字段 newvalue,其值与原始 decimal128格式的 value 字段,数值相等,且为字符串 String\\n\\n[\\n {\\n _id: 1,\\n item: 'Byte',\\n value: Decimal128(&quot;1.333333&quot;),\\n newvalue: '1.333333'\\n },\\n {\\n _id: 2,\\n item: 'Bit',\\n value: Decimal128(&quot;2.666666&quot;),\\n newvalue: '2.666666'\\n }\\n]\\n\\n#经过比对后,数据无误,我们删除原始 decimal128格式的 value 字段\\ndb.newtable.updateMany(\\n{ &quot;_id&quot;: { \$gt: 0 } },\\n\\n{ \$unset: { value : &quot;&quot; } \\n}\\n)\\n\\n##并将 string 格式的 newvalue 重命名为 value\\ndb.newtable.updateMany(\\n{ &quot;_id&quot;: { \$gt: 0 } },\\n\\n{ \$rename: { &quot;newvalue&quot;: &quot;value&quot;}\\n }\\n)\\n\\n##返回两条数据修改完成,本段代码为控制台返回,无需执行\\n{\\n acknowledged: true,\\n insertedId: null,\\n matchedCount: 2,\\n modifiedCount: 2,\\n upsertedCount: 0\\n}\\n\\n##我们确认一下数据\\ndb.newtable.find();\\n\\n##返回数据中 value 字段已经是 string 格式,本段代码为控制台返回,无需执行\\n[\\n { _id: 1, item: 'Byte', value: '1.333333' },\\n { _id: 2, item: 'Bit', value: '2.666666' }\\n]\\n##使用 Mongo Shell 原生客户端登录 Amazon DocumentDB\\n##Bash Statement,其中 YOUR_DOCUMENTDB_ENDPOINT 请使用您环境的##DocumentDB 终端节点地址替换,YOUR_USER_NAME 请使用您环境的 DocumentDB 用户##替换,本操作使用了 DocumentDB 自定义参数组并关闭了 TLS,在您生产环境,建议保留##TLS 处于启用状态\\nmongosh --host YOUR_DOCUMENTDB_ENDPOINT -u YOUR_USER_NAME -p\\n\\n##输入用户密码登陆\\nEnter password: *************\\n\\n##DocumentDB Statement\\n##切换至 poc 数据库\\nUse poc;\\n\\n##查看数据表\\nshow tables;\\n\\n##返回为空,当前我们的数据库中没有数据表存在;\\n</code></pre>\\n<h4><a id=\\"MongoDB__DocumentDB__188\\"></a><strong>MongoDB 向 DocumentDB 迁移</strong></h4>\\n<p>除了可以使用 MongoDB 原生的 mongodump/mongorestore 进行数据的迁移,我们还可以使用 Amazon Data Migration Service(DMS)以 MongoDB 为数据源,以 Amazon DocumentDB 为数据目标,进行数据迁移,本例采用后者</p>\n<p>1.通过控制台找到 DMS 服务,并点选进入 DMS 控制台</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/7b8d9f6e94c14ee6871ada5e5f666a93_image.png\\" alt=\\"image.png\\" /></p>\n<p>2.点击左侧菜单栏的【子网组】,然后点击右上角的【创建子网组】</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/3dbbdd1a24e54dc18fab191bcf5dbd0c_image.png\\" alt=\\"image.png\\" /></p>\n<p>3.创建一个自定义子网组。如果您的环境是 MongoDB 与 DocumentDB 之间,存在有专线或者 VPN 构建的私有网络环境,您可以如图所示创建一个位于私有子网的自定义子网组,否则,请创建一个位于公有子网的自定义子网组。</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/969253ad146c40a189af5513e69d4367_image.png\\" alt=\\"image.png\\" /></p>\n<p>4.点击【创建子网组】,完成子网创建</p>\n<p>5.创建复制实例</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/64f5736c3b324136aafc6a7012214513_image.png\\" alt=\\"image.png\\" /></p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/dcbddb6897a14b64888389a964ddbec2_image.png\\" alt=\\"image.png\\" /></p>\n<ol start=\\"6\\">\\n<li>如果您的环境是 MongoDB 与 DocumentDB 之间,存在有专线或者 VPN 构建的私有网络环境,您可以如图所示反选【公开访问】功能,否则,请勾选【公开访问】功能。</li>\n</ol>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/dee1831cd7da46e99578421f60300fef_image.png\\" alt=\\"image.png\\" /></p>\n<p>7.创建终端节点</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/d8884138806f434ea156186efce9b7a0_image.png\\" alt=\\"image.png\\" /></p>\n<p>7.1 创建以 MongoDB 为引擎的源终端节点</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/d2b7cfaaf94443c19c5b6e4f62f0424d_image.png\\" alt=\\"image.png\\" /></p>\n<p>7.2 按照您的实际情况替换红框内容</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/134e9df8a6004752be84c7a13f4ca365_image.png\\" alt=\\"image.png\\" /></p>\n<p>7.3 创建以 Amazon DocumentDB 为目标的目标终端节点</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/c9f16c23a16b480d95c25b8d64b27246_image.png\\" alt=\\"image.png\\" /></p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/ef993ee2ac944d7a8bf2dfc95b1d2cbc_image.png\\" alt=\\"image.png\\" /></p>\n<p>7.4 使用 Secret Manager 来管理 DocumentDB 的账号信息(可选)</p>\n<p>详情可以阅读另一篇专题 blog,请点击<a href=\\"https://aws.amazon.com/blogs/database/manage-your-aws-dms-endpoint-credentials-with-aws-secrets-manager/\\" target=\\"_blank\\">这里</a></p>\\n<ol start=\\"8\\">\\n<li>创建迁移任务</li>\n</ol>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/1938f76350bc497b9e6db4eb3eaa147e_image.png\\" alt=\\"image.png\\" /></p>\n<p>8.1 使用我们之前创建的复制节点,源终端节点,目标终端节点创建一个迁移任务</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/f03e87bb2ea943d8801b3dbd45c121c3_image.png\\" alt=\\"image.png\\" /></p>\n<p>8.2 在表映像部分,我们创建一个选择规则,对 poc 数据库下的newtable 数据表做选中,然后点选创建任务。</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/e813d4e550744aadb19ad475d7d680cb_image.png\\" alt=\\"image.png\\" /></p>\n<p>8.3 等待迁移任务加载完成,进度到达100%</p>\n<p><img src=\\"https://dev-media.amazoncloud.cn/81d8c355af434eddbc254b4426a9edc1_image.png\\" alt=\\"image.png\\" /></p>\n<p>至此存量数据已经通过本方案结合DMS全部迁移至 DocumentDB 下,并且完成了 Decimal128向 string 数据格式的转换。我们来做一个验证。</p>\n<pre><code class=\\"lang-\\">##登陆到 DocumentDB\\n##DocumentDB Statement\\nmongosh --host YOUR_DOCUMENTDB_ENDPOINT -u YOUR_USER_NAME -p\\n\\n##输入用户密码登陆\\nEnter password: *************\\n\\n##切换至 poc 数据库\\nuse poc;\\n\\n##查看数据表\\nshow tables;\\n\\n##数据表已经由 DMS 同步到了 DocumentDB\\nnewtable\\n\\n##验证一下数据\\ndb.newtable.find();\\n\\n##结果返回符合我们预期\\n[\\n { _id: 1, item: 'Byte', value: '1.333333' },\\n { _id: 2, item: 'Bit', value: '2.666666' }\\n]\\n</code></pre>\\n<h4><a id=\\"_Decimal128_Java_BigDecimal_283\\"></a><strong>将 Decimal128转换为 Java BigDecimal</strong></h4>\\n<p>通过之前的解决方案,我们已经成功的把 Decimal128转换成为 String 存储在数据库中,实现了精度的保留,但是 string 格式保存的数值无法参与计算,我们应该如何解决这个难题?</p>\n<p>在 Java 语言中,Decimal128并不能被直接使用,需要专为 BigDecimal 之后,再进行各类处理与运算。我们知道 Decimal128是基于 String 的一种延展,那 String 能否按照这个思路进行处理呢?</p>\n<p>答案是可以的,我们可以借助 Java 的一个公共类 BigDecimal 实现我们的需求。以下为 Java 的示例代码,展示我们如何利用这个公共类,进行格式的双向转换,可供参考。</p>\n<pre><code class=\\"lang-\\">##Java Code\\n##Transfer String to Java BigDecimal\\n##引用 BigDecimal 公共类\\nImport java.math.BigDecimal;\\n##定义公共类 String2BD\\nPublic class String2BD{\\n\\tpublic static void main(String[ ] args){\\n\\tString inputstring = “12.3456”;\\n\\tBigDecimal bd = new BigDecimal(inputstring);\\n\\tSystem.out.printIn(bd);\\n}\\n}\\n\\n</code></pre>\\n<p>将输入字符串“12.3456“转换得到数字12.3456,可用于从数据库中读取字符串格式数据后转换为 Java 的 BigDecimal 格式。</p>\n<pre><code class=\\"lang-\\">##Java Code\\n##Transfer Java BigDecimal to String\\n##引用 BigDecimal 公共类\\nImport java.math.BigDecimal;\\n##定义公共类 BD2String\\nPublic class BD2String{\\n\\tBigDecimal inputbd = new BigDecimal(65.4321)\\n\\tString outputstring = inputbd.toString();\\n\\tSystem.out.println(outputstring);\\n}\\n\\n</code></pre>\\n<p>将 BigDecimal 格式65.4321转换得到字符串“65.4321“,可将结果以字符串格式存回数据库。</p>\n<h4><a id=\\"_325\\"></a><strong>总结</strong></h4>\\n<p>用本方案使用 String 替代了 Decimal128,完成了存量数据的迁移,对于新增数据,在保证效率的前提下,通过 Java 的 BigDecimal 公共类实现 String 与 BigDecimal 的双向转换,解决了 DocumentDB 中需要使用 Decimal128格式的需求。DocumentDB 新功能持续发布中,敬请关注。</p>\n<p>参考链接:</p>\n<p>1.快速理解 Decimal</p>\n<p><a href=\\"https://www.splashlearn.com/math-vocabulary/decimals/decimal\\" target=\\"_blank\\">https://www.splashlearn.com/math-vocabulary/decimals/decimal</a></p>\\n<p>2.使用 Secret Manager 来管理 DMS Endpoints</p>\n<p><a href=\\"https://aws.amazon.com/blogs/database/manage-your-aws-dms-endpoint-credentials-with-aws-secrets-manager/\\" target=\\"_blank\\">https://aws.amazon.com/blogs/database/manage-your-aws-dms-endpoint-credentials-with-aws-secrets-manager/</a></p>\\n<p>3.Java Public Class BigDecimal from Oracle</p>\n<p><a href=\\"https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html\\" target=\\"_blank\\">https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html</a></p>\\n<h4><a id=\\"_343\\"></a><strong>本篇作者</strong></h4>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/d62a355a564f4524baa410364184db43_image.png\\" alt=\\"image.png\\" /></p>\n<h4><a id=\\"_347\\"></a><strong>付晓明</strong></h4>\\n<p>亚马逊云解决方案架构师,负责云计算解决方案的咨询与架构设计,同时致力于数据库,边缘计算方面的研究和推广。在加入亚马逊云科技之前曾在金融行业IT部门负责互联网券商架构的设计,对分布式,高并发,中间件等具有丰富经验。</p>\n"}
目录
亚马逊云科技解决方案 基于行业客户应用场景及技术领域的解决方案
联系亚马逊云科技专家
亚马逊云科技解决方案
基于行业客户应用场景及技术领域的解决方案
联系专家
0
目录
关闭