透明的分库分表方案

问题提出

随着应用规模的不断扩大,单机数据库就慢慢无法满足应用的需要了,这主要表现在如下方面:

  1. 存量数据越来越大,查询速度越来越慢
  2. 访问并发越来越大,磁盘IO、网络IO、CPU都慢慢成为瓶颈
  3. 事务数越来越多,事务冲突越来越严重,导致TPS越来越少

这个时候,有的人采用了换商用数据库的方案比如Oracle,然后用Oracle的RAC方式进行水平扩展。但是带来的缺点也比较明显,第一是成本太高,一般人吃不消;第二,管理复杂度较单节点有非常大的提升,风险及管理成本也相应增加;第三,对人员的水平要求更高,如果做不好,在某些场景下甚至不如单节点来得快;第四,随着集群规模的变大,性能提升幅度与加入的节点数非正比关系,所以经济性也不太好。

因此,本人的结论是,短时间内采用Oracle等商用大型数据库阶段性的解决一段问题是可以的,但是从长久来说,还是治标不治本的。

因此当数据库处理能力不足的时候,还是要想办法对现有数据库进行的扩展为好。

解决方案

数据库处理性能不足的时候,一般有两种解决方案,一种是垂直扩展,一种是水平扩展。

  • 垂直扩展方案

优势:业务代码不需要进行任何附加处理

劣势:费用增加远超过扩展的处理能力
                通过增加硬件扩展的性能最终有其极
                限网络IO处理瓶颈无法解决
                随着数据量的增加,性能下降加快

  • 水平扩展方案

优势:磁盘IO、网络IO、CPU、内存分散到不同的机器上

水平扩展处理能力与花费的成本成正比
                可以接近无限的对处理能力进行扩展

劣势:对于业务有一定的限制条件
                跨库关联查询不被支持
                对于分库分表及应用需求要有系统的分析

简单的总结一下就是,采用垂直扩展方式,只能短时间解决问题,由于其能增加的性能最终是有极限的,因此不是终极解决方案;而水平扩展方案则几乎有无限的扩展能力,但是对设计人员的设计能力有要求,对于数据库中一些极特殊的SQL语句不支持。

需求分析

Tiny框架设计者当然不会做暂时的方案,当然想得是长久之计,于是毫无疑问要做水平扩展方案(当然,垂直扩展方案和软件几乎没有什么关系,咱也做不了),做之前首先扩展以下的需求:

  • 采用Java技术来实现
  • 要支持常见数据库,主要是能支持所有有JDBC Driver的数据库
  • 支持自增长主键,这样原来依赖自增长主键的数据库应用就不需要在这方面做特殊处理了
  • 支持数据库分页语句,这样原来依赖数据库分页语句的数据库应用就不需要在这方面做特殊处理了
  • 能支持绝大多数的SQL语句
  • 在性能方面最好能接近JDBC驱动
  • 有良好的扩展性,数据库设计者可以方便的进行定制扩展
  • 支持读写分离,负载均衡实现算法可定制
  • 支持分库
  • 支持分表
  • 对事务有良好的支持
  • 对统计及排序有良好的支持

系统设计与实现

实现方案及比较

数据库分区分表方案的实现方式有多种:

  • DAO层:实现难度低、业务代码耦合程度高、业务开发成本高、重构成本高,可复用性较差
  • DataSource层:实现难度中,业务代码耦合程度低、业务开发成本低、重构成本低、可复用性中
  • JDBC层:实现难度高,业务代码耦合程度低、业务开发成本低、重构成本、可复用性好
  • 代理层:实现难度高,业务代码耦合程度低、业务开发成本低、重构成本、可复用性好

Tiny框架采用了在JDBC层实现的方案,这种方案较代理层方面,可以少了网络通信方面的实现,所以代码量少、稳定性高,同时性能方面少一倍的网络通信,所以性能更高。

Tiny分库分表设计方案

稍解释一下:

当TinyDBRouter收到一个SQL时,首先对SQL进行解析,然后根据分库和分表规则路由到合适的真实数据库去执行,然后把执行的结果进行处理,然后把结果正确的提供给数据库请求者,一次交互就完整的完成了。

当然,实际的处理过程则远比这个要复杂得多,因为要考虑到事务的一致性、处理的高效性、结果的正确性,这里面的道道就多了,说起来比较漫长,这里就简单略过。

应用实例

使用方法

Class.forName("org.tinygroup.dbRouterjdbc3.jdbc.TinyDriver");
Connection conn = DriverManager.getConnection("jdbc:dbRouter://Router1", “username", “password");
Statement stmt = conn.createStatement();
String sql;
for (int i = 0; i < 10; i++) {
    sql = "insert into aaa(aaa) values (‘ppp‘)";
    stmt.execute(sql);
}

嗯嗯,上面就是使用方式了,熟悉JDBC的同学们马上就可以发现,这个和普通的JDBC程序没有什么不同么?确实是这样,使用TinyDBRouter,实际开发过程,与原来没有任何不同,不管是你用JDBC,还是Spring JDBC Template,还是iBatis、Hibernate,不管是任何的Java ORM框架,统统都可以使用。

唯一需要注意的就是,要把原来的URL和Driver改成Tiny的。

那其它的数据库管理工具,可以使用么?当然可以,只要是基于Java做的数据库管理工具,只要把Tiny的Driver相关的Jar包放入其ClassPath路径,就可以使用了。

其实对于统计方面的支持,对于所有的分库分表框架来说都是极具挑战性的,比如许多的分库分表框架要求每次SQL只能落在一个分片上执行,才能保证结果的正确性;比如许多的分库分表框架都要求统计时不能有排序等等,甚至有的直接就不支持,欢迎同学们让他们对号入座。

TinyDBRouter唯一的限制是:

不支持跨库关联查询

当然,几乎所有的都不支持这个特性,少量号称支持,实际上没有可用性---因为性能实在是太慢了,数据量如果大一点就死翘翘了。

常见问题问答

  1. 像MySQL、SQL Server中的自增长主键需要特殊处理么?答案:不需要,原有程序照样使用就好
  2. 像M ySQL、SQL Server中的分页SQL可以原样使用么?答案:必须可以
  3. TinyDBRouter支持的SQL语句支持的多么?答案:支持SQL92规范的绝大部分SQL语句(极少量不支持)
  4. 支持Having语句不?答案:支持
  5. 原有项目的代码重构成本高么?答案:这个和DBA制订的数据分区方案有关,只要不违反上面的限制条件都可以不修改。
  6. 我把主表和从表都分到一个分片中,关联只在相同分片中发生,这种情况下,代码需要修改吗?答案:不需要。

总结

Tiny框架的所有部件或子项目,我们从来不加吸引眼球的“最”字,我们相信只要我们扎扎实实的努力加上轻灵优雅的设计,一定会是相关问题领域中一个相当不错的解。

时间: 2024-10-09 02:57:12

透明的分库分表方案的相关文章

透明的分库分表方案——转自:OSChina 悠悠然然

转自:OSChina 悠悠然然 问题提出 随着应用规模的不断扩大,单机数据库就慢慢无法满足应用的需要了,这主要表现在如下方面: 存量数据越来越大,查询速度越来越慢 访问并发越来越大,磁盘IO.网络IO.CPU都慢慢成为瓶颈 事务数越来越多,事务冲突越来越严重,导致TPS越来越少 这个时候,有的人采用了换商用数据库的方案比如Oracle,然后用Oracle 的RAC方式进行水平扩展.但是带来的缺点也比较明显,第一是成本太高,一般人吃不消:第二,管理复杂度较单节点有非常大的提升,风险及管理成本也相应

MySQL分库分表方案

1. MySQL分库分表方案 1.1. 问题: 1.2. 回答: 1.2.1. 最好的切分MySQL的方式就是:除非万不得已,否则不要去干它. 1.2.2. 你的SQL语句不再是声明式的(declarative) 1.2.3. 你招致了大量的网络延时 1.2.4. 你失去了SQL的许多强大能力 1.2.5. MySQL没有API保证异步查询返回顺序结果 1.2.6. 总结 MySQL分库分表方案 翻译一个stackoverflow上的问答,关于分库分表的缺点的,原文链接: MySQL shard

【分库、分表】MySQL分库分表方案

一.Mysql分库分表方案 1.为什么要分表: 当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. mysql中有一种机制是表锁定和行锁定,是为了保证数据的完整性.表锁定表示你们都不能对这张表进行操作,必须等我对表操作完才行.行锁定也一样,别的sql必须等我对这条数据操作完了,才能对这条数据进行操作. 2. mysql proxy:amoeba 做mysql集群,利用amoeba. 从上层的ja

重磅来袭,使用CRL实现大数据分库分表方案

关于分库分表方案详细介绍 http://blog.csdn.net/bluishglc/article/details/7696085 这里就不作详细描述了,本方案拆分结构表示为 会员为业务核心,所有业务围绕会员来进行,所以垂直划分用会员编号作索引,将会员分配到不同的库 会员订单增长量是不固定的,所以需要平水拆分,和分库一样,一个表只存指定会员编号区间的订单 了解基本需求,就可以制作方案了,以下主索引表示主数据编号 库表结构配置 进行操作时,需要知道这个数据放在哪个库,哪个表,因此需要把这个划分

MySQL主从(MySQL proxy Lua读写分离设置,一主多从同步配置,分库分表方案)

Mysql Proxy Lua读写分离设置 一.读写分离说明 读写分离(Read/Write Splitting),基本的原理是让主数据库处理事务性增.改.删操作(INSERT.UPDATE.DELETE),而从数据库处理SELECT查询操作.数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库. 1.设置说明 Master服务器: 192.168.41.196 Slave服务器: 192.168.41.197 Proxy服务器: 192.168.41.203 2.安装Mysql Pro

MySQL 分库分表方案,总结的非常好!

前言 公司最近在搞服务分离,数据切分方面的东西,因为单张包裹表的数据量实在是太大,并且还在以每天60W的量增长. 之前了解过数据库的分库分表,读过几篇博文,但就只知道个模糊概念, 而且现在回想起来什么都是模模糊糊的. 今天看了一下午的数据库分库分表,看了很多文章,现在做个总结,"摘抄"下来.(但更期待后期的实操) 会从以下几个方面说起: 第一部分:实际网站发展过程中面临的问题. 第二部分:有哪几种切分方式,垂直和水平的区别和适用面. 第三部分:目前市面有的一些开源产品,技术,它们的优缺

如何设计可以动态扩容缩容的分库分表方案?

对于分库分表来说,主要是面对以下问题: 选择一个数据库中间件,调研.学习.测试: 设计你的分库分表的一个方案,你要分成多少个库,每个库分成多少个表,比如 3 个库,每个库 4 个表: 基于选择好的数据库中间件,以及在测试环境建立好的分库分表的环境,然后测试一下能否正常进行分库分表的读写: 完成单库单表到分库分表的迁移,双写方案: 线上系统开始基于分库分表对外提供服务: 扩容了,扩容成 6 个库,每个库需要 12 个表,你怎么来增加更多库和表呢? 是你必须面对的一个事儿,就是你已经弄好分库分表方案

分库分布的几件小事(三)可以动态扩容缩容的分库分表方案

1.扩容与缩容 这个是你必须面对的一个事儿,就是你已经弄好分库分表方案了,然后一堆库和表都建好了,基于分库分表中间件的代码开发啥的都好了,测试都ok了,数据能均匀分布到各个库和各个表里去,而且接着你还通过双写的方案咔嚓一下上了系统,已经直接基于分库分表方案在搞了. 那么现在问题来了,你现在这些库和表又支撑不住了,要继续扩容咋办?这个可能就是说你的每个库的容量又快满了,或者是你的表数据量又太大了,也可能是你每个库的写并发太高了,你得继续扩容. 缩容就是现在业务不景气了,数据量减少,并发量下降,那么

浅谈-分库分表方案

名词解释 库:database:表:table:分库分表:sharding 数据库架构演变 刚开始我们只用单机数据库就够了,随后面对越来越多的请求,我们将数据库的写操作和读操作进行分离, 使用多个从库副本(Slaver Replication)负责读,使用主库(Master)负责写, 从库从主库同步更新数据,保持数据一致.架构上就是数据库主从同步. 从库可以水平扩展,所以更多的读请求不成问题. 但是当用户量级上来后,写请求越来越多,该怎么办?加一个Master是不能解决问题的, 因为数据要保存一