分库分表实战讲解——最后一课

DBC 1.6K 0

一、分库分表分区分别是什么?为什么这么做

了解分库分表的原因,如果不分表瓶颈会在哪里

  • 分库分表的原因
    • 数据库最容易产生性能瓶颈的服务组件。数据库连接数资源捉襟见肘和数据库因为表多、数据多造成的性能问题
    • 单一服务中心的数据访问压力也必然会达到单机数据库的承载上限,所以在进行服务化改造的同一时间段内,需要对数据库能力做扩展的工作
    • 单台数据库 这里以mysql为例,mysql数据库,当访问连接数过多时,就会出现‘too many connections’的错误,一般来说是访问量太大或者数据库设置的最大连接数太小的原因。Mysql默认的最大连接数为100.这个连接连接数可以修改,而mysql服务允许的最大连接数为16384
  • 什么是分区?
    • 分表是将一张表分成N多个小表,分区是把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上
  • 物理上多表存储,但是逻辑上单表操作

分库分表实战讲解——最后一课插图

 

分库分表实战讲解——最后一课插图2

二、分库分表常见手段分析

了解分库分表常见手段以及选择考虑方向

  • 一般会有两种分库分表方向,分别是垂直方向和水平方向,第一种方案是直接对现有的数据库进行垂直拆分,可以缓解目前写峰值QPS过大、DB主从延迟的问题。第二种方案是对现有数据库大表进行分库分表
  • 根据不同规模对垂直方向和水平方向的选择
    • 单个库太大,这时我们要看是因为表多而导致数据多,还是因为单张表里面的数据多。 如果是因为表多而数据多,使用垂直切分,根据业务切分成不同的库
    • 单张表的数据量太大,这时要用水平切分,即把表的数据按某种规则切分成多张表,甚至多个库上的多张表。 分库分表的顺序应该是先垂直分,后水平分。 因为垂直分更简单,更符合我们处理现实世界问题的方式
  • 垂直拆分
    • 垂直分表:也就是“大表拆小表”,基于列字段进行的。一般是表中的字段较多,将不常用的, 数据较大,长度较长(比如text类型字段)的拆分到“扩展表“
    • 垂直分库:垂直分库针对的是一个系统中的不同业务进行拆分, 数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈
  • 水平拆分
    • 水平分表:针对数据量巨大的单张表(比如订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈
    • 水平分库:将单张表的数据切分到多个服务器上去,每个服务器具有相应的库与表,只是表中数据集合不同。 水平分库分表能够有效的缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源等的瓶颈

分库分表实战讲解——最后一课插图4

分库分表实战讲解——最后一课插图6

三、分库分表实战环境准备

水平分库分表的模型设计

分库分表实战讲解——最后一课插图8

建表语句编写

太长了,收起来,避免篇幅太长

点击查看完整内容

四、基于springboot实战分库分表搭建

  • 分库分表实战
    • 引入pom依赖
    • 配置yml或者properties文件
    • 配置datasource config
    • 配置分库分表策略

分库分表实战讲解——最后一课插图10

实际操作

加入pom文件

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- sharding-jdbc -->
        <dependency>
            <groupId>com.dangdang</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>1.5.4</version>
        </dependency>

修改application.yml配置文件

product0:
    driver-class-name: com.mysql.jdbc.Driver
    #基本属性
    url: jdbc:mysql://ip:3306/product0?charset=utf8mb4&useSSL=false
    username: root
    password: mima
    databaseName: product0
product1:
    driver-class-name: com.mysql.jdbc.Driver
    #基本属性
    url: jdbc:mysql://ip:3306/product1?charset=utf8mb4&useSSL=false
    username: root
    password: mima
    databaseName: product1

这里我们看一下数据库结构图吧,避免有些模糊、抽象操作!

分库分表实战讲解——最后一课插图12

配置conf类

Product0Config

点击查看完整内容

Product1Config

点击查看完整内容

DataSourceConfig

点击查看完整内容

配置分库分表策略

TableShardingAlgorithm

点击查看完整内容

DatabaseShardingAlgorithm

点击查看完整内容

利用generatorConfig-xdclass.xml生成我们需要的类

generatorConfig-xdclass.xml

点击查看完整内容

主要需要修改的地方如下图

分库分表实战讲解——最后一课插图14
分库分表实战讲解——最后一课插图16

我们需要的就是他

分库分表实战讲解——最后一课插图18

可以测试一下了

ProductController

点击查看完整内容

测试结果如下图

分库分表实战讲解——最后一课插图20
分库分表实战讲解——最后一课插图22
分库分表实战讲解——最后一课插图24

温馨提示

单机下的水平分库、分表其实是更慢的。。。别一味的操作,哈哈哈 [aru_50] 之前可能0.01秒查到的数据,博主这里花了起码5秒。。。

五、分布式场景怎么保证ID唯一性?

讨论分布式场景ID怎么生成?

  • 分布式场景ID生成分析
    • 全局唯一:必须保证ID是全局性唯一的,基本要求
    • 高性能:高可用低延时,ID生成响应要块,否则会成为业务瓶颈
    • 高可用:100%的可用性是骗人的,但是也要无限接近于100%的可用性 99.9% 99.99%
    • 好接入:要秉着拿来即用的设计原则,在系统设计和实现上要尽可能的简单

分库分表实战讲解——最后一课插图26

Zookeeper 一致性

六、分库分表ID唯一性实现手段

讨论分布式场景ID怎么生成?

  • 号段模式是当下分布式ID生成器的主流实现方式之一,号段模式可以理解为从数据库批量的获取自增ID,每次自动生成一个号段,例如 (1,1000] 代表1000个ID,具体的业务服务将本号段,生成1~1000的自增ID并加载到内存(分布式缓存)

 

分库分表实战讲解——最后一课插图28

  • 雪花算法(Snowflake)是twitter公司内部分布式项目采用的ID生成算法,开源后广受国内大厂的好评,在该算法影响下各大公司相继开发出各具特色的分布式生成器 如:部署10台web服务,同一时间点,第一台机器生成uuid+00 第二台机器生成uuid+01 第三台机器生成uuid+02分库分表实战讲解——最后一课插图30
  • 雪花算法生成原则和原理
    • 使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0

     

    分库分表实战讲解——最后一课插图32

七、mysql分库分表非partition key检索

解析分库分表遇到的问题,非partition key如何发起检索

  • 分库分表是根据partition key做数据表下标定位,但在某些场景需要用到非partition key检索数据,就会遇到问题
    • 无法直接找到具体连到哪个库和哪个表
  • 对于单个非partition key查询一般可以根据业务场景需要解决方案
    • 映射法检索,通过非partition key找到对应的partition key,再根据partition key做hash找到对应库表
      • 优点:方案简单清晰
      • 缺点:需要检索两次数据库,消耗IO较大
    • 基因法检索,在存储非partition key时冗余一个字段用于预埋能找到对应的partition key,再根据partition key做hash找到对应库表
      • 优点:建立冗余字段,只需要解析基因即可
      • 缺点:需要设置基因解析逻辑
    • ES检索,根据非partition key作为条件建立起检索,后续查询直接走异构系统ES即可,性能和稳定性由ES保证
      • 优点:性能高,能支撑高并发访问和多条件检索
      • 缺点:开发成本增加,需要维护第三方组件

 

分库分表实战讲解——最后一课插图34

分库分表实战讲解——最后一课插图36

分库分表实战讲解——最后一课插图38

八、mysql分区是什么?

mysql表分区概念讲解,分区有哪些优势

  • 分区表的概念
    • 分区和分表相似,都是按照规则分解表。不同在于分表将大表分解为若干个独立的实体表,而分区是将数据分段划分在多个位置存放,可以是同一块磁盘也可以在不同的机器
    • 分区后,表面上还是一张表,但数据散列到多个位置了,app读写的时候操作的还是大表名字,db自动去组织分区的数据
  • 分区表有哪些类型
    • range分区类型:range 根据属于指定范围的列值将行分配到分区 (range就是区间,guave.range) a 判断==>[1,100]
    • list分区类型: 根据与离散值集之一匹配的列将行分配到分区
    • hash 分区类型:基于由用户定义的表达式返回的值而选择的分区,对要插入表中的行的列值进行操作

分库分表实战讲解——最后一课插图40

九、mysql分区原理和优劣势分析

分区表实践

CREATE TABLE `product` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `sale_id` varchar(64) NOT NULL DEFAULT '' COMMENT '卖家ID',
  `store_id` bigint(20) NOT NULL COMMENT '店铺ID',
  `product_seq` varchar(64) NOT NULL COMMENT '商品标识',
  `sku_id` varchar(64) NOT NULL COMMENT '商品skuID',
  `spu_id` varchar(64) NOT NULL COMMENT '商品spuID',
  `valid` tinyint(1) DEFAULT '1' COMMENT '是否有效,0无效,1有效',
  `create_time` datetime DEFAULT '2020-01-01 00:00:00' COMMENT '创建时间',
  `update_time` datetime DEFAULT '2020-01-01 00:00:00' COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001025 DEFAULT CHARSET=utf8mb4
partition by range columns(id,store_id)
(
partition p01 values less than (10000),
partition p02 values less than (20000),
partition p03 values less than (100000000)
);
  • 分区表原理
    • 存储角度分析:分区表是由多个相关的底层表实现,这些底层表也是由句柄对象表示,所以我们也可以直接访问各个分区,存储引擎管理分区的各个底层表和管理普通表一样
    • 查询角度分析:分区表的索引只是在各个底层表上各自加上一个相同的索引,从存储引擎的角度来看,底层表和一个普通表没有任何不同,存储引擎也无须知道这是一个普通表还是一个分区表的一部分
  • 分区表使用场景
    • 表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他都是历史数据
    • 区表的数据更容易维护,如:想批量删除大量数据可以使用清除整个分区的方式
    • 分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备
    • 优化查询,在where字句中包含分区列时,可以只使用必要的分区来提高查询效率,同时在涉及sum()和count()这类聚合函数的查询时,可以在每个分区上面并行处理,最终做汇总 10个分区分别分别count()
  • 分区表的劣势
    • 5.1一个表最多只能有1024个分区(mysql5.6之后支持8192个分区)。
    • 如果分区字段中有主键或者唯一索引列,那么所有主键列和唯一索引列都必须包含进来,如果表中有主键或唯一索引,那么分区键必须是主键或唯一索引
    • 如果SQL不走分区键,很容易出现全表锁
    • 分库分表,自己掌控业务场景与访问模式,可控;分区表,工程师写了一个SQL,自己无法确定MySQL是怎么玩的,不可控
    • 在分区表实施关联查询,就是一个灾难

发表评论 取消回复
表情 图片 链接 代码

分享