一致性Hash算法在数据库分表中的实践 (2)

我们业务中,主要操作这张表的数据,也就是增删查。然后我们数据库拆分成了3个,所以需要增删查的操作基本一致,都是先通过一致性hash得到库,再通过一致性hash得到表。

获取数据库名的操作如下,获取到数据库后,根据数据库名到对应的连接池中获取连接。

/** * 根据试验信息id获取其所在库名 * DatabaseType为我们数据的枚举 * @return 数据库的名称 **/ private String getDataBase(String experimentMessageId) { //获取数据源 DatabaseType[] databasetype = DatabaseType.values(); List<String> dataBaselist = new ArrayList<>(); Map<String, DatabaseType> map = new HashMap<>(); for (DatabaseType d:databasetype) { if (!d.equals(DatabaseType.KC)) { dataBaselist.add(d.toString()); map.put(d.toString(), d); } } //获取数据源hash ConsistentHash<String> dataBaseCon = getConsistentHash(dataBaselist); //获取id所在数据源 String dataBase = dataBaseCon.get(experimentMessageId); return dataBase; }

获取表名的操作如下,获取到数据库后,在对应的数据库中找到需要的表,再从该表中查询数据。

/** * 根据试验信息id获取其试验数据所在表 * @return **/ public String getTableName(String experimentMessageId) { String dataBase = getDataBase(experimentMessageId); //查询所有试验数据表 List<String> tables = experimentDataEODao.queryTbaleNames(dataBase, tableName); ConsistentHash<String> consistentHash = getConsistentHash(tables); String tableName = consistentHash.get(experimentMessageId); return tableName; }

剩下的增删改操作和平常一致,在此不多赘述。

数据迁移实践

一致性hash势必涉及到数据迁移问题,我们采取的数据迁移方式为定时任务,针对每个数据库在每天夜里全量扫描一次。检查是否有数据量超过1000万的表,若存在这样的表,就把现有的表数量double。
数据迁移只会在同库之间迁移,不会涉及跨数据库的情况。
此方案为初步方案,后续会改进的更加智能,根据表的数量,增加不同数量的表。而不是简单的把表数量翻倍。
表创建后,将需要迁移的表数据逐个迁移。

在连接到数据源后,我们做了如下事情进行数据迁移
1.获取库中所有的表

List<String> tables = getTables(connection, p, d.toString());

2.遍历表,检查表中数据是否超过边界线(我们为1000万)

for (int i = 0; i < tables.size(); i++) { //查询表内数据量 int num = countByTableName(connection, p, tables.get(i)); //finalNum为边界值,此处为1000万 if (num > finalNum) { …… } …… }

3.根据所有的表计算现有的虚拟节点

ConsistentHash<String> consistentHashOld = getConsistentHash(tables);

4.把表加倍

List<String> tablesNew = deepCopy(tables); //注意一定要采用深复制 int tableSize = tablesNew.size(); for (int y = 0; y < tableSize; y++) { String tableNameNew = tableName + (tablesNew.size() + 1); //创建表 createTable(connection, p, d.toString(), tableNameNew); tablesNew.add(tableNameNew); tableDelete.add(tableNameNew); }

5.计算加倍后的虚拟节点

ConsistentHash<String> consistentHashNew = getConsistentHash(tablesNew);

6.数据迁移

for (int z = 0; z < tableSize; z++) { String tableNameOld = tablesNew.get(z); //查询试验信息id不重复的试验数据信息 List<String> disData = selectExperimentIdDis(connection, p, tableNameOld); List<String> deleteList = new LinkedList<>(); for (String experimentId : disData) { //如果数据hash计算 原所在表与新建表之后不一致,执行转移 if (!consistentHashNew.get(experimentId).equals(consistentHashOld.get(experimentId))) { //新增到新表数据 insertHash(connection, p, experimentId, consistentHashOld.get(experimentId), consistentHashNew.get(experimentId)); //删除数据集合 deleteList.add(experimentId); //删除旧表数据 final int defaultDelNum = 1000; if (deleteList.size() == defaultDelNum) { deleteInbatch(connection, p, deleteList, tableNameOld); deleteList.clear(); } } } //删除旧表数据 if (deleteList.size() > 0) { deleteInbatch(connection, p, deleteList, tableNameOld); } } 总结

以上为我们所做的一致性hash实践,其中还存在很多问题,比如迁移过程单线程导致迁移较慢、自动扩容机制不智能、迁移过程中数据访问不稳定等情况。

我们将会在后续的开发中逐步进行完善改进。

以上就是我们针对一致性hash在oracle分表中的实践

参考

一致性哈希算法原理
ketama算法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjfsy.html