ShardingSphere笔记(一): 使用经验总结

文章目录

  • ShardingSphere笔记(一): 使用经验总结
    • 一、背景
      • 框架选择
    • 二、ShardingSphere-jdbc 只是一个帮助你路由的框架(踩坑总结)
      • 1. 它默认会认为你配置的所有的节点都是存在的
      • 2. 利用分表算法做动态数据库是不太现实的
      • 3. 查询语句不能使用关键字
      • 4. 其他小坑
        • 1. Compatible version of org.apache.shardingsphere.infra.util.yaml.constructor.ShardingSphereYamlConstructor$1
    • 三、 封装框架
      • 技术点介绍安排

这篇文章里面只简单总结一些使用ShardingSphere的个人经验,具体的技术实现可以看后面的文章。

先叠个甲,这里面提到的一些解决方案是针对我们的项目总结出来的,可能并不适用于所有情况,算是一个思路。具体场景还需要具体分析。如果各位大佬有更好的解决方案欢迎讨论。

一、背景

公司之前的项目中,所有的历史数据都是使用单表进行存储的,随着历史数据越积越多,有的历史数据表中的数据已经到了上亿条数据,数据的查询就成了一个很大的问题。

以往的时候,除了历史数据查询操作历史数据表的情形比较少,很多数据的查询走的都是抽样表和近期表。但是随着功能的不断扩展,需要从历史数据中分析更多的东西,这时候分库分表就是一个很迫切的需求了。

框架选择

当时我们有两种选择,一个是 mycat、一个就是shardingsphere。
mycat是代理数据库访问,可以看成是一个数据库代理。
而shardingsphere提供了两个项目,一个shardingsphere-jdbc, 一个是shardingsphere-proxy。看名字就能看出来一个是提供jdbc驱动类的jdbc增强库。另一个就是类似于 mycat 的数据库代理了。

经过查询一些资料我更倾向于shardingsphere-jdbc来做数据库分表。原因如下:

  1. 我们的项目不是类似于互联网那种提供云服务的项目,而是需要打包卖给很多客户的。考虑到部署与维护,架构需要尽量减少维护环节。
  2. shardingsphere 也提供了代理端的项目,如果使用 shardingsphere 来做,将来想要切换到代理数据库的实现方式切换成本也会比较小。
  3. shardingsphere 作为 Apache的顶级项目,框架稳定性方面会更信任一些。
  4. Mycat官网的文档真的欣赏不来,反而shardingsphere管网的文档很漂亮。

二、ShardingSphere-jdbc 只是一个帮助你路由的框架(踩坑总结)

这是我在使用和封装框架的过程中一个坑一个坑总结到的最深刻的经验。那就是ShardingShpere没有我们想象的那么智能,在数据分片中,它只是负责帮你去路由。

在这里我们需要先理解ShardingSphere是怎么来做路由的。他通过代理 jdbc,在sql查询的时候通过解析sql,找到你想要查询的表。然后根据你配置数据库表的分片算法根据对应的列找到应该从哪些数据库、哪些数据表中查询数据。

所以这是为什么它会存在很多限制:

  1. 存储过程不支持。(存储过程可以理解成在数据库端存储的封装好的函数,鬼才能从函数名解析到你想要查那个数据库呢,就算解析到了也改不了你的存储过程内容)
  2. 分片列的函数,对分片列的函数同样无法应用分片算法。
  3. 查询需要待分片列,如果不带分片列就没办法走分片算法,那么就会出现全表查询,所有表都要过一遍,尤其当存在join的时候,甚至存在笛卡尔积的查询次数。效率极差。

这还意味着:

1. 它默认会认为你配置的所有的节点都是存在的

就像上面说的,框架没有那么智能,它会认为你既然都让我路由了,那你所有的表都应该存在才是。所以忽略了这个情况就可能会出现一些莫名其妙的问题。以我踩过的坑为例。

我们是需要按月分表的,而按月分表我们又不想一次性建好那么多表,要不然数据库突然多了那么多空的数据表,管理也很麻烦。

所以来看看大聪明是怎么想办法解决这个问题的呢?

spring:shardingsphere:datasource:# ....rules:sharding:tables:# 需要分片的数据库表test_data:# 大聪明觉得我一次性配置了200年的表规则,就可以一次性配置一劳永逸了吧,哈哈actual-data-nodes: ${['ds1', 'ds2']}.test_data_${2018..2200}0${1..9}, ${['ds1', 'ds2']}.test_data_${2018..2200}0${10..12}table-strategy:# ....

这里,一次性配置了200年的数据表规则,但是数据库里面其实没有这么多的表。测试运行没问题。但是现实非常露骨,不仅露骨还会用骨头啪啪打脸。不出所料报错了。空指针异常。

在 Shardingsphere 5.2 版本以上是 ShardingSphereSchema.getColumns 空指针

在5.1 版本之前报错信息时 TableMetaData.getColumns 空指针

为什么会出现这个异常?查了官方的Issure,官方的回复统一都是检查一下 actual-data-nodes然后关闭了Issue, 所以后来在确保所有的真实表都存在之后这个问题才没有。

出现这个问题的原因就是:Shardingsphere默认认为你的真实表都应该是存在的,而且它不确定逻辑板是否存在,而且正常情况下逻辑表都是不存在的,在项目启动的时候它会去刷新Metadata,就是表的描述信息,但是因为大聪明为了一劳永逸配置了不存在的表,导致框架读取不到表信息。

2. 利用分表算法做动态数据库是不太现实的

这里又是一个踩的坑,我们的项目是这样的,有很多的数据源,每一个数据源中的历史数据表是需要分表的。我就想,我岂不是可以利用分片算法来切数据库吗?

于是我就有了下面的实现,我写了一个 数据库的分片算法,这里不做任何逻辑,利用 ThreadLocal 来确定使用哪一个数据库。

/*** 动态数据库的分库算法** @author wangp*/
public class DynamicDataSourceShardingAlgorithm implements StandardShardingAlgorithm<String> {/*** 需要手动指定数据库, 因此这里使用 ThreadLocal 来记录当前的数据库*/private static final ThreadLocal<String> currentDataSource = new TransmittableThreadLocal<>();private Properties properties;@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {String dataSource = currentDataSource.get();if (dataSource == null) {throw new IllegalStateException("Illegal data source !!!");}for (String availableTargetName : availableTargetNames) {if (Objects.equals(availableTargetName, dataSource)) {return dataSource;}}throw new IllegalStateException("Un knows data source :" + dataSource);}@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<String> shardingValue) {return Collections.singletonList(doSharding(availableTargetNames, (PreciseShardingValue) null));}@Overridepublic String getType() {return "DATASOURCE_SPI_BASED";}public static void setCurrentDataSource(String dataSource) {currentDataSource.set(dataSource);}public static String getCurrentDataSource() {return currentDataSource.get();}@Overridepublic Properties getProps() {return properties;}@Overridepublic void init(Properties properties) {this.properties = properties;}
}
spring:shardingsphere:rules:sharding:default-database-strategy:standard:sharding-algorithm-name: dynamic_ds_shardingsharding-column: acquisition_timesharding-algorithms:his_month_sharding:type: HIS_DATA_SPI_BASEDdynamic_ds_sharding:type: DATASOURCE_SPI_BASED

然后想要使用哪一个数据库,就手动调用 DynamicDataSourceShardingAlgorithm.setCurrentDataSource(‘ds1’) 就可以切换到数据源ds1。诶嘿。

经过测试确实可以却换不同的数据源,但是很明显,大聪明又踩坑里面了
分表的数据表通过这种方式没有问题,因为分表的数据查询肯定会走这个分表算法,那单表呢?。单表不走这个算法,那说明它失效了。结果显示单表只走了一个数据库,这和我们的初衷是不一致的。

这就要提到shardignsphere的另一个默认的规则了。那就是 ShardingSphere是一个做分库+分表的框架,而不仅仅是做分表的框架,它会认为你配置给分表配置的数据源对他们来说都是生效的,而没有配置的分表,抱歉我们单表我们为什么要走路由逻辑?与路由理念不一致

没办法研究它的文档和源码吧,结果研究了一圈没看到单表如何做路由,很明显在做无用功。因为单表配置 SingleTableRuleConfiguration 是一个final类,而且只有一个setDefaultDataSouce和getDefaultDataSource 方法,不允许你扩展也不允许你设置多路由。

所以最后放弃了这种做法,采用 SpringBoot 的 AbstractRoutingDataSource + ShardingSphere实现的动态数据源与数据库分表, 后面发现这种方式实现还有一种好处,众所周知,SardingSphere 不支持很多sql原生语句,那么在创建动态数据源的时候把原生的数据源和SharingSphere数据源一块加进去,想用哪一个用哪一个,丝般顺滑

更重要的是,利用这种方式还可以解决一个痛点,按月分表需要动态创建表,利用原生JDBC的datasource就很容易做到。而ShardingSphere的数据源却没有办法做到

这里提另一坑,官方给了一个强制路由的工具类,HintManager,可以设置走哪一个数据源,但是,强制路由,顾名思义,强制走路由,也就意味着使用了它你的分片算法就会失效,所以谨慎使用。

3. 查询语句不能使用关键字

封装完成框架,满心欢喜的运用到项目中,又又又报错了。熟悉的NullPointerException,心中一万只草泥马飘过 ~~~~~~~~~

经过追报错源码,原来是字段不能有关键字,因为Sharedingsphere 是基于sql解析来做路由的,所以对关键字要求比较高。
至于为什么要说这个坑,是因为使用mybatis框架的时候,报了这个错误他只提示你NPL异常,把报错信息给吞了,追了大半天报错堆栈才在原始的报错位置没有被传递出去的报错信息。no viable alternative at input sql, 最终报错到控制台的却是可怜的 Caused by: org.apache.shardingsphere.sql.parser.exception.SQLParsingException: null,不追代码鬼能知道是因为关键字的原因。

4. 其他小坑

1. Compatible version of org.apache.shardingsphere.infra.util.yaml.constructor.ShardingSphereYamlConstructor$1

5.2 版本及以上会出现这个问题,因为需要的解析yaml文件的库版本不满足框架要求,pom文件中的 properties位置 调整yaml版本号即可(Springboot框架自带了这个框架,不需要重新引用)。

<properties><snakeyaml.version>1.33</snakeyaml.version>
</properties>

三、 封装框架

根据我们的业务特性,我封装了我们公司使用的分表分库框架,利用Springboot spi 提供自动注入。维持原本的SardingSphere-jdbc-core-spring-boot-starter 配置不变,提供下面的功能。

  1. 根据配置自动配置历史数据的按月分表
  2. 无需配置真实数据表,框架启动后会根据路由判断真实表是否存在,真实表不存在自动创建表。(查询语句不创建表,否则将会导致大量空表)
  3. 动态切换数据库
  4. 提供原生jdbc数据源切换与shardingsphere数据源切换,方便执行一个存储过程(为了兼容老项目,新项目不太建议存储过程了,维护麻烦)。

技术点介绍安排

因为由于这里的分表逻辑是和我们公司业务相关性比较强,而且使用场景非常有限,但是里面的这几个技术点我这几天准备分几个部分写几个博客来一一介绍。

  1. ShardingSphere 怎么做自定义分表算法(以按月分表为例)
  2. 怎么做到路由查询自动创建表(以按月分表为例)
  3. ShardingSphere 整合 Springboot AbstractRoutingDataSource 做动态数据源于提供原生JDBC数据源。

ShardingSphere笔记(一): 经验和踩坑总结相关推荐

  1. ORB-SLAM3笔记(编译、踩坑、论文、看代码)

    目前基于orb_slam想做的方向 提升动态建图精度                (中个二区趴秋梨膏  √东西MAP就是上不去 KITTI有几个groundtruth官网下架了找不到而且 红外相机退 ...

  2. drupal笔记之block缓存踩坑

    今天有一个功能:在特定页面的footer内容会产生变化 当前footer是使用block做的,放置在footer的,这样所有页面的footer都是一样的.现在页面pageA的footer需要也其他页面 ...

  3. Drupal9笔记之block权限踩坑

    问题浮现: 网站为双语言,默认为en,第二语言为中文. 我创建了一个block,然后再创建翻译的中文bublock时,因为开启了workflow,第一次是审核状态.当我进入block list的时候, ...

  4. 小红书素人KOC素人笔记种草传播如何做到专业不踩坑?

    说起精致女生必备的APP,小红书必须有名字.在小红书上,大量的普通用户分享自己的生活经验.好物体验心得,涵盖美妆.护肤.美食.亲自.烹饪等等,他们的笔记组成了小红书的核心内容,而他们生产内容的商业价值 ...

  5. Vue 踩坑笔记: 引入 ElementUI 时打包失败修复记录(ERROR in ./node_modules/element-ui/lib/theme-chalk/index.css)

    Vue 踩坑笔记: 引入 ElementUI 时打包失败修复记录(ERROR in ./node_modules/element-ui/lib/theme-chalk/index.css Module ...

  6. 口罩、安全帽识别比赛踩坑记(一) 经验漫谈及随想

    前言 因为疫情迎来的史无前例大假期,从开始理直气壮的天天划手机,到中间百无聊赖的躺尸,再到之后实在憋得慌,就想找点什么事搞一搞.恰好这时,一直关注的极视角联合 Intel 公司举办了一个对口罩和安全帽 ...

  7. HBase眼高手低从Shell到IDEA编程、心路笔记、踩坑过程

    HBase眼高手低从Shell到IDEA编程.心路笔记.踩坑过程 HBase眼高手低 通过shell操作Hbase Foundation 在terminal中输入hbase,就可以查看hbase命令的 ...

  8. 修改 framework 代码的经验和踩过的坑

    点击打开链接 修改 framework 代码的经验和踩过的坑 1 经验 源码主要目录结构 目录 子目录 子目录 描述 android/frameworks/base core java/com/and ...

  9. iphone se 一代 不完美越狱 14.6 视频壁纸教程(踩坑笔记)

    iphone se 一代 不完美越狱 14.6 加 视频壁纸教程-踩坑笔记 越狱流程 1.爱思助手制作启动u盘 坑点: 2.越狱好后 视频壁纸软件 1.源 2.软件安装 越狱流程 1.爱思助手制作启动 ...

最新文章

  1. html 模板引擎 热部署,springboot系列四、配置模板引擎、配置热部署
  2. 计算机专业和学历的关系!!重要!!
  3. 基于VTK的MFC应用程序开发(1)
  4. 【Python】skimage模块
  5. 如何使用阿里云ARMS诊断Java服务端报错问题
  6. 可观测性PHP秩判据,线性系统的可控性与可观测性
  7. 地址html后面传参,JS中获取地址栏url后面的参数的三种方法
  8. 基于FairMOT的车流量统计
  9. 蛮牛精选七款Unity插件
  10. IMAX Enhanced:让沉浸式家庭影音娱乐体验不再抽象
  11. 光驱位改装固态硬盘并装win 和linux双系统
  12. FME会员期刊(2012冬季版)
  13. linux分区btrfs,Linux文件系统之btrfs
  14. 6.1 手机时钟系统简介
  15. 开源无线充电恒功率硬件电路
  16. PDF预览完整解决方案及各种兼容(VUE版)
  17. codeforces 584E
  18. 《ThinkPHP 5实战》4个实战开发案例可从代码仓库下载
  19. CVE-2018-5767 Tenda路由器栈溢出漏洞复现
  20. 青少年CTF-弱口令实验室招新赛个人wp

热门文章

  1. 广西大学计算机调剂信息2021,广西大学2021年考研可调剂的专业和人数一览
  2. 如何防止网站被恶意骚扰
  3. 计算机中的用户内存容量,按照 《2010 通则 》 ,以 CIF 汉堡条件成交,卖方对货物风险应负责...
  4. Java Class 是什么
  5. Bluedroid协议栈BTU线程处理HCI数据流程分析
  6. 9 项目资源管理 人人都是项目经理系列(第9/13篇)
  7. VS Code配置使用 LaTeX
  8. matlab粒子群算法求解无约束最小值,pso matlab粒子群算法和遗传 是解决约束优化问题,无 和多目标 的优 259万源代码下载- www.pudn.com...
  9. 邻接矩阵用c语言,邻接矩阵无向图(一)之 C语言详解
  10. 某钢厂脱硫系统智能化超低排放改造设计