读写分离场景分析&实际业务落地

[原创]个人理解,请批判接受,有误请指正。转载请注明出处: https://heyfl.gitee.io/design/read-write-separation.html

接: 冷热分离场景分析&实际业务落地

前言

在数据库的读写研发中,我们遇到最多的可能就是数据量过多导致的『读/写慢』了。针对这些问题,我们一般主要会采取的措施有:

  1. 优化SQL
  2. 优化索引
  3. 优化硬件
  4. 分库分表
  5. 业务拆分
  6. 冷热分离
  7. 读写分离

这次我们主要讲讲读写分离的实际使用场景,以及如何以前刚出来时候的项目实际落地方案,这次的业务对应的场景有好几个,且因为涉及的数据量比较大、实时性与一致性要求都不一样,所以有几种读写分离方案

主要涉及到以下:

  1. 通过redis做读写分离
  2. 通过ES做读写分离
  3. 通过Hive做读写分离

重要说明:这里所说的读写是针对与数据库其他外部存储中间件的读写分离

读写分离

使用读写分离条件:

  1. 数据量大(↑)
  2. 查询响应慢(↓)
  3. 写入响应可以接受(OK)
  4. 所有数据随时需要update(★主要★)

这里以SF订单中台为场景(下面数值可能会比较敏感,这里随便扯个一个量级的数值分析就好哈)

订单中台每日新增单量5000w,数据存mysql,查询场景主要分2种:

  1. 接单系统(主要是B类)下单后进行查询、更新:业务方根据订单号、业务订单号到本中台系统查询订单信息
  2. 下游各类业务系统根据各种复杂条件查询订单信息

业务场景分析

  1. 3个月数据量可达到近50e
  2. 上游查询订单信息,一般是根据我们订单系统返回的内部订单号、业务订单号查询,查询条件是唯一索引,但是查询量较大,每日查询量达到亿级90%以上场景都是下单后当日内查询订单信息
  3. 下游查询订单信息,查询条件是各种复杂条件,查询量不定
  4. 订单信息是需要随时更新的,主要是业务上存在部分特殊情况(主要是预约单,业务上发现过预约到1个月后还是2个月后揽收的件。。。),需要更新订单信息、状态等

以上场景不太满足因为第4点的原因,3个月内数据不满足冷热分离条件,但却满足读写分离的使用条件,很适合做读写分离,以下来看看我们具体怎么做的

  • (其实我们当然还是做了冷热分离,3个月后的数据只能去大数据查询了)
  • (甚至还做了分库分表,分库分表有基因法和索引表法,因为设计分库查询条件比较多,所以采用的后者)
  • (但是这里不是我们讨论的重点所以忽略了哈哈哈)

解决方案

  1. 针对上游根据唯一索引查询订单的功能做Redis读写分离: 采用Redis缓存一天内的订单订单数据(采用过期LRU算法)拦截绝大部分查询请求,其余剩下的非热点数据查询数据库并设置到缓存
  2. 针对下游复杂条件查询的功能,分两种:
    1. (7天内创建、修改的)热点数据,采用ES存储、查询(其实按照情况,也会采用ES+hbase,我们这里的需求上大部分字段都可能用作查询,所以就直接把所有数据存到es了)
    2. (7天外创建的)非热点数据,存hive,业务人员提工单查询,目前没有对应的实时查询接口支持,实际业务场景上也没这块的需求,业务提工单主要是想对客户做月度分析之类的

落实的细节

  1. 针对场景1的『针对上游根据唯一索引查询订单的功能做Redis读写分离』,其实大多逻辑没有什么特别好说的,唯一要注意的是一致性问题:

这里以前我们采用的方案是响应给上游内部订单号,同时异步设置订单信息到Redis,但异步设置缓存与用户根据内部订单号发起订单查询请求的先后顺序无法保证,所以有时候会导致上游接单系统查到的是旧数据
为了解决该问题,我们采用了『类似延迟双删』的方案,先设置旧缓存数据过期时间为50ms,执行数据库更新/保存事务,设置新的缓存(需要通过lua脚本比较新老数据版本号)

  1. 针对场景2,采用了通过flink消费kfk的方式,将数据同步到ES、hive等大数据组件中:

这些主要是综合查询 或者历史数据查询,所以需要的实时性其实没有那么高,所以采用了异步的方式处理,flink这些我也不是很熟悉,之所以用了团队flink那是因为公司平台限制。。。有一说一的是,多批量数据实时并发处理的话,flink确实有他的独到之处,尤其是stream处理?

效果

订单中台系统后台数据库日均压力不到5%,双十一双十二不到10%。。。轻松。。。

问题

关于场景1的:

还是一致性问题,上下游更新操作是异步的,期间查询的还是旧数据,要做这种超强一致性的话可以参考这篇实现超强一致性缓存强一致性方案』,虽然可以这么做,但是没必要🤷‍

关于场景2:

  1. ES数据数据实时性不高(毕竟采用了异步方式,要实时的话。。。
    方式可能有很多,比方说至少要订单中台这边改同步写入es的方式,且需要手动调用es的refresh api,让其buffer刷新到os cache中,上游还得配合改造;
    当然也可以通过加入中间状态的方式处理。。。嗯。。不过。。。其实没必要,近实时就可以了,需要实时的话咱们还是得实际场景实际分析)
  2. 7天外且没做过任何更新的数据,业务人员只能提工单通过hive查,这个其实也没必要,因为这需求很少,而且也不是很重要,所以没必要做实时查询接口,业务人员提工单查询就行了

笔记

使用读写分离应用场景:

  1. 数据量大(↑)
  2. 查询响应慢(↓)
  3. 写入响应可以接受(OK)
  4. 所有数据随时需要update(★主要★)

读写分离的作用

为了提高『读/写』的性能,将读写分离,将读请求分发到不同的数据库实例上,减轻主库的压力,提高主库的写性能(读写二八定律)

问题

一致性问题,实时性问题

Other more

其实还有很多细节,但是没必要一一说明,因为这些都是根据实际业务场景来的,每个公司的业务场景都不一样,所以这里只是提供一个思路,具体的还是要根据实际情况来的


读写分离场景分析&实际业务落地

https://heyfl.gitee.io/design/read-write-separation.html

作者

神奇宝贝大师

发布于

2023-07-08

更新于

2023-07-20

许可协议

评论