多数据库水平分区解决方案
1. 介绍
Hibernate 个扩展用于处理多数据库水平分区架构
由google工程师 2007年 捐献给 Hibernate社区
http://www.hibernate.org/414.html
目前版本: 3.0.0 beta2 未发GA版
条件:Hibernate Core 3.2, JDK 5.0
2. 水平分区原理
个库表如 Order 存在于多个数据库例子上按特定分区逻辑将该库表数据存储在这些例子中条记录主键 PK在所有例子中不得重复
水平分区在大型网站WebSite大型企业应用中经常采用 像www.sina.com.cn ,www.163.com www.bt285.cn www.guihua.org
目出于海量数据分散存储分散操作分散查询以便提高数据处理量和整体数据处理性能
使用:
google工程师设计还是非常好完全兼容 Hibernate本身主要接口
Java代码
org.hibernate.Session org.hibernate.SessionFactory org.hibernate.Criteria org.hibernate.Query
因此员开发变化不大甚至不需要关心后台使用了分区数据库迁移问题不大而且配置上比较简明
3. 3种策略:
1) ShardAccessStrategy, 查询操作时到那个分区执行
默认提供两个实现:
顺序策略:SequentialShardAccessStrategy 每个query按顺序在所有分区上执行
平行策略:ParallelShardAccessStrategy 每个query以多线程方式并发平行在所有分区上执行 此策略下需要使用线程池机制满足特定性能需要java.util.concurrent.ThreadPoolExecutor
2) ShardSelectionStrategy, 新增对象时存储到哪个分区
框架默认提供了个轮询选择策略 RoundRobinShardSelectionStrategy, 但般不这样使用
通常采用“attribute-based sharding”机制基于属性分区般是用户根据表自己实现个基于属性分区策略类ShardSelectionStrategy 例如以下WeatherReport基于continent属性选择分区:
Java代码
public WeatherReportShardSelectionStrategy implements ShardSelectionStrategy { public ShardId selectShardIdForNewObject(Object obj) { (obj instanceof WeatherReport) { ((WeatherReport)obj).getContinent.getShardId; } throw IllegalArgumentException; } }
3) ShardResolutionStrategy, 该策略用于查找单个对象时判断它在哪个或哪几个分区上
默认使用 AllShardsShardResolutionStrategy 可以自定义例如:
Java代码
public WeatherReportShardResolutionStrategy extends AllShardsShardResolutionStrategy { public WeatherReportShardResolutionStrategy(List<ShardId> shardIds) { super(shardIds); } public List<ShardId> selectShardIdsFromShardResolutionStrategyData( ShardResolutionStrategyData srsd) { (srsd.getEntityName.equals(WeatherReport..getName)) { Continent.getContinentByReportId(srsd.getId).getShardId; } super.selectShardIdsFromShardResolutionStrategyData(srsd); } }
4. 水平分区下查询
对于简单查询 HibernateShard 可以满足
水平分区下多库查询是个挑战主要存在于以下 3种操作:
1) distinct
需要遍历所有shard分区并进行合并判断重复记录
2) order by
类似 1)
3) aggregation
countsimavg等聚合操作先分散到分区执行再进行汇总
是不是有点类似于 MapReduce ? 呵呵
目前 HibernateShard 不支持 1), 2), 对 3) 部分支持
HibernateShard 目前通过 Criteria 接口实现对 聚合提供了较好支持 Criteria 以API接口指定了 Projection 操作逻辑相对简单
而HQL原生 SQL 还不支持此类操作
5. 再分区和虚拟分区
当数据库规模增大需要调整分区逻辑和数据存储时 需要再分区
两种方式: 1)数据库数据迁移其他分区; 2) 改变记录和分区映射关系这两种方式都比较麻烦尤其“改变记录和分区映射关系”需要调整 ShardResolutionStrategy
HibernateShard 提供了种虚拟分区层当需要调整分区策略时只需要调整虚拟分区和物理分区映射关系即可以下是使用虚拟分区时配置创建过程:
Java代码
Map<Integer, Integer> virtualShardMap = HashMap<Integer, Integer>; virtualShardMap.put(0, 0); virtualShardMap.put(1, 0); virtualShardMap.put(2, 1); virtualShardMap.put(3, 1); ShardedConfiguration shardedConfig = ShardedConfiguration( prototypeConfiguration, configurations, strategyFactory, virtualShardMap); shardedConfig.buildShardedSessionFactory;
6. 局限:
1)HibernateShard 不支持垂直分区 垂直+水平混合分区
2) 水平分区下 查询功能受到定限制有些功能不支持实战中需要在应用层面对水平分区算法进行更多考虑
3) 不支持跨分区 关系 操作例如:删除A分区上 s 表B分区上关联子表 t记录无法进行参照完整性约束检查 (其实这个相对 跨分区查询挑战应该说小多也许google工程师下个版本会支持呵呵)
4) 解析策略接口似乎和对象ID全局唯性有些自相矛盾
AllShardsShardResolutionStrategy 接口返回是给定对象ID所在 shard ID集合按理应该是明确个 shard ID.
参考资料:HibernateShard 参考指南
最新评论