当前位置: 首页 > news >正文

新企业如何在国税网站上做套餐天津建设工程信息网专家

新企业如何在国税网站上做套餐,天津建设工程信息网专家,注册公司的流程图,惠州 企业网站建设概述 订单系统可以说是整个电商系统中最重要的一个子系统#xff0c;因此订单数据可以算作电商企业最重要的数据资产。订单系统从代码上来说可分为两部分#xff1a;订单程序和历史订单处理程序。数据存储进行分库分表。 订单系统业务分析 对于一个合格的订单系统#xf…概述 订单系统可以说是整个电商系统中最重要的一个子系统因此订单数据可以算作电商企业最重要的数据资产。订单系统从代码上来说可分为两部分订单程序和历史订单处理程序。数据存储进行分库分表。 订单系统业务分析 对于一个合格的订单系统最基本的要求是什么数据不能出错。用户的每一次购物从下单开始到支付、发货再到收货流程中的每个环节都需要同步更新订单数据每次更新操作可能都需要同时更新好几张表。这些操作可能会随机分发到不同的服务器节点上执行服务器或网络都有可能会出问题在这么复杂的情况下如何保证订单数据不出错呢第一代码必须是正确的没有 Bug当然这个要求很简单也很复杂全是 Bug 系统无法正常运行但是也没有什么系统能保证没有一个 Bug。当然要确保不能因为代码 Bug 而导致数据错误。第二要能够正确地使用事务。比如在创建订单的时候如果需要同时在订单表和订单商品表中插入数据那么我们必须在一个数据库事务中执行这些插入数据的 INSERT 语句数据库事务可以确保执行需要同时进行的操作语句时要么一起成功要么一起失败。而实际上在微服务下仅仅使用数据库事务是不够的很多时候还需要分布式事务。即使满足了上面列举的这两个基本要求某些特殊情况也仍然可能会引发数据错误是什么样的数据错误问题如何解决呢其实任何一个公司的电商系统其订单系统的功能都是独一无二的因为订单系统会基于其业务配置了很多的功能并且都很复杂。因此我们的电商系统只能化繁为简聚焦那些最核心的、共通的业务功能和数据模型并且以此为基础讨论其中的实现技术。 订单系统的核心功能和数据表 首先简单梳理一下订单系统所必备的功能其包含但远远不限于如下功能 创建订单 从京东的流程可以看到用户从购物车选择了商品后去结算而创建订单其实包括两个业务步骤一是订单确认二是订单提交。订单提交后则进入支付流程。 更新订单状态 随着购物流程推进更新订单状态。 查询订单 为了支撑这些必备功能一般订单数据库中至少需要具备如下 4 张表订单主表也称订单表用于保存订单的基本信息。订单商品表用于保存订单中的商品信息。订单支付表用于保存订单的支付和退款信息。订单优惠表用于保存订单使用的所有优惠信息。这 4 张表之间的关系是订单主表与后面的几个子表都是一对多的关系关联的外键就是订单主表的主键即订单 ID。订单状态包括“0-待付款1-待发货2-已发货3-已完成4-已关闭5-无效订单”。 订单重复下单问题 仔细分析一下订单创建的场景订单系统为用户提供创建订单的 HTTP 接口用户在浏览器页面上点击“提交订单”按钮浏览器向订单系统发送一条创建订单的请求订单系统的后端服务收到请求向数据库的订单表中插入一条订单数据至此订单创建成功。那么我们设想一下用户在点击“提交订单”的按钮时不小心点了两下那么浏览器就会向服务端连续发送两条创建订单的请求最终的结果将会是什么很自然会创建两条一模一样的订单。这样肯定是不行的因此我们还需要做好防重工作怎么做呢可能有人会想到前端页面上应该防止用户重复提交表单当用户“提交订单”的按钮后将该按钮置灰不可用。但是仔细想想即使前端控制了用户不重复提交网络错误也有可能会导致重传很多 RPC 框架和网关都拥有自动重试机制所以对于订单服务来说重复请求的问题是客观存在的。解决办法是让订单服务具备幂等性。什么是幂等性幂等操作的特点是操作任意多次执行所产生的影响均与一次执行所产生的影响相同。也就是说对于幂等方法使用同样的参数对它进行多次调用和一次调用其对系统产生的影响是一样的。例如 update tableA set count 10 where id 1;这个操作多次执行id 等于 1 的记录中的 count 字段的值都为 10这个操作就是幂等的我们不用担心这个操作被重复。 update tableA set count count 1 where id 1;这样的 SQL 操作就不是幂等的一旦重复结果就会产生变化。所以不用担心幂等方法的重复执行会对系统造成任何改变。如果创建订单的服务具备幂等性那么无论创建订单的请求发送了多少次正确的结果都是数据库只有一条新创建的订单记录。这里又会涉及一个不太好解决的问题对于订单服务来说如何判断收到的创建订单的请求是不是重复请求呢在插入订单数据之前先查询一下订单表里面有没有重复的订单是不是就可以做出判斯了呢这个方法看起来容易。实际上却很难实现。原因是我们很难通过 SQL 的 WHERE 语句来定义“重复的订单”如果订单的用户、商品、数量和价格都一样是否就能认为它们是重复订单呢这个其实是无法确定的因为有可能用户就是连续下了两个一模一样的订单。这个问题的思路是利用数据库的唯一约束来判断数据是否重复。在数据库的最佳实践中其中一条是要求数据库的每个表都有主键。在非分库分表的情况下我们在向数据库的表中插入一条记录的时候无需提供主键插入的同时由数据库自动生成一个主键。这样重复的请求就会导致插入重复的数据。表的主键是自带唯一约束的如果我们在一条 INSERT 语句中提供了主键并且这个主键的值已经存在于表中那么这条 INSERT 语句就会执行失败数据也不会成功插入表中。我们可以利用数据库的这种“主键唯一约束”特性在插入数据的时候带上主键来解决创建订单服务的幂等性问题。具体做法如下首先为订单系统增加一个“生成订单号”的服务这个服务没有参数返回值就是一个新的、全局唯一的订单号。在用户进入创建订单的页面时前端页面会先调用这个生成订单号的服务得到一个订单号在用户提交订单的时候在创建订单的请求中带着这个订单号。这个订单号就是订单表的主键这样无论是用户原因还是网络原因等各种情况导致的重试这些重复请求中的订单号都是相同的。订单服务在订单表中插入数据的时候这些重复的 INSERT 语句中的主键都是同一个订单号。数据库的主键唯一约束特性就可以保证只有一次 INSERT 语句的执行是成功的这样就实现了创建订单服务的幂等性。时序图如下还有一点需要注意的是在具体实现时如果是因为重复订单导致插入订单表的语句失败那么订单服务就不要再把这个错误返回给前端页面了。否则就有可能会出现用户点击创建订单按钮后页面提示创建订单失败而实际上订单已经创建成功了。正确的做法是遇到这种情况订单服务直接返回“订单创建成功”的响应即可。 订单 ABA 问题和解决 订单系统中各种更新订单的服务同样也需要具备幂等性。更新订单的服务比如支付、发货等这些步骤中的更新订单操作最终都会落到订单库上都是对订单主表进行更新操作。比如对支付操作的数据库的更新操作、无论是执行一次还是重复执行多次订单状态都是已支付不用我们额外设置任何逻辑这就是天然幂等性。在实现这些更新订单的服务时还有哪些问题需要特别注意呢在并发环境下我们需要特别注意 ABA 问题。什么是更新下的 ABA 问题呢我们知道并发编程下的 CAS 有 ABA 问题这个 ABA 问题和并发的 ABA 问题有相似之处。我们来看这么一个例子订单支付完成填入物流单号 666 提交后发现填错了修改成正确的单号 888对于订单服务来说这里就产生了两个更新订单的请求。按照我们的设想正常情况下订单中的快递单号会先更新成 666再更新成 888这是没有问题的。但是现实生活有很多不正常的情况比如更新成 666 的请求到了快递单号更新成 666然后更新成 888 的请求到了快递单号又更新成 888。但是订单服务在向调用方返回 666 更新成功的响应时这个响应在网络传输过程中丢失了。如果调用方没有收到成功响应触发自动重试逻辑再次发起更新成 666 的请求快递单号将会再次更新成 666这种情况下数据显然就会出错了。这就是 ABA 问题。那么 ABA 问题应该怎么解决呢仔细想想并发编程里怎么解决 ABA 问题的版本戳。所以这里同样可以使用版本戳。为订单主表增加一列列名可以叫 version、也就是“版本号”的意思。每次查询订单的时候版本号需要随着订单数据返回给页面。页面在更新数据的请求时需要把该版本号作为更新请求的参数再带回给订单更新服务。订单服务在更新数据的时候需要比较订单当前数据的版本号与消息中的版本号是否一致如果不一致就拒绝更新数据。如果版本号一致则还需要在更新数据的同时把版本号加 1。当然需要特别注意的是“比较版本号、更新数据和把版本号加 1”这个过程必须在同一个事务里面执行只有这一系列操作具备原子性才能真正保证并发操作的安全性。具体的 SQL 语句参考如下: UPDATE orders set tracking_number 666,version version 1 WHERE version ?;版本号的机制可用于保证从打开某条订单记录开始一直到这条订单记录更新成功这期间不会存在有其他人修改过这条订单数据的情况。因为如果被其他人修改过数据库中的版本号就会发生改变那么更新订单的操作就不会执行成功而只能重新查询新版本的订单数据然后再尝试更新。总的来说因为网络、服务器等导致的不确定因素重试请求是普遍存在且不可避免的问题。具有幂等性的服务可以克服由于重试问题而导致的数据错误。所以总的来说对于创建订单的服务可以通过预先生成订单号作为主键然后利用数据库中“主键唯一约束”的特性避免重复写入订单实现创建订单服务的幂等性。对于更新订单的服务可以通过一个版本号机制即在每次更新数据之前校验版本号以及在更新数据的同时自增版本号这样的方式来解决 ABA 问题以确保更新订单服务的幂等性。通过这样两种具备幂等性的实现方法我们可以保证无论是不是重复请求订单表中的数据都是正确的。当然这里讲到的实现订单幂等性的方法在其他需要实现幂等性的服务中也完全可以套用只需要这个服务操作的数据保存在数据库中并且数据表带有主键即可。实现服务幂等性的方法远不止本章介绍的这两种其实实现幂等性的方法可分为两大类一类是通过一些精巧的设计让更新本身就是幂等的这种方法并不能适用于所有的业务。另一类是利用外部的具备一致性的存储比如 MySQL来做冲突检测在设计幂等方法的时候通常可以顺着这两个思路来展开。 读写分离与分库分表 使用 Redis 作为 MySQL 的前置缓存可以帮助 MySQL 挡住绝大部分的查询请求。这种方法对于像电商中的商品系统、搜索系统这类与用户关联不大的系统、效果特别好。因为在这些系统中、任何人看到的内容都是一样的也就是说对后端服来说任何人的查询请求和返回的数据都是一样的。在这种情况下Redis 缓存的命中率非常高几乎所有的请求都可以命中缓存。但是与用户相关的系统不是用户系统本身用户信息等相关数据在用户登录时进行缓存就价值很高使用缓存的效果就没有那么好了比如订单系统、账户系统、购物车系统、订单系统等等。对于这些系统而言各个用户查询的信息与用户自身相关即使同一个功能界面用户看到的数据也是不一样的。比如“我的订单”这个功能用户看到的都是自己的订单数据。在这种情况下缓存的命中率就比较低了会有相当一部分查询请求因为命中不了缓存穿透到 MySQL 数据库中。随着系统的用户数量越来越多穿透到 MySQL 数据库中的读写请求也会越来越多当单个 MySQL 支撑不了这么多的并发请求时该怎么办? 读写分离 读写分离是提升 MySQL 并发能力的首选方案当单个 MySQL 无法满足要求的时候只能用多个 MySQL 实例来承担大量的读写请求。MySQL 与大部分常用的关系型数据库一样都是典型的单机数据库不支持分布式部署。用一个单机数据库的多个实例组成一个集群提供分布式数据库服务是一件非常困难的事情。一个简单且非常有效的是用多个具有相同数据的 MySOL 实例来分担大量查询请求也就是“读写分离”。很多系统特别是互联网系统数据的读写比例严重不均衡读写比例一般在 9:1 到几十比 1即平均每发生几十次查询请求才会有一次更新请求那就是说数据库需要应对的绝大部分请求都是只读查询请求。分布式存储系统支持分布式写是非常困难的因为很难解决好数据一致性的问题。但分布式读相对来说就简单得多能够把数据尽可能实时同步到只读实例上它们就可以分担大量的查询请求了。读写分离的另一个好处是实施起来相对比较简单。把使用单机 MySQL 的系统升级为读写分离的多实例架构非常容易一般不需要修改系统的业务逻辑只需要简单修改 DAOData Access Object一般指应用程序中负责访问数据库的抽象层层的代码把对数据库的读写请求分开请求不同的 MySQL 实例就可以了。通过读写分离这样一个简单的存储架构升级数据库支持的并发数量就可以增加几倍到十几倍。所以当系统的用户数越来越多时读写分离应该是首要考虑的扩容方案。主库负责执行应用程序发来的数据更新请求然后将数据变更同步到所有的从库中。这样主库和所有从库中的数据一致多个从库可以共同分担应用的查询请求。 读写分离的数据不一致问题 读写分离的一个副作用是可能会存在数据不一致的问题。原因是数据库中的数据在主库完成更新后是异步同步到每个从库上的这个过程会有一个微小的时间差。正常情况下主从延迟非常小以几毫秒计。但即使是这样小的延迟也会导致在某个时刻主库和从库上数据不一致的问题。应用程序需要能够接受并克服这种主从不一致的情况否则就会引发一些由于主从延迟而导致的数据错误。回顾我们的订单系统业务用户对购物车发起商品结算创建订单进入订单页打开支付页面进行支付支付完成后按道理应该再返回到支付之前的订单页。但如果这时马上自动返回到订单页就很有可能会出现订单状态还是显示“未支付”的问题。因为支付完成后订单库的主库中订单状态已经更新了但订单页查询的从库中这条订单记录的状态可能还未更新如何解决这种问题呢其实这个问题并没有特别好的技术手段来解决所以可以看到稍微上点规模的电商网站并不会支付完成后自动跳到到订单页而是增加了一个支付完成页面这个页面其实没有任何新的有效信息就是告诉你支付成功的信息。如果想再查看一下刚刚支付完成的订单需要手动选择这样就能很好地规避主从同步延迟的问题。如果是那些数据更新后需要立刻查询的业务这两个步骤可以放到一个数据库事务中同一个事务中的查询操作也会被路由到主库这样就可以规避主从不一致的问题了还有一种解决方式则是对查询部分单独指定进行主库查询。总的来说对于这种因为主从延迟而带来的数据不一致问题并没有一种简单方便且通用的技术方案可以解决对此我们需要重新设计业务逻辑尽量规避更新数据后立即去从库查询刚刚更新的数据。 分库分表 除了访问 MySQL 的并发问题还要解决海量数据的问题很多的时候我们会使用分布式的存储集群因为 MySQI 本质上是一个单机数据库所以很多场景下其并不适合存储 TB 级别以上的数据。但是绝大部分电商企业的在线交易类业务比如订单、支付相关的系统还是无法离开 MySQL 的。原因是只有 MySOL 之类的关系型数据库才能提供金融级的事务保证。目前的分布式事务的各种解法方案多少都有些不够完善。虽然 MySQL 无法支持这么大的数据量以及这么高的并发需求但是交易类系统必须用它来保证数据一致性那么如何才能解决这个问题呢这个时候我们就要考虑分片也就是拆分数据。如果一个数据库无法支撑 1TB 的数据那就把它拆分成 100 个库每个库就只有 10GB 的数据了。这种拆分操作就是 MySOL 的分库分表操作。 如何规划分库分表 以订单表为例首先我们需要思考的问题是选择分库还是分表或者两者都有分库就是把数据拆分到不同的 MySQL 数据库实例中分表就是把数据拆分到一个数据库的多张表里面。在考虑到底是选择分厍还是分表之前我们需要首先明确一个原则那就是能小拆就小拆能少拆就少拆。原因很简单数据拆得越分散并发和维护就越麻烦系统出问题的概率也就越大。遵循上面这个原则还需要进一步了解哪种情况适合分表哪种情况适合分库。选择分厍或是分表的目的是解决如下两个问题。第一是为了解决因数据量太大而导致查询慢的问题。这里所说的“查询”其实主要是事务中的查询和更新操作因为只读的查询可以通过缓存和主从分离来解决。分表主要用于解决因数据量大而导致的查询慢的问题。第二是为了应对高并发的问题。如果一个数据库实例撑不住就把并发请求分散到多个实例中所以分库可用于解决高并发的问题。简单地说如果数据量太大就分表如果并发请求量高就分库。一般情况下我们的解决方案大都需要同时做分库分表我们可以根据预估的并发量和数据量分别计算应该拆分成多少个库以及多少张表。 商城订单服务的实现 数据量 在设计系统我们预估订单的数量每个月订单 2000W每天 60w一年的订单数可达 2.4 亿。而每条订单的大小大致为 1KB按照我们在 MySQL 中学习到的知识为了让 B 树的高度控制在一定范围保证查询的性能每个表中的数据不宜超过 2000W。在这种情况下为了存下 2.4 亿的订单我们似乎应该将订单表分为 1612 往上取最近的 2 的幂张表。但是这样设计有个问题我们只考虑了订单表没有考虑订单详情表。我们预估一张订单下的商品平均为 10 个那即使一年的订单详情数可以达到 24 亿同样以每表 2000W 记录计算应该订单详情表为 128120 往上取最近的 2 的幂张而订单表和订单详情表虽然记录数上是一对一的关系但是表之间还是一对一也就是说订单表也要为 128 张。经过再三分析我们最终将订单表和订单详情表的张数定为 32 张。这会导致订单详情表单表的数据量达到 8000W为何要这么设计呢原因我们后面再说。 选择分片键 既然决定订单系统分库分表则还有一个重要的问题那就是如何选择一个合适的列作为分表的依据该列我们一般称为分片键Sharding Key)。选择合适的分片键和分片算法非常重要因为其将直接影响分库分表的效果。选择分片键有一个最重要的参考因素是我们的业务是如何访问数据的比如我们把订单 ID 作为分片键来诉分订单表。那么拆分之后如果按照订单 ID 来查询订单就需要先根据订单 ID 和分片算法计算所要查的这个订单具体在哪个分片上也就是哪个库的哪张表中然后再去那个分片执行查询操作即可。但是当用户打开“我的订单”这个页面的时候它的查询条件是用户 ID由于这里没有订单 ID因此我们无法知道所要查询的订单具体在哪个分片上也就没法查了。如果要强行查询的话那就只能把所有的分片都查询一遍再合并查询结果这个过程比较麻烦而且性能很差对分页也很不友好。那么如果是把用户 ID 作为分片键呢答案是也会面临同样的问题使用订单 ID 作为查询条件时无法定位到具体的分片上。这个问题的解决办法是在生成订单 ID 的时候把用户 ID 的后几位作为订单 ID 的一部分。这样按订单 ID 查询的时候就可以根据订单 ID 中的用户 ID 找到分片。所以在我们的系统中订单 ID 从唯一 ID 服务获取 ID 后还会将用户 ID 的后两位拼接形成最终的订单 ID。然而系统对订单的查询万式肯定不只是按订单 ID 或按用户 ID 查询两种方式。比如如果有商家希望查询自家家店的订单有与订单相关的各种报表。对订单做了分库分表就没法解决了。这个问题又该怎么解决呢一般的做法是把订单里数据同步到其他存储系统中然后在其他存储系统里解决该问题。比如可以再构建一个以店铺 ID 作为分片键的只读订单库专供商家使用。或者数据同步到 Hadoop 分布式文件系统HDFS中然后通过一些大数据技术生成与订单相关的报表。在分片算法上我们知道常用的有按范围比如时间范围分片哈希分片查表法分片。我们这里直接使用哈希分片对表的个数 32 直接取模一旦做了分库分表就会极大地限制数据库的查询能力原本很简单的查询分库分表之后可能就没法实现了。分库分表一定是在数据量和并发请求量大到所有招数都无效的情况下我们才会采用的最后一招。 具体实现 如何在代码中实现读写分离和分库分表呢一般来说有三种方法。1纯手工方式修改应用程序的 DAO 层代码定义多个数据源在代码中需要访问数据库的每个地方指定每个数据库请求的数据源。2组件方式使用像 Sharding-JDBC 这些组件集成在应用程序内用于代理应用程序的所有数据库请求并把请求自动路由到对应的数据库实例上。3代理方式在应用程序和数据库实例之间部署一组数据库代理实例比如 Atlas 或 Sharding-Proxy。对于应用程序来说数据库代理把自己伪装成一个单节点的 MySQL 实例应用程序的所有数据库请求都将发送给代理代理分离请求然后将分离后的请求转发给对应的数据库实例。在这三种方式中一般推荐第二种使用分离组件的方式。采用这种方式代码侵入非常少同时还能兼顾性能和稳定性。如果应用程序是一个逻辑非常简单的微服务简单到只有几个 SQL或者应用程序使用的编程语言没有合适的读写分离组件那么也可以考虑通过纯手工的方式。不推荐使用代理方式第三种方式原因是代理方式加长了系统运行时数据库请求的调用链路会造成一定的性能损失而且代理服务本身也可能会出现故障和性能瓶颈等问题。代理方式有一个好处对应用程序完全透明。在分片键的选择上订单信息的查询往往会指定订单的 ID 或者用户 ID所以用到订单表中的 ID 和用户 ID。 MySQL 应对海量数据 归档历史数据 订单数据会随着时间一直累积的数据前面我们说过预估订单的数量每个月订单 2000W一年的订单数可达 2.4 亿三年可达 7.2 亿。数据量越大数据库就会越慢这是为什么我们需要理解造成这个问题的根本原因。无论是“增、删、改、查”中的哪个操作其本质都是查找数据因为我们需要先找到数据然后才能操作数据。无论采用的是哪种存储系统一次查询所耗费的时间都取决于如下两个因素1查找的时间复杂度。2数据总量。查找的时间复杂度又取决于如下两个因素1查找算法。2存储数据的数据结构。这两个因素也是面试问题中经常考察的知识。 所以面试官并不是非要问一些“用不上”的问题来为难求职者这些知识点不是用不上而是求职者很多时候不知道怎么用。大多数做业务的系统采用的都是现成的数据库数据的存储结构和查找算法都是由数据库来实现的对此业务系统基本上无法做出任何改变。我们知道 MySQL 的 InnoDB 存储引擎其存储结构是 B 树查找算法大多数时候是对树进行查找查找的时间复杂度就是 O(log n)这些都是固定的。我们唯一能改变的就是数据总量了。所以解决海量数据导致存储系统慢的问题方法非常简单就是一个“拆”字把大数据拆分成若干份小数据学名称为“分片”( Shard)。拆开之后每个分片里的数据就没那么多了然后让查找尽量落在某一个分片上以此来提升查找性能。 存档历史订单数据 订单数据一般保存在 MySQL 的订单表里说到拆分 MySQL 的表前面我们不是已经用到了“分库分表”吗其实分库分表很多的时候并不是首选的方案应该先考虑归档历史数据。以京东为例可以看到在“我的订单”中查询时分为了近三个月订单、今年内订单、2021 年订单、2020 年订单等等这就是典型的将订单数据归档处理。所谓归档也是一种拆分数据的策略。简单地说就是把大量的历史订单移到另外一张历史订单表或数据存储中。为什这么做呢订单数据有个特点具备时间属性的并且随着系统的运行数据累计增长越来越多。但其实订单数据在使用上有个特点最近的数据使用最频繁超过一定时间的数据很少使用这被称之为热尾效应。因为新数据只占数据息量中很少的一部分所以把新老数据分开之后新数据的数据量就少很多查询速度也会因此快很多。虽然与之前的总量相比老数据没有减少太多但是因为老数据很少会被访问到所以即使慢一点儿也不会有太大的问题而且还可以使用其他的存储系统提升查询速度。这样拆分数据的另外一个好处是拆分订单时系统需要改动的代码非常少。对订单表的大部分操作都是在订单完成之前执行的这些业务逻辑都是完全不用修改的。即使是像退货退款这类订单完成之后的操作也是有时限的这些业务逻辑也不需要修改还是按照之前那样操作订单即可。基本上只有查询统计类的功能会查到历史订单这些都需要稍微做些调整。按照查询条件中的时间范围选择去订单表还是历史订单中查询就可以了。很多大型互联网电商在逐步发展壮大的过程中长达数年的时间采用的都是这种订单拆分的方案正如我们前面看到的京东就是如此。 商城历史订单服务的实现 既然是历史订单的归档归档到哪里去呢我们可以归档到另外的 MySQL 数据库也可以归档到另外的存储系统这个看自己的业务需求即可比如归档到 MongoDB 数据库。对于数据的迁移归档我们总是在 MySQL 中保留 3 个月的订单数据超过三个月的数据则迁出。前面我们说过预估每月订单 2000W一张订单下的商品平均为 10 个如果只保留 3 个月的数据则订单详情数为 6 亿分布到 32 个表中每个表容纳的记录数刚好在 2000W 左右这也是为什么前面的分库分表将订单表设定为 32 个的原因。 在进行数据迁移的过程需要注意以下两点 分布式事务 考察迁移的过程我们是逐表批次删除对于每张订单表先从 MySQL 获得指定批量的数据写入 MongoDB再从 MySQL 中删除已写入 MongoDB 的部分这里存在着一个多源的数据操作为了保证数据的一致性看起来似乎需要分布式事务。但是其实这里并不需要分布式事务解决的关键在于写入订单数据到 MongoDB 时我们要记住同时写入当前迁入数据的最大订单 ID让这两个操作执行在同一个事务之中。这样在 MySQL 执行数据迁移时总是去 MongoDB 中获得上次处理的最大 OrderId作为本次迁移的查询起始 ID当然数据写入 MongoDB 后还要记得删除 MySQL 中对应的数据。在这个过程中我们需要注意的问题是尽量不要影响线上的业务。迁移如此大量的数据或多或少都会影响数据库的性能因此应该尽量选择在闲时迁移而且每次数据库操作的记录数不宜太多。按照一般的经验对 MySQL 的操作的记录条数每次控制在 10000 以下是比较合适在我们的系统中缺省是 2000 条。更重要的是迁移之前一定要做好备份这样的话即使不小心误操作了也能用备份来恢复。 如何批量删除大量数据 在迁移历史订单数据的过程中还有一个很重要的细节间题如何从订单表中删除已经迁走的历史订单数据虽然我们是按时间迁出订单表中的数据但是删除最好还是按 ID 来删除并且同样要控制住每次删除的记录条数太大的数量容易遇到错误。这样每次删除的时候由于条件变成了主键比较而在 MySQL 的 InnoDB 存储引擎中表数据结构就是按照主键组织的一棵 B 树同时 B 树本身就是有序的因此优化后不仅查找变得非常快而且也不需要再进行额外的排序操作了。为什么要加一个排序的操作呢因为按 ID 排序后每批删除的记录基本上都是 ID 连续的一批记录由于 B 树的有序性这些 ID 相近的记录在磁盘的物理文件上大致也是存放在一起的这样删除效率会比较高也便于 MySQL 回收页。关于大批量删除数据还有一个点需要注意一下执行删除语句后最好能停顿一小会因为删除后肯定会牵涉到大量的 B 树页分裂和合并这个时候 MySQL 的本身的负载就不小了停顿一小会可以让 MySQL 的负载更加均衡。
http://www.zqtcl.cn/news/825618/

相关文章:

  • 建站赔补用python做网站优点
  • 个人免费域名空间建站淄博网络公司全网推广
  • 企业信息年报系统南昌做seo的公司
  • 门户网站开发模板动漫设计与制作设计课程
  • vip网站怎么做有关设计的网站
  • wordpress网站第一次打开慢那个网站做视频没有水印
  • 做外贸英语要什么网站网站整体设计风格
  • 高端网站开发哪里好2022最新新闻素材摘抄
  • 网站建设实训个人深圳做营销网站的公司哪家好
  • 广州seo网站策划wordpress关闭主题提示
  • 做门票售卖网站怎么制作自己的水印
  • 网站绑定两个域名怎么做跳转asp 网站后台
  • 百度网站怎么做的赚钱吗郑州资助app下载
  • 成都成华区网站建设天津网站优
  • 大朗网站制作商城网站建设相关费用
  • 付费阅读网站代码搜索引擎推广方式有哪些
  • 企业网站搭建介绍一个电影的网站模板下载
  • wordpress网站插件下载郑州专业网站制作
  • 佛山南海区建网站的公司dw怎么做购物网站
  • 杭州网站关键词排名优化响应式网站好还是自适应网站好
  • 潍坊作风建设网站什么是网站建设技术
  • 网站后台图片不显示东莞市企业招聘信息网
  • 网站发布平台商业网站的网址
  • 免费的培训网站建设门户网站建设管理工作方案
  • 企业网站建设实验感想企业网络推广哪家公司好
  • 网站建设和维护视频如何入侵网站服务器
  • 怎样建设网站空间成都网站设公司
  • 百度文库账号登录入口百度seo规则最新
  • 服务器可以自己的网站吗网络营销策划与创意
  • 广州市招投标网站个人网站可以做论坛