高并发情况下MySql面对亿级流量如何力挽狂澜?


高并发情况下MySql面对亿级流量如何力挽狂澜?

1.单库到多库的变革是为什么?分库分表是什么?

为什么分库?

  1. 遇到性能瓶颈

    MySql最大连接数为16384(但是没有这样的机器支持mysql性能全开) 一般mysql安装默认最大连接数为100 线上环境一般扩展至500

    程序的每次请求都需要一个连接(Conection) 假设MySQL有同时处理500请求的能力,但是现在有1000流量(QPS)进来,那么就会有500个请求等待获取连接,一般应用请求有峰值和低估之分,但是如TB双11情况下,请求一直在峰值,长久下去,会造成大量的请求堆积,就会拖垮服务器,导致宕机

  2. 提高查询速度

    Mysql数据都存储在磁盘中,假设现在有一张表有5000W的数据,每次检索数据都是一次磁盘IO,虽然可以通过索引优化连接速度,但是Mysql索引结构为B+Tree,索引一样是存储在磁盘中,数据量过大会导致tree树高过高(每一次树高在检索时会进行一次磁盘IO),磁盘IO次数高,会导致查询速度慢

  3. 数据量

    数据库数据过多,一般是数据库运行很久了,这样肯定是部分数据库表数据量大,数据基数大,查询速度慢,造成请求堆积,服务宕机

总结. 类似于Nginx服务转发


2.多维的业务场景&不同的性能瓶颈应该如何拆分?

分库

  1. 垂直分库: 不同属性的sql并发,一般按照功能进行库的划分。例如一个商场,用户一个库,商品一个库,订单一个库…不同的请求进根据自己的属性进不同的库查询。

  2. 水平分库: 假设2000QPS中有1800去请求订单库,但是当前分库后订单库连接数还是在500。 此时需要将订单库进行扩展,建立多个相同结构的订单库,对数据进行均摊。以缓解单库的压力

分表

  1. 分表方式,分为水平分表和垂直分表

  2. 垂直分表:(减少查询次数)Mysql在查询之后会将数据丢入Mysql缓存中,以便下次查询能够直接命中数据,不需要扫描库,减少查询时间。但是即使每次只查询了少量字段,MySQL还是会将整行数据丢入缓存中,而缓存是有大小的,列过多,缓存的数据越少。,命中次数就会越少,查询速度就会越慢。而垂直分表,将热字段和冷字段分离之后,缓存中能够存放的记录数就会越多,查询的命中次数增加,就可以减少查询时间。 垂直分表之后通过外键链接两条数据

  3. 水平分表: 数据行过多,引起性能瓶颈,一般是单表数据量增长过快,在某个节点,创建另外一张结构相同的表

  4. 分表的前提在整个数据库没有遇到性能瓶颈的情况

3.(技术有风险)引入分库分表后产生的问题剖析

表: 订单库,库存库

垂直分库会产生的问题

  1. 事务
    例: 下订单,加订单 -> 减库存 单库添加数据就可以了
    1
    2
    3
    4
    5
    6
    7
    8
    @Transition
    Methods
    try{
    成功
    commit
    }catch(Exception e){
    rollback
    }

解决方式:

  • 1PC

    待补充

  • XA

    待补充

  • 2PC

    待补充

  • 3PC

    待补充

  • TCC

    待补充

  • MQ(分布式事务)

    待补充

  • 远程表

    待补充

  • 广播表

    待补充

  1. 连表查询(join)
    解决方式
    • 在客户端做数据组合
      字段冗余 表冗余

      例: 先查用户信息,再查订单信息 组合

水平分库会产生的问题

  1. 分页
    例: 分页且按照订单金额排序怎么办?

    • 并行查询,第一页,每页10条,三个库分别查询前十条返回三十条数据,然后筛选出前十条数据。但是返回的数据一旦过多会出现问题。
    • 提前做数据聚合,丢入nosql,定时同步,不能保证数据的实时性
  2. 聚合函数
    count(1)

    查询全部数据库,最后做数据汇总

  3. ID唯一性

    • 第三方生成
    • Redis incr (Redis Incr 命令将 key 中储存的数字值增一)
    • uuid (会影响效率)
    • 主键步长 db1: 1,3,5,7 db2: 2,4,6,8 一旦添加了新的库,数据主键需要全部改变
    • 特殊算法生成: 雪花…
  4. hbase + flive + 实时风控

分库分表之后程序应该如何去访问?

  1. 编码层 –> AbstracRoutingDataSource()

    1
    2
    3
    4
    5
    if(id < 10000){
    conn db1
    }else if(id > 10000 && id < 20000 ){
    conn db2
    } ...

    灵活的数据源切换,但是代码臃肿

  2. 框架层 –> Mybatis Interceptor接口

  3. 驱动层 –> Sharding JDBC
    avatar

  4. 代理层 –> MyCat(类似NG,统一管理,请求分发) 详情

  5. 服务层 –> SQL特殊版本支持

4.驱动层Sharding-JDBC实战

5.当MySql单库扛不住一定要分库分表吗?

6.分库分表经典面试题深入浅出

收获

  1. 我们要知道为什么这样做。 知其然,知其所以然
  2. begin connit rollback

文章作者: zxc
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 zxc !
 上一篇
VsCode 因为在此系统上禁止运行脚本 解决办法 VsCode 因为在此系统上禁止运行脚本 解决办法
12341. 以管理员身份运行vscode;2. 执行:get-ExecutionPolicy,显示Restricted,表示状态是禁止的;3. 执行:set-ExecutionPolicy RemoteSigned;4. 这时再执行get
2020-10-19
下一篇 
HTTP状态码 HTTP状态码
HTTP状态码400一般是js请求方式错误 在后端使用 @RequestParam 接受参数时 ajax中请将 contentType: 'application/json' 去除 在后端使用 @RequestBody
2020-03-21
  目录