高并发系统设计40问
唐扬
美图公司技术专家
立即订阅
9202 人已学习
课程目录
已更新 38 讲 / 共 40 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么你要学习高并发系统设计?
免费
基础篇 (6讲)
01 | 高并发系统:它的通用设计方法是什么?
02 | 架构分层:我们为什么一定要这么做?
免费
03 | 系统设计目标(一):如何提升系统性能?
04 | 系统设计目标(二):系统怎样做到高可用?
05 | 系统设计目标(三):如何让系统易于扩展?
06 | 面试现场第一期:当问到组件实现原理时,面试官是在刁难你吗?
演进篇 · 数据库篇 (5讲)
07 | 池化技术:如何减少频繁创建数据库连接的性能损耗?
08 | 数据库优化方案(一):查询请求增加时,如何做主从分离?
09 | 数据库优化方案(二):写入数据量增加时,如何实现分库分表?
10 | 发号器:如何保证分库分表后ID的全局唯一性?
11 | NoSQL:在高并发场景下,数据库和NoSQL如何做到互补?
演进篇 · 缓存篇 (6讲)
12 | 缓存:数据库成为瓶颈后,动态数据的查询要如何加速?
13 | 缓存的使用姿势(一):如何选择缓存的读写策略?
14 | 缓存的使用姿势(二):缓存如何做到高可用?
15 | 缓存的使用姿势(三):缓存穿透了怎么办?
16 | CDN:静态资源如何加速?
加餐 | 数据的迁移应该如何做?
演进篇 · 消息队列篇 (6讲)
17 | 消息队列:秒杀时如何处理每秒上万次的下单请求?
18 | 消息投递:如何保证消息仅仅被消费一次?
19 | 消息队列:如何降低消息队列系统中消息的延迟?
20 | 面试现场第二期:当问到项目经历时,面试官究竟想要了解什么?
用户故事 | 从“心”出发,我还有无数个可能
期中测试 | 10道高并发系统设计题目自测
演进篇 · 分布式服务篇 (9讲)
21 | 系统架构:每秒1万次请求的系统要做服务化拆分吗?
22 | 微服务架构:微服务化后,系统架构要如何改造?
23 | RPC框架:10万QPS下如何实现毫秒级的服务调用?
24 | 注册中心:分布式系统如何寻址?
25 | 分布式Trace:横跨几十个分布式组件的慢请求要如何排查?
26 | 负载均衡:怎样提升系统的横向扩展能力?
27 | API网关:系统的门面要如何做呢?
28 | 多机房部署:跨地域的分布式系统如何做?
29 | Service Mesh:如何屏蔽服务化系统的服务治理细节?
演进篇 · 维护篇 (5讲)
30 | 给系统加上眼睛:服务端监控要怎么做?
31 | 应用性能管理:用户的使用体验应该如何监控?
32 | 压力测试:怎样设计全链路压力测试平台?
33 | 配置管理:成千上万的配置项要如何管理?
34 | 降级熔断:如何屏蔽非核心系统故障的影响?
高并发系统设计40问
登录|注册

09 | 数据库优化方案(二):写入数据量增加时,如何实现分库分表?

唐扬 2019-10-07
你好,我是唐扬。
前一节课,我们学习了在高并发下数据库的一种优化方案:读写分离,它就是依靠主从复制的技术使得数据库实现了数据复制为多份,增强了抵抗大量并发读请求的能力,提升了数据库的查询性能的同时,也提升了数据的安全性。当某一个数据库节点,无论是主库还是从库发生故障时,我们还有其他的节点中存储着全量的数据,保证数据不会丢失。此时,你的电商系统的架构图变成了下面这样:
这时,公司 CEO 突然传来一个好消息,运营推广持续带来了流量,你所设计的电商系统的订单量突破了五千万。订单数据都是单表存储的,你的压力倍增,因为无论是数据库的查询还是写入性能都在下降,数据库的磁盘空间也在报警。所以,你主动分析现阶段自己需要考虑的问题,并寻求高效的解决方式,以便系统能正常运转下去。你考虑的问题主要有以下几点:
1. 系统正在持续不断地的发展,注册的用户越来越多,产生的订单越来越多,数据库中存储的数据也越来越多,单个表的数据量超过了千万甚至到了亿级别。这时即使你使用了索引,索引占用的空间也随着数据量的增长而增大,数据库就无法缓存全量的索引信息,那么就需要从磁盘上读取索引数据,就会影响到查询的性能了。那么这时你要如何提升查询性能呢?
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《高并发系统设计40问》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(43)

  • 每天晒白牙
    主要内容梳理
    写入请求量大会造成性能和可用性的问题,如何应对呢?
    采取对数据进行"分片",这是一种思想,在数据库中就是分库分表,Kafka中是分区,ES中是分片

    分库分表的思想是根据某种分配策略把数据尽量均匀的分到多个数据库节点或多个表中,这样每个数据库节点和表都只存储部分数据,这样对数据的存储、读和写都有意义
    存储:因为分库分表后每个节点和表只存储部分数据,这样就能解决数据存储的瓶颈
    读:因为每个节点和表存储部分数据,数据量变小,可以提升查询性能
    写:数据写入被分摊到多个节点和表,写入性能提高

    分库分表有两种方式:垂直拆分和水平拆分
    垂直拆分的关注点在业务相关性,原则是按照业务拆分,核心思想是专库专用,将业务耦合度高的拆分到单独库中
    水平拆分是把单一数据库按照某种规则拆分到多个数据库和多个数据表中,关注点在数据的特点

    水平拆分的两种方法
    1.根据某个字段的hash值拆分
    比如想把用户表拆成16库64表,方案如下
    先对id进行hash操作hash(id),这样有助于打散数据
    然后对16取余 hash(id)%16,这样就得到了分库后的索引
    最后对64取余 hash(id)%16%64,这样就得到了分表后的索引值

    2.根据某个字段的区间或范围拆分
    可以根据时间拆分

    引入分库分表确实有很多优点,但也会引入新的问题
    1.引入了分区分表键,也叫分区键
    因为我们需要对分区键进行hash进行索引,这样就导致我们查询都要带上该分区键,比较好的解决办法是用id做分区键,但是如果有根据用户昵称查询的需求怎么办呢?
    解决办法就是建立一个昵称和id的映射表
    2.一些数据库的特性的实现变得困难
    (1)夸库join不可用
    解决办法是在业务代码中做处理
    (2)求count
    采取第三方组件例如redis实现

    课后思考题
    大数据的存储组件一般都涉及数据分片技术
    例如Kafka的分区,ES的分片等等
    拿Kafka的分区来举例
    Kafka会对消息的key进行hash然后对分区数量取模,这样就得到了topic对应的分区索引

    疑问点
    1.老师我想请教下就是多库join的问题,如果采用在业务代码中进行处理不太妥吧,数据量太大了,如果有分页或排序的需求,这是要把各个库的数据都查出来,在内存中进行操作,这样会想当耗费内存,且性能低,老师有啥好办法吗?

    2.如果一个订单库采用了买家id做为分区键,这样查询买家的订单非常容易,那要查询卖家的订单是不是和文中根据昵称查询一样,建立一个卖家和买家的映射表解决?

    3.文中老师说如果要做分库分表留言一次性做到位,但这样在开始会很浪费空间,所以一般公司还是会采取慢慢扩容的方式,这样就引入了不停机迁移数据的问题,针对这种情况,老师是怎么做的呢?
    谢谢老师

    作者回复: 1.多表join一般不会是全量数据,是分页数据,所以只有一少部分
    2.建议是订单ID分库分表,然后建立买家ID和卖家ID和订单ID的映射
    3. 一般是先双写两个库,然后校验数据,然后灰度切读,最后全量切读

    2019-10-07
    3
    36
  • 撒旦的堕落
    老师说的道理 我都明白 只是如果现在有一张上亿的表 并且存在特定属性更新 那么如何不停机 进行分库分表 有木有具体的实践

    作者回复: 可以搭建新的库之后,先在业务上双写,然后校验两边的数据,再灰度切读,再全量切读

    2019-10-09
    7
  • tyul
    老师,请问下昵称和 ID 的映射表怎么建立,是按照昵称进行分库分表吗,即先查询这个昵称在哪个库哪个表,然后找到 ID,根据 ID 所在的库和表进行查询吗?

    作者回复: 是的,没错

    2019-10-07
    2
    5
  • 枫叶11
    公司小业务少时,不可能一开始就规划很多库和表(如16*64),就像很多项目开始都只有一个库,但是我们做架构时可以预先考虑到后面可能会分库分表。请问老师,能不能讲一下最开始设计数据库时需要为今后分库分表考虑哪些因素,和一旦扩容后数据迁移的方案和注意点。谢谢。

    作者回复: 主要考虑数据的增长情况,数据迁移一般是先双写旧库和新库,然后校验数据,然后灰度切读,最后全量切读,注意点就是数据校验过程,会比较繁琐

    2019-10-07
    1
    4
  • 小喵喵
    老师能详细介绍一下分区和分片技术吗?
    2019-10-10
    3
  • jc9090kkk
    感谢老师分享,对于分表有点疑问:
    1.如果是用户信息表需要分表,数据量大的前提下,需要准备一个映射表来存储昵称+uid的对应关系,文中提到了映射表也可以做分库分表,基本的思路是什么?用户在做登录相关操作的时候,都不知道昵称+uid的映射关系在哪张表中,难道是通过昵称算出hash值来确定分区键?
    2.如果hash分表的策略又达到了瓶颈,需要更多的容量呢?基于对业务影响最小的方案是采用数据冗余+新的分区表还是重建分表规则做数据迁移?这一部分没有讲到哦,后面能否专门讲解下,一般应该是前者吧,因为后者在数据量大的情况下做一次数据迁移成本太高了?
    3.对于文中提到的,16个库每个库中64张表,1024个张表,这个分表策略的理由是什么?个人感觉这个分表规则显得有些太浮夸了,因为有些业务压根用不到这么多表,甚至有时候分表操作是分表策略(局部分表)+当前模式(局部不分表)公用的方式来协调的,一步一步迭代过来的?不是很理解文中提到的这个策略的容量是如何计算出来的?如果数据量压根用不到这么多表,数据过于分散,对于管理和维护成本来讲有点小题大做了吧?

    另外有一点,文中提到的总计数的问题,用redis存储的前提是当前的业务逻辑不是敏感的,用redis可以提升性能,如果是敏感业务的话,在更新数据库后还没有写入redis中的这个时间差,请求并发没办法估量和控制,所以最后的数据总量仅仅是最终的数据是一致的,但是逻辑是不一致的,核心原因是redis和mysql是属于不同的存储系统,无法做到两个系统公共支持一个分布式事物,无法拿到精确一致的视图,当然如果是非敏感业务,在保证性能的前提下,逻辑不一致可以容忍的话是可以考虑这种方案的。

    作者回复: 1. 是对昵称做hash,登陆的时候不需要知道昵称呀,可以针对手机号做hash,昵称是用来判断昵称是否存在
    2. 不太清楚数据冗余 + 新的分区表的意思,是增加新的分区表吗?那么就要改分库分表的规则,那这样原先的数据就读不到了?是要做数据迁移?
    3. 是需要一步步迭代,这里是说这些库表是足够了,如果业务没有那么大数据量,可以按照业务来
    4. 计数是最终一致就好了

    2019-10-08
    3
  • zk_207
    扬哥,后续可以开一期讲一下线上数据迁移的专题吗?

    作者回复: 马上就有啦:)

    2019-10-24
    2
  • Richeir
    老师,如果水平分表是按照用户Id分的,如何进行分页查询呢?

    作者回复: 如果需要按照别的字段分页查询就需要冗余存储一份了

    2019-10-22
    1
    1
  • longslee
    老师,今天回来提个问题:在垂直拆分各个业务到不同的库和中心后,以前的那种rel关系表,到底应该归为哪个中心呢?望解答,困惑了我很久,谢谢!

    作者回复: 我归在了用户中心

    2019-10-18
    1
  • 深深的人
    老师查询conut怎么做冗余,那种有where条件的

    作者回复: 可以考虑用es

    2019-10-15
    1
  • longslee
    打卡。老师,我一直以为“垂直”分表,是把一张大宽表,选出其中一些“列”,来化为新表😢 另外,在Oracle中的分区Partition索引,它支持多级 Sub Partition,那个它复杂度和存储是不是很恐怖呢😱
    2019-10-11
    1
  • 黑暗浪子
    这个东西能不用就不用。毕竟很多老系统还有超多join操作,你一开始分库分表,所有代码都要重写。我倒觉得换es,mongodb是个好思路

    作者回复: 如果有运维能力也可

    2019-10-10
    1
  • 正在减肥的胖籽。
    分库分表之后,对于app端查询的问题还比较好解决。但是后端运营系统查询就麻烦,比如订单分库分表后,运营系统查询订单的时候可能根据多维度查询,这种方案您在工作中是怎么去解决的?我现在的做法就是同步到es里面。用ES去查。

    作者回复: 可以的,也可以同步到一个大库中,不过性能有点儿差

    2019-10-09
    1
    1
  • xu晓晨
    如果分库分表后 又增加了一个库来存储。那么原来的数据岂不是都不能用了?所有的数据再需要重新的分一遍吗?
    据说一致性hash能解决这问题?老师可以具体说说吗

    作者回复: 一致性hash解决不了这个问题,如果要增加库的话,只能重新分配,所以会比较麻烦

    2019-10-08
    1
    1
  • Toutoublue
    我挺推荐AWS Dynamo DB的,不用我自己部署,原生支持分区(有partition key),还支持分区内排序(有sort key),而且可以用API调用。
    这个不是广告,纯属个人使用感受。
    2019-10-07
    1
    1
  • Corner
    请教老师,为什么id要先做hash再做取余计算分库位置呢?直接用id取余不可以吗?

    作者回复: 直接取余也好,只是怕ID会不均匀

    2019-10-07
    1
  • M
    麻烦请教下老师,项目中单表百万级的多表联查怎么做优化呢?
    2019-12-04
  • 深深的人
    老师,我们是商家的数据放在一起,但是有的商家数据比较多,有的少,哪种hash函数会没有热点问题呢?
    2019-11-23
  • leesir
    分库分表如何做:
    1、对实体表,路由规则可以是id取模,计算得到数据真正存放的表。可以降低单表的规模,平均每个表的数据量。
    2、对时间倒排的列表,比如微博内容或者订单,可以根据时间字段水平分表,将近期少部热点数据集中到一起。

    分库分表所引发的问题的解决方案:
    1、由于分区规则的原因,查询无论如何都必须拿到分区键。可以对某些高频非分区键字段建立二级映射,模拟mysql主键和二级索引的解决方式(二级索引的叶子数据存放的是主键索引)。比如根据name查询用户,可以建立name和uid的映射,查询时先根据name拿到uid,再用uid做后续查询。
    2、数据库拆分后,针对联表查询,要么少做联表,要么做数据冗余(表字段冗余,或者其他nosql数据冗余)。
    3、分布式事务
    a) 数据库中间件
    b) mq事务消息
    c) 将分布式大事务转化成多个本地小事务,通过异步通知+定时补偿+幂等实现最终一致性
    2019-11-20
  • 布小丫学编程
    Redis也是通过数据分片来解决水平扩展的。对于用户昵称查询,总数啥的,可以直接load到ES中吗?然后查询时直接查询ES就可以了?这种方案会不会有什么问题?

    作者回复: 这样也可以的

    2019-11-19
收起评论
43
返回
顶部