透明的分库分表方案

问题提出

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

  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进行解析,然后根据分库和分表规则路由到合适的真实数据库去执行,然后把执行的结果进行处理,然后把结果正确的提供给数据库请求者,一次交互就完整的完成了。

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

应用实例

使用方法

?


1

2

3

4

5

6

7

8

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-17 15:07:23

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

PostgreSQL 分库分表 插件之一 pg_shard

MySQL的分库分表有非常多的解决方案,PostgreSQL 的分库分表方案也不少.今天要给大家介绍的是pg_shard插件.安装很简单,如果你的GCC版本第一4.6,那么首先要安装一个高版本的GCC,因为pg_shard里面用了gcc 4.6以后新加的特性. # yum install -y gmp mpfr libmpc libmpc-devel # wget http://gcc.cybermirror.org/releases/gcc-4.9.3/gcc-4.9.3.tar.bz2 #

订单表的分库分表方案设计(大数据)

    原创文章,转载注明出处     一.两种方案分库分表    一般业界,对订单数据的分库分表,笔者了解,有两类思路:按照订单号来切分.按照用户id来切分.   方案一.按照订单号来做hash分散订单数据        把订单号看作是一个字符串,做hash,分散到多个服务器去.      具体到哪个库.哪个表存储数据呢?订单号里面的数字来记录着.     现在的微信红包.它的订单分库分表,是对订单号进行hash计算.不是什么取模.取整数.这样数据是均匀分散的.     然后订单号的末尾3个数

【转】微服务MySQL分库分表数据到MongoDB同步方案

需求背景 近年来,微服务概念持续火热,网络上针对微服务和单体架构的讨论也是越来越多,面对日益增长的业务需求是,很多公司做技术架构升级时优先选用微服务方式.我所在公司也是选的这个方向来升级技术架构,以支撑更大访问量和更方便的业务扩展. 发现问题 微服务拆分主要分两种方式:拆分业务系统不拆分数据库,拆分业务系统拆分库.如果数据规模小的话大可不必拆分数据库,因为拆分数据看必将面对多维度数据查询,跨进程之间的事务等问题.而我所在公司随着业务发展单数据库实例已经不能满足业务需要,所以选择了拆分业务系统同时

详解yii2实现分库分表的方案与思路

前言 大家可以从任何一个gii生成model类开始代码上溯,会发现:yii2的model层基于ActiveRecord实现DAO访问数据库的能力. 而ActiveRecord的继承链可以继续上溯,最终会发现model其实是一个component,而component是yii2做IOC的重要组成部分,提供了behaviors,event的能力供继承者扩展. (IOC,component,behaviors,event等概念可以参考http://www.digpage.com/学习) 先不考虑上面的

mysql 分库分表的方法

分表后怎么做全文搜索 1.merge方式分表(不好) 2. 使用 sql union 3 使用Sphinx全文检索引擎 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. 根据个人经验,MySQL执行一个sql的过程如下: 1,接收到sql;2,把sql放到排队队列中 ;3,执行sql;4,返回执行结果.在这个执行过程中最花时间在什么地方呢?第一,是排队等待的时间,第二,

水平分库分表的关键问题及解决思路

分片技术的由来 关系型数据库本身比较容易成为系统性能瓶颈,单机存储容量.连接数.处理能力等都很有限,数据库本身的"有状态性"导致了它并不像Web和应用服务器那么容易扩展.在互联网行业海量数据和高并发访问的考验下,聪明的技术人员提出了分库分表技术(有些地方也称为Sharding.分片).同时,流行的分布式系统中间件(例如MongoDB.ElasticSearch等)均自身友好支持Sharding,其原理和思想都是大同小异的. 分布式全局唯一ID 在很多中小项目中,我们往往直接使用数据库自

水平分库分表的关键步骤和技术难点

在之前的文章中,我介绍了分库分表的几种表现形式和玩法,也重点介绍了垂直分库所带来的问题和解决方法.本篇中,我们将继续聊聊水平分库分表的一些技巧. 分片技术的由来 关系型数据库本身比较容易成为系统性能瓶颈,单机存储容量.连接数.处理能力等都很有限,数据库本身的"有状态性"导致了它并不像Web和应用服务器那么容易扩展.在互联网行业海量数据和高并发访问的考验下,聪明的技术人员提出了分库分表技术(有些地方也称为Sharding.分片).同时,流行的分布式系统中间件(例如MongoDB.Elas

TSharding:用于蘑菇街交易平台的分库分表组件

  tsharding TSharding is the simple sharding component used in mogujie trade platform. 分库分表业界方案 分库分表TSharding TSharding组件目标 很少的资源投入即可开发完成 支持交易订单表的Sharding需求,分库又分表 支持数据源路由 支持事务 支持结果集合并 支持读写分离 TSharding Resources Abstract TSharding Resources Classes TS

大众点评订单分库分表实践之路

本文是关于大众点评订单分库分表实践的一个具体分享,包含对订单库的具体切分策略,以及我个人的一些思考. 背景   订单单表早已突破两百G,因查询维度较多,即使加了两个从库,各种索引优化,依然存在很多查询不理想的情况.加之去年大量的抢购活动的开展,数据库达到瓶颈,应用只能通过限速.异步队列等对其进行保护.同时业务需求层出不穷,原有的订单模型很难满足业务需求,但是基于原订单表的DDL又非常吃力,无法达到业务要求.随着这些问题越来越突出,订单数据库的切分就愈发急迫了. 我们的目标是未来十年内不需要担心订