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

建设局网站seo优化网站优化

建设局网站,seo优化网站优化,h5响应式网站上海,做网站分层技术极客时间《后端存储实战课》阅读笔记 01 | 创建和更新订单时#xff0c;如何保证数据准确无误#xff1f; ‍ 插入防重复#xff1a;预生成订单号 在插入数据#xff0c;尤其是新建订单的时候#xff0c;需要注意网络波动或者用户手抖等导致的重复订单问题#xff0c…极客时间《后端存储实战课》阅读笔记 01 | 创建和更新订单时如何保证数据准确无误 ‍ 插入防重复预生成订单号 在插入数据尤其是新建订单的时候需要注意网络波动或者用户手抖等导致的重复订单问题需要注意的是这并不能完全依靠前端防抖来实现。1是依赖前端并不可靠2.是在后端比如说网关层可能就有重试的机制。 一个比较通用的解决方案是让订单系统提供一个接口不需要任何入参返回一个全局唯一的订单号也称为预生成订单号。 在创建订单号的时候前端带着预生成的订单号去生成订单这样就可以防止因为网络抖动或者用户手抖重复创建订单了。 而带着预生成的订单号怎么防止重复下单就比较简单了一般是订单号作为主键利用主键唯一来约束即可。当然网络抖动等导致第二单重复创建的时候用户友好考虑虽然插入失败但是可以直接给用户返回创单成功而不是失败。 考虑到后端一般以订单号为主键插入数据库考虑到插入性能因此生成的全局唯一的订单号一般是符合主键约束的单增的数字。 更新信息防ABA问题版本号机制 举一个例子说明ABA更新的问题用户修改订单的备注当前是555用户修改成666点击保存但是发现输入错误又改成888点击保存发现成功了就退出了。 最后这个备注是多少呢既又可能是666也有可能是888. 对于后端来说更新成666和更新成888就是两次更新请求考虑到网络抖动和服务处理速度实际到数据库执行来说可能出现更新成666了但是响应丢失了。更新成888成功响应成功。第一次更新666的服务端发现超时尝试重试成功。 因此会出现666-》888-》666的情况就是ABA问题。解决ABA问题也有一个比较他同识的方法版本号机制,具体来说增加一列版本号每次查询都返回其他信息和版本号每次更新的时候都需要带着old version number。 这样在更新的时候就可以写出类似的sql UPDATE orders set tracking_number 666, version version 1 WHERE version 8;‍ 如果版本号不符合要求自然无法更新成功。通过这样的机制就可以保证当前的更新的时候看到的信息一定是最新的信息。 对于之前的例子第二次更新888和第三次重复更新666都会失败成功解决ABA问题。 这样的版本号也可以同时解决这样的问题a设备拿着很久之前打开的网页去更新信息然后发现信息对不上之类的问题。 ‍ 02 | 流量大、数据多的商品详情页系统该如何设计 商品详情页的特点如下所以说详情页是一个需要好好设计的页面。 访问次数多页面内容多内容又多形式又杂。包括文字、图片、视频各种。 详情页这种典型的get请求页面需要做好的就是存储在考虑缓存之前我们需要先考虑非缓存的存储。 详情页内容形式比较杂因此需要针对不同的内容进行不同形式的存储。 详情页内容主要包括商品基本信息颜色、大小等、价格信息、参数信息、文字介绍、视频图片等。而评价、商家信息、其它商品等电商中其他系统负责的部分本次不讨论。 按照适合存储的介质可以将详情页的内容如下分类 文本信息 方便结构化的比如所有商品基本都有的大小、颜色、重量等考虑使用MySQL等进行存储不方便结构化的某些商品特有的比如防晒霜的防护指数、酒精的浓度等某些商品才特有这种商品分类比较少的时候可以考虑MySQL等进行结构化存储但是数量多了建议使用MongoDB。其基于BJSON存储不需要数据列相同。 图片和视频图片和视频由于占用存储空间比较大一般的存储方式都是在数据库中只保存图片视频的 ID 或者 URL实际的图片视频以文件的方式单独存储。而文件一般使用对象存储服务进行存储。 其它优化 缓存这个不必多说当然还需要注意缓存一致性问题~网页静态化对于长期不变的网页信息比如说商品介绍为了减少服务器压力可以考虑将网页部分直接静态化即就把这个页面事先生成好保存成一个静态的 HTML访问商详页的时候直接返回这个 HTML毕竟NGINX能抗住的并发和后端服务能抗住的并发不在一个数量级。对于价格之类的动态信息在访问的时候再实时查询获取。 MongoDB 最大的特点就是它的“表结构”是不需要事先定义的其实在 MongoDB 中根本没有表结构。由于没有表结构它支持你把任意数据都放在同一张表里你甚至可以在一张表里保存商品数据、订单数据、物流信息等这些结构完全不同的数据。并且还能支持按照数据的某个字段进行查询。 它是怎么做到的呢MongoDB 中的每一行数据在存储层就是简单地被转化成 BSON 格式后存起来这个 BSON 就是一种更紧凑的 JSON。所以即使在同一张表里面它每一行数据的结构都可以是不一样的。当然这样的灵活性也是有代价的MongoDB 不支持 SQL多表联查和复杂事务比较孱弱不太适合存储一般的数据。 03 | 复杂而又重要的购物车系统应该如何设计 一个很有意思的问题是对于购物车系统是否可以通过MySQL上增加Redis缓存来提升性能 如果随便想一想那么很可能得出错误的答案可以。实际上缓存优化的是读性能因此读多写少的场景才适合用缓存。我们考虑一下购物车这个场景每个用户访问自己购物车的时候大概率是要下单或者修改购物车所以缓存的优化其实很有限反而大概率因为引入缓存带来了维护缓存的压力。 评论区读多写少用缓存写多读少用MQ。对于前者前提是读场景频繁且能具备较高的命中率。用户购物车数据不符合该场景。 04 | 事务账户余额总是对不上账怎么办 订单类似的系统从业务角度来说不太需要记录全部历史记录。但是为了「对账」在每一次变动的时候都需要额外记录一个变动信息流水信息而且变动信息最好是只能新增不能删除或者改动。比如取消或者修改都是新增一行变动信息记录下来操作被取消或者修改。 05 | 分布式事务如何保证多个系统间的数据是一致的 2PC、3PC、TCC、SAGA 和本地事务表等等。 需求对于A、B两个服务实现分布式事务 。 2PC需要强一致、并且并发量不大的场景 核心原理引入一个事务协调者的概念在实际实现中事务协调者一般不会是一个单独的服务就本地进程中运行即可将分布式事务划分为两个阶段准备阶段和提交阶段。 准备阶段服务A和服务B都实现对应逻辑并写入数据但是注意对应到数据库层面系统A和系统B是开启事务但是不提交的。提交阶段服务A和服务B都提交事务。 可能出现数据不一致的情况 准备阶段无论哪个系统发生异常由于事务没有提交要么就超时、要么就回滚总之没有数据不一致的情况。 提交阶段只要进入提交阶段就属于开工没有回头箭只能继续执行了。如果因为网络超时那么重试即可成功。但是如果服务A和服务B本身宕机或者系统底层数据库宕机那么确实会出现数据不一致的情况。但是实际中因为提交阶段的执行时间很短不太容易出现问题。 2PC适合的场景强一致并发量不大。2PC可以保证数据强一致但整个事务的执行过程需要阻塞服务端的线程和数据库的会话所以2PC 在并发场景下的性能不会很高。并且协调者是一个单点一旦过程中协调者宕机就会导致订单库或者促销库的事务会话一直卡在等待提交阶段直到事务超时自动回滚。 卡住的这段时间内数据库有可能会锁住一些数据服务中会卡住一个数据库连接和线程这些都会造成系统性能严重下降甚至整个服务被卡住。 todo 待看下MySQL自身的两阶段提交的原理~感觉和2PC一模一样 本地事务表分布式最终一致性 核心原理思路将分布式事务转化成本地事务表中记录消息的本地事务。具体做法服务A和服务B的分布式事务可以转变成服务A开启事务后执行操作并在本地事务中记录服务B需要的操作然后就可以直接提交了。服务A或者其他服务异步的根据这个消息去执行服务B的操作再更新事务表中数据状态即可。 可能出现数据不一致的情况 异步的操作服务B的时候因为这一步的异步操作可能会失败重试即可。只要不是一直不断失败。同时在服务B操作完成之前会存在暂时的数据不一致。 本地事务表适合的场景 异步执行的那部分操作不能有依赖的资源。比如说我们下单的时候除了要清空购物车以外还需要锁定库存就不适合本地事务表了因为这样第二步的异步操作会一直失败导致数据不一致最终一致性允许出现暂时的数据不一致。 此外事务消息本质上和本地事务表是一个思路在使用上还更加简单 TCC 2025年06月09日00:45:56 待开始~ TCC 方案该方案天生适合用于需要强隔离性的分布式事务中。 核心思想是针对每个操作都要注册一个与其对应的确认Try和补偿Cancel 。如同名字TCC 整个事务流程由三个阶段组成 Try 阶段尝试执行完成所有业务检查一致性, 预留必须业务资源准隔离性。Confirm 阶段如果所有分支的Try都成功了则走到Confirm阶段。Confirm真正执行业务不作任何业务检查只使用 Try 阶段预留的业务资源。Cancel 阶段如果所有分支的Try有一个失败了则走到Cancel阶段。Cancel释放 Try 阶段预留的业务资源。 按照 TCC 的协议Confirm 和 Cancel 是只返回成功不会返回失败。如果由于网络问题或者服务器临时故障那么事务管理器会进行重试最终成功。 以一个下单服务为例说明 TCC 事务处理流。该下单服务由两个系统操作完成订单系统 X、资金账户系统 Y。 Try 操作 : try X 下单系统创建待支付订单。try Y 自己账户系统冻结订单金额 100 元。Confirm 操作 confirm X 订单更新为支付成功。confirm Y 扣减账户系统 100 元。Cancel 操作 Cancel X 订单异常资金退回Cancel Y 扣款异常订单支付失败 由上述操作过程可见TCC 其实有点类似 2PC 的准备阶段和提交阶段但 TCC 是位于用户代码层面而不是在基础设施层面这为它的实现带来了较高的灵活性可以根据需要设计资源锁定的粒度不会导致数据库层面的阻塞。但是相对而言其代码复杂度应该比2PC更高毕竟2PC是数据库的回滚而TCC的Cancel需要业务上去回滚。 ‍ SAGA SAGA适用于长时间多流程的分布式事务大致的思路是把一个大事务分解成多个可交错运行的子事务集合并在每个子事务中引入补偿操作。 在 SAGA 模式下分布式事务内有多个参与者每一个参与者都是一个冲正补偿服务需要用户根据业务场景实现其正向操作和逆向回滚操作。 SAGA 由两部分操作组成。 一部分是将大事务 T 拆分成若干小事务命名为 T1T2Tn。每个子事务被应被视为原子行为如果分布式事务 T 能够正常提交那么它对数据的影响最终一致性就应该与连续按顺序成功提交子事务 Ti 等价。 另一部分是为每个子事务设计对应的补偿动作命名为 C1C2Cn。Ti 与 Ci 满足以下条件 Ti 与 Ci 具备幂等性。Ci 必须能成功提交即不考虑 Ci 的失败回滚情况如果出现失败持续重试直至成功或者被人工介入为止。 如果 T1 到 Tn 均执行成功那么整个事务顺利完成否则要根据下面两种恢复策略之一进行恢复。 正向操作Forward Recovery 如果 Ti 提交失败则一直对 Ti 进行重试直至成功为止最大努力交付。这种恢复方式不需要进行补偿适用于事务最终都要执行成功的情况譬如订单服务中银行已经扣款那么就一定要发货。逆向回滚Backward Recovery 如果 Ti 提交失败则执行对应的补偿 Ci直至恢复到 Ti 之前的状态这里要求 Ci 必须成功持续重试最大努力交付。 由于存在重试的机制这也是为什么Ti需要具备幂等性。 ​ 相比于TCCSAGA更适合长时间执行保证最终一致性的事务且不需要提前锁定资源的操作。 不需要提前锁定资源这一点虽然简单但是失败事务失败时不一定是一件好事因为相比于TCC的提前占据资源SAGA是实际执行事务然后回测业务上可能更加复杂。谁来执行事务TCC是由事务发起方调度而SAGA可以由服务发起方来调度也可以没有中心调度节点比如Ti执行的完毕发送mq消息其它节点订阅消息进行后续操作。 “Saga”一词源自古诺尔斯语Old Norse原指冰岛和中世纪北欧流传的长篇英雄传说或历史叙事如《尼雅尔萨迦》特点是故事跨度长、情节复杂且分阶段展开。这一概念被借用到分布式事务领域是因为SAGA事务模式同样将一个长时间运行的大事务Long Lived Transaction分解为多个有序的子事务每个子事务像“故事章节”一样逐步推进最终完成整体事务的叙述。 事务消息 见消息队列实现分布式事务|事务消息1其本质和事务消息相同只是介质不同。 ‍ ‍ ‍ 参考 5.3.2 TCC | 深入架构原理与实践 ‍ 06 | 如何用Elasticsearch构建商品搜索系统 在 ES 里面数据的逻辑结构类似于 MongoDB每条数据称为一个 DOCUMENT简称 DOC。DOC 就是一个 JSON 对象DOC 中的每个 JSON 字段在 ES 中称为 FIELD把一组具有相同字段的 DOC 存放在一起存放它们的逻辑容器叫 INDEX这些 DOC 的 JSON 结构称为 MAPPING。 MySQL与Elasticsearch的名词对应关系 因为用户每输入一个字都可能会发请求查询搜索框中的搜索推荐。所以搜索推荐的请求量远高于搜索框中的搜索。es针对这种情况提供了suggestion api并提供的专门的数据结构应对搜索推荐性能高于match但它应用起来也有局限性就是只能做前缀匹配。再结合pinyin分词器可以做到输入拼音字母就提示中文。如果想做非前缀匹配可以考虑Ngram。不过Ngram有些复杂需要开发者自定义分析器。比如有个网址www.geekbang.com用户可能记不清具体网址了只记得网址中有2个e此时用户输入ee两个字母也是可以在搜索框提示出这个网址的。以上是我在工作中针对前缀搜索推荐和非前缀搜索推荐的实现方案。 ‍ ES最不擅长的就是深分页了……所以据我所知没什么好的解决方案。 ‍ ‍ 07MySQL HA如何将“删库跑路”的损失降到最低 原理 一般是两个措施结合使用来保证数据库可以 定时全量备份使用binlog回放 定时全量备份的目的是加快数据回放到某一个时间点。虽然binlog可以完成这一步但是总不能从建表开始回放吧这样的话无论是耗时还是binlog有没有保存这么久都是问题。 使用binlog回放的目的是精确指定时间因为「全量备份」的频次一般来说最高是天级别还需要binlog来指定回放时间段。在回放 Binlog 的时候指定的起始时间可以比全量备份的时间稍微提前一点儿确保全量备份之后的所有操作都在恢复的 Binlog 范围内这样可以保证恢复的数据的完整性。且binlog的回放是幂等的在binlog的格式是row格式的前提下大家一般也都是这么设置的具体格式区别见为啥用binlog格式为row来解决问题或者说binlog的格式为statement会有什么问题首先看下两种不同的binlog的格式有什么区别然后这个问题就可以解决了。 statemen...2 操作 全量备份数据库test $mysqldump -uroot -p test test.sql备份出来的文件就是一个 SQL 文件如何执行 $mysql -uroot test test.sqlshow variables like ‘%log_bin%’”命令确认一下是否开启了 Binlog 功能 mysql show variables like %log_bin%; -------------------------------------------------------------------- | Variable_name | Value | -------------------------------------------------------------------- | log_bin | ON | | log_bin_basename | /usr/local/var/mysql/binlog | -------------------------------------------------------------------- mysql show master status; ---------------------------------------------------------------------------- | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | ---------------------------------------------------------------------------- | binlog.000001 | 18745 | | | | ---------------------------------------------------------------------------- ‍ Binlog 恢复数据在回放 Binlog 的时候指定的起始时间可以比全量备份的时间稍微提前一点儿确保全量备份之后的所有操作都在恢复的 Binlog 范围内这样可以保证恢复的数据的完整性。 $mysqlbinlog --start-datetime 2020-02-20 00:00:00 --stop-datetime 2020-02-20 15:09:00 /usr/local/var/mysql/binlog.000001 | mysql -uroot高可用 08 | 一个几乎每个系统必踩的坑儿访问数据库超时 2025年06月11日14:00:23 待开始 todo 需要知道的一点是当数据库非常忙的时候它执行任何一个 SQL 都很慢。所以并不是说慢 SQL 日志中记录的这些慢 SQL 都是有问题的 SQL。大部分情况下导致问题的 SQL 只是其中的一条或者几条。不能简单地依据执行次数和执行时长进行判断但是单次执行时间特别长的 SQL仍然是应该重点排查的对象。 ‍ ‍ 10 | 走进黑盒SQL是如何在数据库中执行的 一条 SQL 在数据库中执行首先 SQL 经过语法解析成 AST然后 AST 转换为逻辑执行计划逻辑执行计划经过优化后转换为物理执行计划再经过物理执行计划优化后按照优化后的物理执行计划执行完成数据的查询。几乎所有的数据库都是由执行器和存储引擎两部分组成执行器负责执行计算存储引擎负责保存数据。 ‍ 11 | MySQL如何应对高并发一使用缓存保护MySQL Cache Aside 模式和上面的 Read/Write Through 模式非常像它们处理读请求的逻辑是完全一样的唯一的一个小差别就是Cache Aside 模式在更新数据的时候并不去尝试更新缓存而是去删除缓存。 实战注意缓存穿透可以考虑预热缓存两种方案少量放量真实流量预热或者主动预热缓存。 ‍ 12 | MySQL如何应对高并发二读写分离 如果你配置了多个从库推荐你使用“HAProxyKeepalived”这对儿经典的组合来给所有的从节点做一个高可用负载均衡方案既可以避免某个从节点宕机导致业务可用率降低也方便你后续随时扩容从库的实例数量。因为 HAProxy 可以做 L4 层代理也就是说它转发的是 TCP 请求所以用“HAProxyKeepalived”代理 MySQL 请求在部署和配置上也没什么特殊的地方正常配置和部署就可以了。 组件作用组合后的效果HAProxy负载均衡、流量分发多节点后端服务的流量管理Keepalived高可用、提供VIP 、故障切换HAProxy 节点的高可用性保障 客户端 - [VIP] - HAProxy 主节点正常 ↘ HAProxy 从节点备用/热备 ↘ 后端服务器集群豆包这种组合在云原生时代仍是经典方案之一虽然现在也有 Kubernetes Ingress etcd 等替代方案但其轻量、稳定、低延迟的特点在传统架构中依然不可替代。 13 | MySQL主从数据库同步是如何实现的 ‍ MySQL 从 5.7 版本开始增加一种半同步复制Semisynchronous Replication的方式。异步复制是事务线程完全不等复制响应同步复制是事务线程要等待所有的复制响应半同步复制介于二者之间事务线程不用等着所有的复制成功响应只要一部分复制响应回来之后就可以给客户端返回了。 比如说一主二从的集群配置成半同步复制只要数据成功复制到任意一个从库上主库的事务线程就直接返回了。这种半同步复制的方式它兼顾了异步复制和同步复制的优点。如果主库宕机至少还有一个从库有最新的数据不存在丢数据的风险。并且半同步复制的性能也还凑合也能提供高可用保证从库宕机也不会影响主库提供服务。所以半同步复制这种折中的复制方式也是一种不错的选择。 ‍ “rpl_semi_sync_master_wait_slave_count”含义是“至少等待数据复制到几个从节点再返回”。这个数量配置的越大丢数据的风险越小但是集群的性能和可用性就越差。最大可以配置成和从节点的数量一样这样就变成了同步复制。 “rpl_semi_sync_master_wait_point”这个参数控制主库执行事务的线程是在提交事务之前AFTER_SYNC等待复制还是在提交事务之后AFTER_COMMIT等待复制。默认是 AFTER_SYNC也就是先等待复制再提交事务这样完全不会丢数据。AFTER_COMMIT 具有更好的性能不会长时间锁表但还是存在宕机丢数据的风险。 ‍ 复制状态机所有分布式存储都是这么复制数据的 这种基于“快照 操作日志”的方法不是 MySQL 特有的。 Redis Cluster 中它的全量备份称为 Snapshot操作日志叫 backlog它的主从复制方式几乎和 MySQL 是一模一样的。 Elasticsearch它是一个内存数据库读写都在内存中那它是怎么保证数据可靠性的呢对它用的是 translog它备份和恢复数据的原理和实现方式也是完全一样的。这些什么什么 log都是不同的马甲儿而已几乎所有的存储系统和数据库都是用这一套方法来解决备份恢复和数据复制问题的。 ‍ ‍ ‍ 14 | 订单数据越来越多数据库越来越慢该怎么办 在分库分表之前还有一个首选方案归档历史数据。这么做是因为订单这样的数据具有很强的热近效应历史数据无论是查询还是修改都非常少。 而且归档相比于分库分表还有一个优势对于历史代码改动小。当然如果最开始就做了分库分表的设计自然也就不存在归档这一说法了 使用APP的时候经常可以看到点击查看三个月之前的订单的按钮其实就是因为「归档历史数据」设计引发的。 迁移大概流程 在迁移完成之后我们就需要考虑删除热库中的订单数据这一步了。 如何删除大批量的数据两个注意点分批删除 尽量使用主键删除。分批删除即使用limit xxx​循环删除分批删除好处太多避免MySQL压力减少可能的锁表时间如果删除where没有命中索引是可能会锁表的主键删除算是进一步优化吧。归档场景一般按照时间归档可以找到归档时间中最大的主键id因为id递增所以可以把删除条件换为id{max id}​删除后表大小为什么还没减小简短来说mysql删除表只是将空间标记为无效并没有实际释放磁盘空间释放空间需要执行Alter table {table_name} engine innodb​相关操作具体13 为什么表数据删掉一半表文件大小不变3 无端联想limit非常有用在执行ddl的时候如果是update或delete操作需要强制写上limit 1​。 ‍ 15 | MySQL存储海量数据的最后一招分库分表 大厂在线交易这部分的业务比如说订单、支付相关的系统还是舍弃不了 MySQL原因是只有 MySQL 这类关系型数据库才能提供金融级的事务保证。 我们之前也讲过分布式事务那些新的分布式数据库提供的所谓的分布式事务多少都有点儿残血目前还达不到这些交易类系统对数据一致性的要求。 ‍ 在考虑到底是分库还是分表之前需要先明确一个原则那就是能不拆就不拆能少拆不多拆。原因也很简单你把数据拆分得越散开发和维护起来就越麻烦系统出问题的概率就越大。 分库分表之后对查询来说也是有很多限制的比如说查询如果没有带Sharging Key分表列那么就会查询所有的分表再聚合结果查询性能损耗极大。 分库分表的目的是解决高并发、查询数据量大的问题。简单地说数据量大就分表并发高就分库。 ‍ 选择合适 Sharding Key 和分片算法非常重要直接影响了分库分表的效果。此外千万需要考虑热点问题 Sharding Key 如何选择 Sharding Key 选择 Sharding Key 最重要的参考因素是我们的业务是如何访问数据的。 比如说 如果我们业务最常的方式是根据订单ID作为查询条件那么就可以以订单ID为Sharding Key。 但以订单ID为Sharding Key那么这时候用户想查询自己的订单就没法使用Sharding Key了因此可以考虑 1.让用户ID成为订单的一部分比如生成订单的时候最后几位为用户ID 2.将系统同步到其他存储比如ES来进行查询 需要注意的是将系统同步到其他存储比如ES来进行查询如果需要更详细的信息再进一步根据订单ID进MySQL查询是一个常用的做法。 2更加常用如果又有其他查询需要比如查询某个商户下的订单某个城市下产生的订单「1」是无法在系统设计初期完全考虑到的。 对于热点问题设计的时候时刻保持注意注意即可。这里介绍解决热点问题的一个冷门的方法手动创建分片映射​ 分片算法 分片算法如何不合理的话会产生热点问题 一般有三种分片方式 范围分片容易产生热点问题但对查询更友好适合并发量不大的场景 哈希分片比较容易把数据和查询均匀地分布到所有分片中 查表法更灵活但性能稍差。 一般实际运用中采用哈希分片比较多而考虑到性能、处理方便一般会直接使用sharding key % 分片数量 ​的方式来分片。 实际上sharding key % 分片数量​的方式并没有严谨的打散分片还是有可能会产生热点问题。但是其好处也是很明显的处理快速、不会出错、排查问题需要手动查询的时候也很方便所以还是需要综合考虑数据热点的可能性。 17 | 大厂都是怎么做MySQL to Redis同步的?||缓存一致性 在【wip】缓存一致性保证4中针对缓存一致性的保障针对先改后改和先改后删方案都分别提出了并发限制和lease的机制来保证缓存一致性。 这里提出了另一种解题的思路 使用mq或者Canal订阅mysql的binlog变动来更新缓存具体来说通过mq或者Canal订阅binlog变动然后消费者根据binlog去更新缓存。 这样做的方式类似于先改后改不过对缓存的“最终一致性”有更强的保证。 好处保证缓存一定能更新成功原方案极小可能服务器宕机导致数据不一致如何配合上顺序消费保证可以保证缓存和数据库的最终一致性 坏处数据一致性的延迟略高毕竟中间又多了两步需要考虑一旦出现不同步问题时的降级或补偿方案。 18 | 分布式存储你知道对象存储是如何保存图片文件的吗 对象存储是最简单的分布式存储系统主要由数据节点集群、元数据集群和网关集群或者客户端三部分构成。数据节点集群负责保存对象数据元数据集群负责保存集群的元数据网关集群和客户端对外提供简单的访问 API对内访问元数据和数据节点读写数据。 为了便于维护和管理大的对象被拆分为若干固定大小的块儿块儿又被封装到容器也就分片中每个容器有一主 N 从多个副本这些副本再被分散到集群的数据节点上保存。 对象存储虽然简单但是它具备一个分布式存储系统的全部特征。所有分布式存储系统共通的一些特性对象存储也都具备比如说数据如何分片如何通过多副本保证数据可靠性如何在多个副本间复制数据确保数据一致性等等。 ‍ ​ ‍ 20 | 如何在不停机的情况下安全地更换数据库 我把这个复杂的切换过程的要点按照顺序总结成下面这个列表供你参考 上线同步程序从旧库中复制数据到新库中并实时保持同步一般可以用订阅binlog实现上线双写订单服务只读写旧库开启双写同时停止同步程序 开启对比和补偿程序确保新旧数据库数据完全一样逐步切量读请求到新库上下线对比补偿程序关闭双写读写都切换到新库上下线旧库和订单服务的双写功能。 其中值得注意的地方 对比补偿程序存在的意义启动双写和停止同步程序之间是无法做到无缝这期间数据会存在一些不一致切换过程中可能由于代码逻辑问题或者网络超时等问题导致数据不一致。 对比补偿程序没有一个统一严谨的方式只能根据业务场景去分析比如订单完成状态的订单是不修改的因此可以按照订单维度去同步等 关闭双写之前都是可以无损回滚的关闭双写之后无法无损的回滚了 ‍ 23 | MySQL经常遇到的高可用、分片问题NewSQL是如何解决的 对于CockroachDB这种new SQL其只带云原生属性天生就是为了分布式集群设计且可以说提供了MySQL这样的ACID保证值得关注。 其架构 可以从架构图中看出其支持分布式SQL的能力来源于其底层的分布式KV数据库底座借助于分布式KV数据库的能力其很容易达到分布式这一目的。 但是也是因此其对于ACID的保证不和MySQL完全一样其有两种事务的隔离级别SI和SSI ​ 先从SI开始SI的隔离是基于快照的看起来其不会有脏读、不可重复读和幻读的问题但是其有写倾斜Write Skew的问题。 写倾斜Write Skew中 “倾斜” 在此处是一个数学/物理隐喻 正常情况事务并发修改时数据状态应沿正确方向演变如账户总和保持正值异常情况多个事务的独立操作产生“合力偏移”使数据状态滑向错误方向如总和意外变负 CockroachDB 的 写倾斜Write Skew 是一种特定类型的并发事务异常指多个事务同时读取同一数据集并根据读取结果独立修改不同数据项最终导致违反全局业务逻辑约束的现象。其核心特点是事务间无直接数据冲突但组合结果不正确。 一个经典案例是主副卡转账问题 -- 事务A修改主卡 BEGIN; SELECT * FROM accounts WHERE type IN (主卡,副卡); -- 读数据集 UPDATE accounts SET balance balance - 200 WHERE id 主卡; COMMIT;-- 事务B修改副卡并发执行 BEGIN; SELECT * FROM accounts WHERE type IN (主卡,副卡); -- 读相同数据集 UPDATE accounts SET balance balance - 200 WHERE id 副卡; COMMIT;核心矛盾 表面无冲突 事务A修改主卡​事务B修改副卡​ → 无数据行重叠传统行锁如SELECT FOR UPDATE​只能锁定具体行 → 锁不住“逻辑约束” 真实冲突点 业务要求主卡副卡总和 0​ → 这是个跨行的逻辑约束事务各自检查时总和为1500但未考虑对方修改 → 约束被绕过 CockroachDB通过 Serializable Snapshot Isolation (SSI) 实现 “约束感知”的冲突检测 事务读取时记录 逻辑范围如WHERE type IN (主卡,副卡)​ 提交时检查是否有其他事务修改过此范围内的数据 ✅ 事务A提交时发现事务B修改了“副卡”在读取范围内→ 中止✅ 事务B提交时发现事务A修改了“主卡” → 中止 最终只有先提交的事务成功另一个重试后基于新数据计算 相当于自动为逻辑约束加锁而非物理行锁 消息队列实现分布式事务|事务消息 在实际应用中比较常见的分布式事务实现有 2PCTwo-phase Commit也叫二阶段提交、TCC(Try-Confirm-Cancel) 和事务消息。每一种实现都有其特定的使用场景也有各自的问题都不是完美的解决方案。这里只讨论「事务消息」的实现。 事务消息的核心原理就是先发送给mq一个消息然后执行事务通过执行事务的结果决定最开始的那条消息是否提交或者是回滚。流程如下图所示 ‍ 对于第四步提交事务消息时失败了的情况RocketMq和Kafka有不同的处理 Kafka 的解决方案比较简单粗暴直接抛出异常让用户自行处理。我们可以在业务代码中反复重试提交直到提交成功或者删除之前创建的订单进行补偿。RocketMQ 则提供了一种MQ反查机制即Broker 没有收到提交或者回滚的请求Broker 会定期去 Producer 上反查这个事务对应的本地事务的状态然后根据反查结果决定提交或者回滚这个事务。 因此为了支持MQ的反查业务方需要实现一个供Broker反查的接口。 ↩ 为啥用binlog格式为row来解决问题或者说binlog的格式为statement会有什么问题 首先看下两种不同的binlog的格式有什么区别然后这个问题就可以解决了。 statement记录SQL语句row记录具体的行操作逻辑日志。row不会存在问题可以肯定的那么statement为什么会存在问题因为statement记录的是实际SQL的输入顺序从库就会按这个执行而这与实际的插入顺序可能不同在并发批量插入、并发的时候可能存在问题实际上可以见 小林coding中对auto-inc锁为轻量级版本binlog为statement会存在问题。 ↩ 13 为什么表数据删掉一半表文件大小不变 根本原因MySQL的删除的标记删除覆盖。可能原因数据空洞数据页分裂导致文件占用过大。 根据个人理解精简。 要回答这个问题或其他类似问题我们就必须弄懂两个前置问题 MySQL如何删除数据行/数据页MySQL的数据空洞 MySQL如何删除数据行/数据页 MySQL删除数据行、页的流程就是打上删除标记和自己操作MySQL数据很像后面需要再用到这个位置的话直接覆盖。 举个例子下面图片中如果R4删除了就被打上了标记那么如果插入(300,600)的数据就可以复用R4现在的位置。需要注意的是如果插入的数据300或600就不能复用现在的位置。 删除数据页和数据行类似就是打上标记不同的是对于数据行只有符合范围的数据才能复用如上面所示而对于数据页来说任何新的数据页都可以复用。 ​ MySQL的数据空洞: 在很多情况下MySQL的数据页中的某些空间会有空洞而浪费 【插入】和【删除】操作均有可能会导致数据空洞具体来说删除造成空洞就如上面所示插入造成空洞的原因是插入导致数据页分裂 。 这样删除数据后表大小没有减少就找到原因了是因为 MySQL的删除是标记的方式 加上 数据空洞现象。 引申一下如何 解决数据空洞呢 或者说 如何减小表空间呢 答案是重建表。 试想一下如果你现在有一个表 A需要做空间收缩为了把表中存在的空洞去掉业务可以怎么做呢 你可以新建一个与表 A 结构相同的表 B然后按照主键 ID 递增的顺序把数据一行一行地从表 A 里读出来再插入到表 B 中。 由于表 B 是新建的表所以表 A 主键索引上的空洞在表 B 中就都不存在了。显然地表 B 的主键索引更紧凑数据页的利用率也更高。如果我们把表 B 作为临时表数据从表 A 导入表 B 的操作完成后用表 B 替换 A从效果上看就起到了收缩表 A 空间的作用。 实际上数据库支持这样的能力可以使用alter table A engineInnoDB​命令来重建表。在 MySQL 5.5 版本之前这个命令的执行流程跟我们前面描述的差不多区别只是这个临时表 B 不需要你自己创建MySQL 会自动完成转存数据、交换表名、删除旧表的操作。 上方的重建表的过程和原理都比较简单但是存在一个问题在这个操作过程中没法 增删改查即业务会受损。 2025年01月02日20:05:16 看到这了。 为了尽可能避免这种情况在表重建过程中又加入了一种log文件row log​用来记录在重建过程中的 增删改 操作。这也就是online DDL名字的来源。 没有row log离线DDL有row logonline DDL↩ / 【wip】缓存一致性保证 旁路缓存中如果修改了数据库的数据为了保证缓存一致性通常有先更后更和先更后删两种方案来更新缓存。需要注意的是简单的应用两种方案都无法保证严格的缓存一致性。 先更后更指的是先更新数据库再更新缓存先更后删指的是先更新数据库再删除缓存中的数据。 先更后更方案出现缓存不一致的时机是 并发出现更新先更后删方案出现缓存不一致的时机是 并发出现缓存中读取不到数据。 出现缓存不一致的时机唯一的可能性就是并发更新缓存先更后删方案并发出现缓存miss才会可能出现并发更新缓存数据。 两种方案更具体的细节讲解可见数据库和缓存如何保证一致性 | 小林coding 2025年04月30日10:09:48 写到这了。 ‍ todo提一下延迟双删并表明延迟双删是减少数据一致性的问题没有严格意义上的保证没有数据不一致的问题。 保证缓存一致性采用写改的方式的 坏处 1.需要全量保存数据缓存压力大 2.数据无法设置超时时间与第一条相辅相成 3.如果后续修改时失败可能导致缓存永远不一致。为了修复这个问题可能由需要引入outbox组件这样带来更大的复杂性且引入outbox也不能百分之百的解决问题。 ​ 作者给出的最终解决方案是类似于分布式锁的方案禁掉并发。 好处 1.不存在缓存miss 2.不存在惊群问题先改后删的方案可能存在惊群问题即如果多个并发读请求进来正好缓存miss了那么可能存在多个并发的读mysql并且修改缓存的情况作者称之为惊群问题 ‍ ‍ 改删方案有 存在不一致出现在读写并发 改改方案 不一致出现在写写并发。 因此作者认为改删方案不一致概率更高。 ‍ ‍ ‍ 个人感觉比较好的方案先改后删 租户机制文章没提及个人认为lease机制要限制较短的过期时间 缓存设置过期时间。 除了缓存一致性之外上面也提到了先改后删方案中还存在惊群问题那么惊群问题如何解决呢 关键就在于如果查询时发现缓存中已经有lease代表已经有并发开始了查询步骤此时就等待一段时间再重试即可代码上如何实现等待呢感觉可以使用singleFlight。 ‍ ‍ 感觉这里面最有用的学到的东西就是 解决缓存不一致问题的思路限制并发或者拿锁 本质上lease也是一种拿锁锁的是 设置缓存数据的资格。 ‍ todo更多思考引入版本号机制能否解决问题 ‍ 参考主要参考该文比较硬核里面讨论的比较详细 缓存与主副本数据一致性系统设计方案上篇_HAiLab的技术博客_51CTO博客 ‍ ↩
http://www.tj-hxxt.cn/news/138943.html

相关文章:

  • 小说网站怎么建设的WordPress积分打赏插件制作
  • 来一个网站谢谢了免费游戏不用登录大全
  • 西安好玩的地方有哪些郑州seo推广外包
  • 大连建站平台太原网站建设技术托管
  • 湖北襄阳网站建设网站建设的介绍
  • 太原谁家网站做的好dede做购物网站
  • 西安网站建设方案优化wordpress博客付费
  • 西部数码域名网站模板做网站购买什么
  • 河南省建设注册中心网站南昌seo网站开发
  • 延吉手机网站建设开发网站如何运营维护
  • 网站自动推广软件免费公司网站备案怎么做
  • 怎么往公司网站添加有园林案例的网站
  • 做网站月收入网站开发用什么字体
  • 常州发布信息的有什么网站网络营销作业策划方案
  • wordpress建站不好用wordpress怎么设置
  • 能打开的a站广东网站设计哪家好
  • 注册网站会员有风险吗app免费软件
  • 如何建立一个带论坛的网站安徽住房和城乡建设厅官网
  • 门户网站栏目维护建设方案衡阳seo外包
  • wordpress站长工作什么专业学网页设计制作
  • 谷歌怎么做公司网站如何解析后用二级域名做网站
  • 泌阳专业网站建设注册电子邮箱免费注册
  • 镇江做网站哪家公司好做企业网站需要什么文件
  • 网站建设 网络推广广州市设计院官网
  • 护肤网站的功能设计咸宁抖音seo收费标准
  • 盐城市建设局网站网站架构设计师有哪些学校可以报考
  • 如何搭建一个个人网站哪个网站简历做的好
  • 西部数码网站助手教程网页设计师培训哪个好
  • 广州网站制作是什么漯河网站建设 千弘网络
  • 做擦边球网站会不会违法呢莱芜一中贴吧