分库分表简介

在实践中对于海量数据一张表无法搞定,那么就想办法将数据放到多个地方,目前比较普遍的方案有3个:
1. 读写分离
2. 分库分表
3. NoSQL
只分库,或者只分表,或者分库分表融合方案都统一认为是分库分表方案,因为分库,或者分表只是一种特殊的分库分表而已。NoSQL比较具有代表性的是MongoDB,es;
1. 读写分离,主从复制
在实际应用中的绝大多数情况下读操作远大于写操作。MySQL提供了读写分离的机制,所有写操作必须对应到主库(Master),读操作可以在主库(Master)和从库(Slave)机器上进行。
主库与从库的结构完全一样,一个主库可以有多个从库,甚至在从库下还可以挂从库,这种一主多从的方式可以有效地提高数据库集群的吞吐量。
在DBA领域一般配置主-主-从或者主-从-从两种部署模型。
所有写操作都先在主库上进行,然后异步更新到从库上,所以从主库同步到从库机器有一定的延迟,当系统很繁忙时,延迟问题会更加严重,从库机器数量的增加也会使这个问题更严重。
此外,主库是集群的瓶颈,当写操作过多时会严重影响主库的稳定性,如果主库挂掉,则整个集群都将不能正常工作。
根据以上特点,我们总结一些最佳实践如下。
1.1 当读操作压力很大时,可以考虑添加从库机器来分解大量读操作带来的压力,但是当从库机器达到一定的数量时,就需要考虑分库来缓解压力了。
1.2 当写压力很大时,就必须进行分库分表操作了。

2. 整体的切分方式
单个库太大,这时我们要看是因为表多而导致数据多,还是因为单张表里面的数据多。 如果是因为表多而数据多,使用垂直切分,根据业务切分成不同的库。
如果是因为单张表的数据量太大,这时要用水平切分,即把表的数据按某种规则切分成多张表,甚至多个库上的多张表。

2.1 垂直切分

垂直分表如果一张表的字段非常多,那么很有可能会引起数据的跨页存储,这会造成数据库额外的性能开销,而垂直分表可以解决这个问题。垂直分表就是将一张表中不常用的字段拆分到另一张表中,从而保证第一章表中的字段较少,避免出现数据库跨页存储的问题,从而提升查询效率。而另一张表中的数据通过外键与第一张表进行关联。

垂直拆分优点:
1. 可以使得行数据变小,一个数据块 (Block) 就能存放更多的数据,在查询时就会减少 I/O 次数 (每次查询时读取的 Block 就少)。
2. 数据维护简单
垂直切分缺点:
1. 主键出现冗余,需要管理冗余列。
2. 依然存在单表数据量过大的问题(需要水平拆分)。

垂直拆分小结
系统层面的“服务化”拆分操作,能够解决业务系统层面的耦合和性能瓶颈,有利于系统的扩展维护。而数据库层面的拆分,道理也是相通的。与服务的“治理”和“降级”机制类似,我们也能对不同业务类型的数据进行“分级”管理、维护、监控、扩展等。
众所周知,数据库往往最容易成为应用系统的瓶颈,而数据库本身属于“有状态”的,相对于Web和应用服务器来讲,是比较难实现“横向扩展”的。数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈,是大型分布式系统中优化数据库架构的重要手段。

2.2 水平切分

如果一张表中的记录数过多(超过1000万条记录),那么会对数据库的读写性能产生较大的影响,虽然此时仍然能够正确地读写,但读写的速度已经到了业务无法忍受的地步,此时就需要使用水平分表来解决这个问题。水平分表是将一张含有很多记录数的表水平切分,拆分成几张结构相同的表。举个例子,假设一张订单表目前存储了2000万条订单的数据,导致数据读写效率极低。此时可以采用水平分表的方式,将订单表拆分成100张结构相同的订单表,分别叫做 order1、order2……order_100。
然后可以根据订单所属用户的 ID 进行哈希取模后均匀地存储在这100张表中,从而每张表中只存储了20万条订单记录,极大提升了订单的读写效率。

水平拆分优点
1. 单库单表的数据保持在一定的量级,有助于性能的提高。
2. 切分的表的结构相同,应用层改造较少,只需要增加路由规则即可。
水平拆分缺点
1. 切分后,数据是分散的,很难利用数据库的Join操作,跨库Join性能较差。
2. 分片事务的一致性难以解决。
垂直切分和水平切分的共同点如下:
1. 存在分布式事务的问题。
2. 存在跨节点Join的问题。
3. 存在多数据源管理的问题。

水平切分规则,主要有两种方式:
1. 按哈希切分
2. 按时间切分

3. 分库分表事务处理机制:
1. 两阶段提交协议
2. 最大努力保证模式
3. 事务补偿机制
在对性能要求很高的场景中,两阶段提交协议并不是一种好方案(原因之一是出点毛病就全部回滚,代价太大),最大努力保证模式也会使多个分布式操作互相嵌套,有可能互相影响。这里,我们给出事务补偿机制,其性能很高,并且能够尽最大可能地保证事务的最终一致性。
事务补偿机制并不苛求系统的实时一致性,只要在一个允许的时间周期内达到最终一致性即可(也就是说是可以慢一点,但是最后数据要一致)。这使得事务补偿机制成为一种可行的方案。
注意:如果采用事务补偿机制,则在遇到问题时,我们需要记录遇到问题的环境、信息、步骤、状态等,为了后续通过重试机制使其达到最终一致性。

4. 分库分表两大模式
分库分表中间件全部可以归结为两大类型:
1. CLIENT模式;
2. PROXY模式;
CLIENT模式代表有阿里的TDDL,开源社区的sharding-jdbc(sharding-jdbc的3.x版本即sharding-sphere已经支持了proxy模式)。架构如下:

PROXY模式代表有阿里的cobar,民间组织的MyCAT。架构如下:

无论是CLIENT模式,还是PROXY模式。几个核心的步骤是一样的:SQL解析,重写,路由,执行,结果归并。

4.1 应用层依赖类中间件
这类分库分表中间件的特点就是和应用强耦合,需要应用显示依赖相应的jar包(以Java为例),比如知名的TDDL、当当开源的sharding-jdbc、蘑菇街的TSharding、携程开源的Ctrip-DAL、支付宝开源但比较低调的zdal等。
此类中间件的基本思路就是重新实现JDBC的API,通过重新实现DataSource、PrepareStatement等操作数据库的接口,让应用层在基本(注意:这里用了基本)不改变业务代码的情况下透明地实现分库分表的能力。中间件给上层应用提供熟悉的JDBC API,内部通过SQL解析、SQL重写、SQL路由等一系列的准备工作获取真正可执行的SQL,然后底层再按照传统的方法(比如数据库连接池)获取物理连接来执行SQL,最后把数据结果合并处理成ResultSet返回给应用层。
此类中间件的优点很明显,就是无需额外部署,只要和应用绑定一起发布即可,但是缺点也很明显,就是不能跨语言,比如Java写的sharding-jdbc显然不能用在C#项目中,所以携程的dal也要重新写一套C#的客户端。

4.2 中间层代理类中间件
这类分库分表中间件的核心原理是在应用和数据库的连接之间搭起一个代理层,上层应用以标准的MySQL协议来连接代理层,然后代理层负责转发请求到底层的MySQL物理实例,这种方式对应用只有一个要求,就是只要用MySQL协议来通信即可,所以用MySQL Workbench这种纯的客户端都可以直接连接你的分布式数据库,自然也天然支持所有的编程语言。比较有代表性的产品有开创性质的Amoeba、阿里开源的Cobar、社区发展比较好的Mycat 等。
在技术实现上除了和应用层依赖类中间件基本相似外,代理类的分库分表产品必须实现标准的MySQL协议,某种意义上讲数据库代理层转发的就是MySQL协议请求,就像Nginx转发的是Http协议请求。
上述无论哪种类型的产品,除了实现分库分表这一主要功能外,都会额外实现一些其他很有实用价值的功能,比如读写分离、负载均衡等。

5. 分库分表后主键ID策略

5.1 自增

数据在单表中可以通过自增ID生成,但是当切换分表后,用户ID如果还是用自增生成,需要注意在创建新表时设置AUTOINCREMENT,例如创建表tbuser2时,设置AUTO_INCREMENT=10000000,DDL如下:

CREATE TABLE if not exists `tb_user_2` (	
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,	
  `username` varchar(16) NOT NULL COMMENT '用户名',	
  `remark` varchar(16) NOT NULL COMMENT '备注'	
) ENGINE=InnoDB AUTO_INCREMENT=10000000;	
- 这样的话,当新增用户时,用户ID就会从10000000开始,而不会与之前的用户ID冲突	
insert into tb_user_2 values(null, 'afei', 'afei');

5.2 Redis incr

第二种方案就是利用Redis的incr命令。将之前最大的ID保存到Redis中,接下来新增用户的ID值都通过incr命令得到。然后insert到表tbuser中。这种方案需要注意Redis主从切换后,晋升为主的Redis节点中的ID可能由于同步时间差不是最新ID的问题。这样的话,可能会导致插入记录到tbuser失败。需要对这种异常特殊处理一下即可。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值