我们的系统真的需要分库分表吗?分库分表常见场景和解决方案

522 阅读7分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

什么是分库分表

把原来存储在一个库表中的数据拆分到不同的库/表中。

为什么分库分表

业务的不断发展和数据的不断递增,未来场景下可能出现瓶颈

分布式部署、单机服务性能瓶颈、数据处理能力瓶颈、数据存储瓶颈等

众所周知,数据库往往最容易成为应用系统的瓶颈,而数据库本身属于“有状态”的,相对于Web和应用服务器来讲,是比较难实现“横向扩展”的。数据库的连接资源比较宝贵且单机处理能力也有限,在高并发场景下,分库一定程度上能够突破IO、连接数及单机硬件资源的瓶颈,是大型分布式系统中优化数据库架构的重要手段。

分库分表的实施策略

分库分表有垂直切分水平切分两种。

垂直拆分——主要是字段的拆分;

水平拆分——表结构不变,数据分表;

垂直切分

按照功能模块、关系密切程度将不同的业务表划分出来,部署到不同的库上。例如,我们的采购工作台,不同的业务表存储在不同的数据库中。系统层面的“服务化”拆分操作,能够解决业务系统层面的耦合和性能瓶颈,有利于系统的扩展维护。而数据库层面的拆分,道理也是相通的。与服务的“治理”和“降级”机制类似,我们也能对不同业务类型的数据进行“分级”管理、维护、监控、扩展等。

水平切分

按照某种规则把一张表的数据拆分成多个结构相同的表。

常用拆分规则:

  • 范围法:以用户的uid主键为范围规则划分
    •user-db0:存储0到1千万的uid数据
    •user-db1:存储1到2千万的uid数据

  • 范围法的优点
    •切分简单,根据uid,按照范围,很快能够定位到数据在哪个库上
    •扩容简单,如果容量不够,只要增加user-db2即可

  • 范围法的不足
    •uid必须要满足递增的特性
    •数据量不均,新增的user-db2,在初期的数据会比较少
    •请求量不均,一般来说,新注册的用户活跃度会比较高,故user-db1往往会比user-db0负载要高,导致服务器利用率不平衡

  • 哈希法:以用户的uid进行划分
    •user-db0:uid %2=0 的数据保存在db0库上
    •user-db1:uid %2=1 的数据保存在db1库上

  • 哈希法的优点
    •切分策略简单,根据uid取模,根据取模结果很快能够定位到数据在哪个库上
    •数据量均衡,只要uid是均匀的,数据在各个库上的分布一定是均衡的
    •请求量均衡,只要uid是均匀的,负载在各个库上的分布一定是均衡的

  • 哈希法的不足
    •扩容麻烦,如果容量不够,要增加一个库,重新hash可能会导致数据迁移,如何平滑的进行数据迁移,是一个需要解决的问题

  • 城市/租户-有明显业务特征的分表

  • 根据不同的城市、租户、供应商进行分库

  • user-db3201:3201南京的数据保存在db0库上

  • user-db3202:3202无锡的数据保存在db1库上

  • 优点:根据不同的业务特征进行拆分,按照不同的租户直接分离数据,数据独立

  • 缺点:单个租户数据量快速增大后依旧是瓶颈


拆分带来的问题

应该使用哪一种方式来实施数据库分库分表,这要看数据库中数据量的瓶颈所在,并综合项目的业务类型进行考虑。

拆分带来的问题?www.cnblogs.com/wade-luffy/…

  • 垂直分库带来的问题和解决思路
    跨库join的问题:全局表、字段冗余、数据同步、系统层组装
    跨库事务(分布式事务)的问题:分布式事务

  • 水平分库带来的问题和解决思路
    分布式全局唯一ID:id生成规则不再依赖于数据库
    分片字段该如何选择:片键 ,表中最频繁被使用,或者最重要的字段来作为分片字段
    数据迁移,容量规划,扩容等问题:历史数据、扩容
    跨分片的排序分页 :业务处理
    跨分片的函数处理 :业务处理
    跨分片join : 全局表、ER分片、内存计算

我们的系统真的需要分库分表吗?

Sharding-sphere

Sharding-Sphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar这3款相互独立的产品组成。他们均提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如Java同构、异构语言、容器、云原生等各种多样化的应用场景。

官网:shardingjdbc.io/

Sharding-JDBC

定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务
,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

1、适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。

2、支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。

3、支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。

优点:
1、性能很好的
2、支持跨数据库jdbc

缺点:
1、增加了开发难度
2、不支持跨语言(java)

Sharding-Proxy

定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前
先提供MySQL版本,它可以使用任何兼容MySQL协议的访问客户端(如:MySQL Command Client, MySQL 
Workbench等)操作数据,对DBA更加友好。

sharding-proxy是一种数据库中间件,从数据库层面解决分库分表问题,应用与sharding-proxy交互,sharding-proxy与实际分库分表数据库交互,sharding-proxy需要配置分库分表策略

优点:

  • 向应用程序完全透明,可直接当做MySQL使用。
  • 适用于任何兼容MySQL协议的的客户端。
  • sharding-ui,直接的管理sharding-proxy,在上面动态修改配置等信息。

缺点:

性能,作为数据库的代理层,使用java与阻塞式的驱动,这样,在高并发的场景下,sharding-proxy自身的性能就会变的很低了。因为会有大量内核态线程阻塞。做为代理层,我的理解,他应该是不阻塞线程的模型,来让代理层可以做更多的事情。比如,我以前需要5台集群代理支持的并发,现在可能通过1台能做当时5台所做的事情。

拆分带来的问题?www.cnblogs.com/wade-luffy/…

Sharding-Sidecar

定位为Kubernetes或Mesos的云原生数据库代理,以DaemonSet的形式代理所有对数据库的访问。 通过无中心、
零侵入的方案提供与数据库交互的的啮合层,即Database Mesh,又可称数据网格。

MyCat和Sharding-jdbc的区别

Mycat(proxy中间件层):

Sharding-jdbc(TDDL为代表的应用层):

sharding-jdbc和mycat使用不同的理念,sharding-jdbc目前是基于jdbc驱动,无需额外的proxy,因此也无需关注proxy本身的高可用。Mycat 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库,而 Sharding-JDBC 是基于 JDBC 接口的扩展,是以 jar 包的形式提供轻量级服务的