论坛首页 Java企业应用论坛

数据库分切设计何必纠结于hibernate shard模式,应该简单化了

浏览 6798 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-10-18  
最近讨论db shard的帖子比较多,感觉很多都是在参考hibernate shard的思路,但hibernate分表真的那么好吗?我觉得它最少有2个问题:

1. 改成shard后,代码的API调用要变。代码改动很大。
2. 设计很复杂,不清晰,逻辑关系难以理解。

hibernate shard基本上就是为了shard而对hibernate做的增增补补,凑合用还行,根本不具备设计上的参考价值。

对数据库分切方面,到目前为止,我觉得还是guzz的设计最清晰,如果我说的不对,欢迎理性讨论。不管您是否使用guzz,但是guzz在数据库分切方面的设计,对于清晰的设计模式,比hibernate shard更具有借鉴意义。

guzz垂直切分

垂直切分是指将不同的表分别存储到不同的数据库中。guzz默认配置级支持,不需要写任何代码,可以在任何时候,在需要时,将每张表存储到自己单独的一组服务器上,应该说是垂直分切的极限了。而且设计上,无论什么时候怎么分切,都不需要你改动代码。开发时你可以让所有表在一个库上;部署时,分到多个库上;以后业务增加了,再更加分散的放。

垂直分切简单配置方式:

1. 声明你要用多少台数据库,数据库之间什么关系。

        <dialect class="org.guzz.dialect.H2Dialect"></dialect>
        <dialect name="mysql5dialect" class="org.guzz.dialect.Mysql5Dialect" />
        <dialect name="oracle10gdialect" class="org.guzz.dialect.Oracle10gDialect" />
        
        <tran>
                <dbgroup name="default" masterDBConfigName="masterDB" />
                <dbgroup name="mysql" masterDBConfigName="masterDB" slaveDBConfigName="mysqlSlaveDB" dialectName="mysql5dialect" />
                <dbgroup name="oracle" masterDBConfigName="oracleDB" dialectName="oracle10gdialect" />
        </tran> 

这里我们声明了3组数据库,而且数据库类型还不一样。

2. 对每张表,配置应该存储到那个库里

	<a-business dbgroup="default" name="filterWord" class="com.guzzservices.business.FilterWord" />
	<a-business dbgroup="mysql" name="filterWordGroup" class="com.guzzservices.business.FilterWordGroup" />
	<a-business dbgroup="oracle" name="configuration" class="com.guzzservices.business.Configuration" />

简单的配置,将三个对象分别存储到3台不同的数据库中,完成垂直分切。

guzz水平切表

水平切表是指将一张大表,分切成许多小表。guzz的设计是当需要水平分表时,原先代码不变,为每个需要分切的表编写一个分表策略类,配置到系统中。然后在调用前,声明分表策略即可。
 
  整个过程只需要新写一个类,在调用出增加一行代码即可,对原始系统入侵非常小,风险可控。

  流程总比hibernate shard要清晰很多,具体可以看http://code.google.com/p/guzz/wiki/TutorialShadowTable?wl=zh-Hans


数据库主从分离

从垂直分切部分可以看到,guzz也是配置性的原生支持读写分离。如果需要增加从数据库,可以随时加上,不需要改任何代码。不需要改动代码,而且配置也不复杂,应该算是设计上的极限了吧?

你只需要在dbgroup中增加一个属性“slaveDBConfigName”,然后在一个properties文件中加上所有你需要的从数据库连接池配置即可,从数据库可以有许多台。

这个hibernate shard根本就没有涉及到。而且guzz允许程序控制读写库选取,和proxy模式的中间件路由各有优势,毕竟更加容易控制。如果你做过内容提前审核再允许发布的系统,就会明白proxy中间件解决不了全部问题,有些读操作不允许延迟,只能读主库,而是也是读事务,proxy中间件会很尴尬。

异构数据库

这个hibernate以及ibatis之类的更没有了。而且也是对应用透明的,你可以随时选择增加一种数据库,然后把某些表放到上面,如增加一个H2做应用端缓存数据库,自己完成类似Timesten + oracle的架构。

配置方式在上面的垂直分切小节也可以看到。

数据库连接池配置

随着表垂直和水平切分的进行,数据库会越来越多,数据源配置也会越来越多。guzz的设计是配置分组管理,类似Mysql的配置文件。每个数据源配置都在一个组内,无论增加多少都清晰了然,不会名字相互冲突。

示例:
[masterDB]
guzz.identifer=blogMasterDB
guzz.IP=localhost
guzz.maxLoad=120
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/blog?useUnicode=true&amp;characterEncoding=UTF-8&amp;useServerPrepStmts=true
user=root
password=root
acquireIncrement=10
idleConnectionTestPeriod=60

[updateMasterDB]
guzz.identifer=incUpdateDB1
guzz.IP=localhost
guzz.maxLoad=20
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/guzzSlowUpdate?useUnicode=true&amp;characterEncoding=UTF-8
user=slowupdate
password=slowupdate
acquireIncrement=10
idleConnectionTestPeriod=60

[logMasterDB]
....

如果一些数据库对某些连接池支持更好,guzz设计上还允许为不同的数据源指定不同的连接池实现。

如果您需要分表,还是放弃hibernate shard或ibatis的设计模式吧,哪些只是临时拼凑出来的东西,设计上根本就不怎么样!
   发表时间:2010-10-19  
对于数据库切分,麻烦之一就是分页查询等查询。。没用过guzz ,不知道是否已经解决了。。大概看了下文档,没怎么说明。。

稍微网上知道的比较好的数据库切分的中间件是阿里巴巴的amoeba
0 请登录后投票
   发表时间:2010-10-21  
切分后的表查询需要应用自己控制,guzz不记录路由关系,也不知道数据是如何分布的。和amoeba的策略不一样。

在这方面,使用guzz相当于在使用JDBC,只是说某些地方方便了,包括:连接池管理,ORM,对象的增删改和简单查询都能够像hibernate一样完全对象化。剩下的复杂联合查询sql的编写还是要靠DBA。

我觉得,如果您的项目需要分表,基本上来说,也指望不上自动的关联查询,性能肯定不放心。还是自己来的心理踏实。
0 请登录后投票
   发表时间:2010-10-21  
1、hibernate shard不支持垂直切分,你把三个不同的类(表)分到三个库里面,在HIBERNATE中也可以使不同的数据源来实现,代码层面同样是不需要改的,配置多个数据源即可。在我的理解中,真正的垂直切分是把一张表的字段拆分成多张表但只对应一个JAVA类,应用程序使时就和其他单表单类时相同。
2、使用hibernate shard的水平切分时,增删改查的操作同样和原来一样,改动的只在获得session factory对象时的代码(这个一般由一个静态工具方法、或框架中完成的),分库策略配置等,不存在麻烦的问题,当然数据迁移带来一定的麻烦似乎很难避免。
3、这两种切分在HIBERNATE中确实还有很多功能未能实现,多是跨库的关联操作。
0 请登录后投票
   发表时间:2010-11-17  
lgdlgd 写道
1、hibernate shard不支持垂直切分,你把三个不同的类(表)分到三个库里面,在HIBERNATE中也可以使不同的数据源来实现,代码层面同样是不需要改的,配置多个数据源即可。在我的理解中,真正的垂直切分是把一张表的字段拆分成多张表但只对应一个JAVA类,应用程序使时就和其他单表单类时相同。
2、使用hibernate shard的水平切分时,增删改查的操作同样和原来一样,改动的只在获得session factory对象时的代码(这个一般由一个静态工具方法、或框架中完成的),分库策略配置等,不存在麻烦的问题,当然数据迁移带来一定的麻烦似乎很难避免。
3、这两种切分在HIBERNATE中确实还有很多功能未能实现,多是跨库的关联操作。


看了一些shard的资料。

1. 做到字段的切分应该不是垂直切分的范围。对于字段存储在不同的数据库中,开发者还能够按照普通的pojo使用,hibernate支不支持不知道,但是guzz是支持的。可以通过custom column loader实现,不仅允许存储到不同的表,就是存储在不同的库,或者存储在文件系统,memcached中都可以。

2. hibernate shard的水平切分,在单对象操作时的确很优雅,但select时非常头疼,必须遍历查询所有的表然后合并结果集,如果需要对大数据翻页查询就疯掉了(不是大数据你也不需要分表)。这种设计过分考虑了通用性,但忽略了水平切分场景下,对代价的容忍程度;如果按照hibernate shard策略,设计者很难选择只在一个表执行查询,即便知道规则。对于真正需要分表的应用,数据很多,根本无法接受这种实现模式。guzz水平切分没有那么通用性,架构也很简单清晰,但允许指定表(通过指定规则参数),并且在表增加时不需要修改程序和配置,也不用重启应用。如果你按照时间分切,到点提前在数据库中创建下张会使用的表即可。我觉得这样更加实用。

3. 跨库关联以及自动reshard,目前而言,我觉得还是架构师和DBA应该考虑的;框架自动去做,难道你放心?

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics