文章来源:爱可生开源社区

作者:钟悦

作者简介

钟悦,就职于某大型国有银行,多年从事MySQL和分布式中间件的方案设计与实施工作;资深MySQL数据库专家,架构师;DBLE开源项目积极贡献者。

文章概要

DBLE默认支持数十种数据拆分算法,基本能满足大部分的社区用户的使用需求;为了满足更广的业务场景,DBLE还支持更加灵活的自定义拆分算法;本文对面向有类似需求的DBLE开发者,提供了一个如何开发和部署自定义的拆分规则的一个指引

目录

1. 工作原理

  • 1.1 函数的加载

  • 1.2 路由计算

  • 1.3 参数查询

2. 开发和部署

  • 2.1 开发

  • 2.2 部署

3. 接口规范

  • 3.1 配置项setters

  • 3.2 selfCheck()

  • 3.3 init()

  • 3.4 calculate()和calculateRange()

  • 3.5 getAllProperties()

4. 内置路由函数的缩写与类名对照表

1. 工作原理

1.1 函数的加载

路由函数的加载发生在DBLE启动或重载时。

  • DBLE读取rule.xml时,根据用户配置的标签的class属性
  • DBLE通过Java的反射机制,从$DBLE_HOME/lib的jar包中,找到对应的jar(里的class文件),加载同名的类并创建对象

  • DBLE会逐个扫描中的标签,并根据name属性来调用路由函数的对应setter,以此完成赋值过程——例如,如果用户配置了2,那么DBLE就会尝试找路由函数中叫做setPartitionCount()的方法,并将字符串“2”传给它

  • DBLE调用路由函数的selfCheck()方法,执行函数编写者制定的检查动作,例如检查赋值得到的变量值是否有问题

  • DBLE调用路由函数的init()方法,执行函数编写者制定的准备动作,例如创建后面要用到的一些中间变量

1.2 路由计算

路由函数接受用户SQL中的分片字段的值,计算出这个值对应的数据记录应该在哪个编号的数据分片(逻辑分片)上,DBLE从而知道把这个SQL准确发到这些分片上。

1.3 参数查询

用户通过管理端口(默认9066),通过SHOW @@ALGORITHM WHERE SCHEMA=? AND TABLE=?来查询表上的路由算法时,DBLE调用路由算法的getAllProperties()方法,直接从内存中获取路由信息的配置。

mysql> show @@algorithm where schema=testdb and table=seqtest;
+-----------------+----------------------------------------------------+
| KEY             | VALUE                                              |
+-----------------+----------------------------------------------------+
| TYPE            | SHARDING TABLE                                     |
| COLUMN          | ID                                                 |
| CLASS           | com.actiontech.dble.route.function.PartitionByLong |
| partitionCount  | 2                                                  |
| partitionLength | 1                                                  |
+-----------------+----------------------------------------------------+
5 rows in set (0.05 sec)

2. 开发和部署

2.1 开发

开发时,理论上只需要引入AbstractPartitionAlgorithm抽象类和RuleAlgorithm接口及它们的依赖类就可以了。但实际上AbstractPartitionAlgorithm抽象类依赖了TableConfig类,由此开启了环游世界的依赖之旅。因此,现实的操作还是引用整个DBLE项目的源代码会比较直接方便。

开发一个新的路由函数时,必须给这个路由函数的开发新建项目,然后再引用DBLE项目(项目引用项目的方式)。而不应该直接打开DBLE的项目,然后在DBLE的项目里面直接新建源代码来直接开发(内嵌开发方式)。通过遵循这个做法,会有以下好处:

  1. 路由函数可以独立打包,直接去看路由函数的jar包版本就能够确认函数版本;而把路由函数嵌到DBLE里的话,就很容易出现DBLE版本一样,但不清楚里面的函数是什么版本的窘况
  2. 路由函数的递进可以更加自由,如果DBLE的AbstractPartitionAlgorithm抽象类和RuleAlgorithm接口没有变动,同一版本的路由函数可以延续使用好几个版本的DBLE,而不需要每次DBLE释放新版就得去重编译

  3. 可以让路由函数中的受保护代码免受DBLE自身的开源协议影响

2.2 部署

完成开发之后,成品打包成jar包进行发布,而不要直接发布class和依赖的library(其他项目的jar包或class文件)。

让DBLE使用上新的路由函数的过程:

  1. 将成品jar包放入$DBLE_HOME/lib目录中
  2. 调整jar包的所有者权限(chown)和文件权限(chmod),使之与其他$DBLE_HOME/lib目录里的jar包一样

    | 请注意:2.18.12.0及以后版本建议放在algorithm目录下,用于区分原生lib和自定义lib,便于管理

  3. 按照原来的思路配置rule.xml,但需要注意标签的class属性必须要填写新的路由函数类的完全限定名(Fully Qualified Name),例如net.john.DBLE.route.functions.NewFunction

  4. 配置逻辑表之类的必要信息,重启DBLE后,自动生效。

3. 接口规范

每个路由函数本质上就是一个继承了AbstractPartitionAlgorithm抽象类,并且实现了RuleAlgorithm接口的一个类。下面以内置的com.actiontech.DBLE.route.function.PartitionByLong为例,介绍实现一个路由函数类所需要做的最小工作(必要工作)。

3.1 配置项setters

在rule.xml中,我们需要配置partitionCount和partitionLength两个配置项。

<function name="hashmod" class="com"><property name="partitionCount">4</property><property name="partitionLength">1</property>
</function>

为了让DBLE在函数加载过程中,能够认出这里的partitionCount(值为4)和partitionLength(值为1),因此PartitionByLong类中,就必须有属性设置方法(setter)setPartitionCount()和setPartitionLength()。而因为rule.xml是个文本型的XML文件,所以这些函数的传入参数就只能是一个String,数据类型转换和预处理的动作就由这些setter来处理了。

public void setPartitionCount(String partitionCount) {this.count = toIntArray(partitionCount);/* 参考本文的getAllProperties()的说明 */propertiesMap.put("partitionCount", partitionCount);
}public void setPartitionLength(String partitionLength) {this.length = toIntArray(partitionLength);/* 参考本文的getAllProperties()的说明 */propertiesMap.put("partitionLength", partitionLength);
}

3.2 selfCheck()

在函数加载过程中,完成了配置项赋值之后,DBLE会调用这个路由函数对象的selfCheck()方法,让这个对象自我检查刚才读进来的配置项的值,放在一起是不是有问题。如果有问题的话,路由函数编写者在这时候,可以通过抛出RuntimeException来进行报错,并终止DBLE使用这个函数,当然,由于RuntimeException的霸道,DBLE自己也会因此而报错退出。

由于selfCheck()是RuleAlgorithm接口的要求,而且AbstractPartitionAlgorithm抽象类没又实现它,对于想偷懒或者没有必要进行这个检查的人来说,还是需要自行定义一个空的同名方法来实现它。

@Override
public void selfCheck() {
}

3.3 init()

在函数加载过程的最后,DBLE调用这个路由函数对象的init()方法,让这个对象完成一些内部的初始化工作。

在我们的例子PartitionByLong里,通过init()方法准备了PartitionUtil对象,其中有一个哈希值的范围与逻辑分片号对应的数组,这样在后面的路由计算时就能通过查数组来加速得到结果。

3.4 calculate()和calculateRange()

DBLE执行用户SQL时,根据用户SQL的不同,调用calculate()或calculateRange()来确定用户的SQL应该发到哪个数据分片上去。

从IPO(Input-Process-Output)来分析,calculate()和calculateRange()的工作原理是一样的:

  • Input:用户SQL中的分片字段值
  • Output:用户SQL应该要发往的数据分片的编号
  • Process:Input与Output转换的计算过程,由函数开发者编写

calculate()和calculateRange()的使用场景不同,导致它们存在着一些微小的差异。

函数名 调用场景 Input Output
calculate() 用户SQL里分片字段的值是单值的情况,例如 … WHERE sharding_key = 1 1个String 1个Integer
calculateRange() 用户SQL里分片字段的值是连续范围,例如 … WHERE sharding_key BETWEEN 1 AND 5 2个String Integer数组
@Override
public Integer calculate(String columnValue) {try {if (columnValue == null || columnValue.equalsIgnoreCase("NULL")) {return 0;}long key = Long.parseLong(columnValue);return calculate(key);} catch (NumberFormatException e) {throw new IllegalArgumentException("columnValue:" + columnValue + " Please eliminate any quote and non number within it.", e);}
}@Override
public Integer[] calculateRange(String beginValue, String endValue) {long begin = 0;long end = 0;try {begin = Long.parseLong(beginValue);end = Long.parseLong(endValue);} catch (NumberFormatException e) {return new Integer[0];}int partitionLength = partitionUtil.getPartitionLength();if (end - begin >= partitionLength || begin > end) { //TODO: optimize begin > endreturn new Integer[0];}Integer beginNode = calculate(begin);Integer endNode = calculate(end);if (endNode > beginNode || (endNode.equals(beginNode) && partitionUtil.isSingleNode(begin, end))) {int len = endNode - beginNode + 1;Integer[] re = new Integer[len];for (int i = 0; i < len; i++) {re[i] = beginNode + i;}return re;} else {int split = partitionUtil.getSegmentLength() - beginNode;int len = split + endNode + 1;if (endNode.equals(beginNode)) {//remove duplicatelen--;}Integer[] re = new Integer[len];for (int i = 0; i < split; i++) {re[i] = beginNode + i;}for (int i = split; i < len; i++) {re[i] = i - split;}return re;}
}

3.5 getAllProperties()

当用户找DBLE要路由函数的配置信息时,DBLE通过访问路由函数的getAllProperties()来获得一个<配置项, 配置值>的哈希表,然后将里面的内容逐项返回给用户。

getAllProperties()是RuleAlgorithm接口所规定要实现的,但为了简化编写新的路由函数的工作,在AbstractPartitionAlgorithm抽象类里,定义了propertiesMap这个私有变量,并且把“将propertiesMap交出去”作为了实现了getAllProperties()方法的默认实现。

一般来说,这个默认的实现能满足需求,而新路由函数编写者只需要在配置项setters处理用户配置时,将<配置项, 配置值>给put()进propertiesMap里就好了。

@Override
public Map<String, String> getAllProperties() {return propertiesMap;
}

4. 内置路由函数的缩写与类名对照表

DBLE内置的路由函数都位于com.actiontech.DBLE.route.function命名空间。但实际配置rule.xml的时候,却不用写那么长的完全限定名,这其实都是XMLRuleLoader类做了转换,因此实现了简写。下面就是7个内置函数的类名和它们的简写。

简写名

完整类名
date PartitionByDate
enum PartitionByFileMap
hash PartitionByLong
jumpstringhash PartitionByJumpConsistentHash
numberrange AutoPartitionByLong
patternrange PartitionByPattern
stringhash PartitionByString

社区投稿 | DBLE 自定义拆分算法相关推荐

  1. TF之LSTM:基于tensorflow框架自定义LSTM算法实现股票历史(1990~2015数据集,6112预测后100+单变量最高)行情回归预测

    TF之LSTM:基于tensorflow框架自定义LSTM算法实现股票历史(1990~2015数据集,6112预测后100+单变量最高)行情回归预测 目录 输出结果 LSTM代码 输出结果 数据集 L ...

  2. DL之DNN优化技术:自定义MultiLayerNetExtend算法(BN层使用/不使用+权重初始值不同)对Mnist数据集训练评估学习过程

    DL之DNN优化技术:自定义MultiLayerNetExtend算法(BN层使用/不使用+权重初始值不同)对Mnist数据集训练评估学习过程 目录 输出结果 设计思路 核心代码 更多输出 相关文章: ...

  3. php 红包算法,PHP语言:实现微信红包拆分算法

    本文主要向大家介绍了PHP语言:实现微信红包拆分算法,通过具体的内容向大家展示,希望对大家学习php语言有所帮助. · 修复最后一个红包输出未保留2位数 · 修复领取的红包金额低于最小红包限制 * 红 ...

  4. 社区发现(一)--算法综述

    基础概念简介:https://baike.baidu.com/item/%E7%A4%BE%E5%8C%BA%E5%8F%91%E7%8E%B0%E7%AE%97%E6%B3%95/19460396 ...

  5. php分割金额_PHP实现红包金额拆分算法案例详解

    这次给大家带来PHP实现红包金额拆分算法案例详解,PHP实现红包金额拆分算法的注意事项有哪些,下面就是实战案例,一起来看一下.<?php // 新年红包金额拆分试玩 class CBonus { ...

  6. 计算机网络二分法划分网络,三种经典复杂网络社区结构划分算法研究_GN算法

    论文导读::复杂网络是复杂系统的高度抽象.即社区结构特性[3].算法是一种试探优化法[4].算法. 关键词:复杂网络,社区结构,Laplace图谱,Kernighan-Lin算法,GN算法 1引言 现 ...

  7. 第五章:Sharding-JDBC 自定义分片算法

    Sharding-JDBC 自定义分片算法 自定义分片算法 Sharding提供了以下4种算法接口 PreciseShardingAlgorithm RangeShardingAlgorithm Hi ...

  8. CK3M自定义伺服算法(C语言)开发的简单流程

    本文的章节安排如下 1 注意事项 2 自定义伺服算法(C语言)开发 2.1 Global Includes 2.2 C Language 2.3 编译并下载程序 2.4 控制器调试 3 运动程序 在导 ...

  9. 社区发现之标签传播算法(LPA)

    在Graph领域,社区发现(Community detection)是一个非常热门且广泛的话题,后面会写一个系列,该问题实际上是从子图分割的问题演变而来,在真实的社交网络中,有些用户之间连接非常紧密, ...

最新文章

  1. 求自定类型元素序列的中位数
  2. Python学习第四天----Linux之用户与用户组权限
  3. cannot be cast to org.springframework.web.accept.ContentNegotiationManager
  4. tsf php,TSF:腾讯推出的 PHP 协程方案
  5. python commands模块_python commands模块在python3.x被subprocess取代
  6. jQuery的顶级对象 $
  7. Py之face_alignment:face_alignment库的简介、安装、使用方法之详细攻略
  8. MyEclipse之安装SVN1.10.7
  9. SAP顾问,市场的双重需求
  10. 计算机网络(一)-概述(补充)
  11. LeetCode 135 分发糖果
  12. Emulator 29.2.12 稳定版发布,启用 Google Maps UI
  13. Trouble Shooting记录:服务 Microsoft Exchange Information Store 意外停止
  14. 分享一个自己写的基于TP的关系模型(2)
  15. struts2之自定义拦截器及拦截器生命周期分析
  16. 大数据分析师的报考条件是什么?
  17. 如何调整plt.plot()线的粗细,linewidth
  18. C# 五步完成Bmp文件流到AVI的转换
  19. Frame skipped from debugging during step-in. VSCode调试无法定位其它库中代码的解决办法
  20. 第三节 数据通信基础

热门文章

  1. 产业区块链发展周报(10.17—10.23)| 陀螺研究院
  2. android adobe pdf阅读器,Adobe发布Android手机专用PDF阅读程序
  3. 乔布简历:谁说我只是个简历模板库?
  4. html注册登录接口,API注册
  5. Ubuntu 7z安装
  6. 数据分析师的Windows装机必备软件
  7. 任天堂红白机 ( NES ) 文档
  8. zigbee无线传感网技术与应用开发v2.0_物联网通讯协议——Zigbee
  9. P3166 [CQOI2014]数三角形
  10. 认识无线网络之Wi-Fi