写点什么

开源一夏 | 拥抱新技术?你需要考虑的方面

  • 2022 年 8 月 11 日
    湖南
  • 本文字数:4301 字

    阅读完需:约 14 分钟

开源一夏 | 拥抱新技术?你需要考虑的方面

前言

大家好,本文是博主在负责对企业项目新技术引入时,考虑不周的点,文中以第一视角对整个过程进行复盘以及事后分析。以 Mycat 为例。希望对大家有所帮助~

一、背景

在一次会议内容提到一个新的技术,是我没有涉及到的领域—分库分表技术预研,当时会议提到该领域其中一个技术点 Mycat 技术点,该技术是我没有涉及到,而在此次会议被安排负责该项技术的预研。

二、需求

接下来,我就花时间去了解 Mycat这个东西,网上各种找资料,说实话,资料还是非常的多的,当时的想法就是满足现有的需求。当时 Leader 给我的任务是针对部分数据量大的表,进行单库分表。将这些需要分表的表按照月份进行分表。


比如订单表,将订单表分成:m_order_202201, m_order_202202, m_order_202203...


我就针对这个需求,去学习 Mycat 如何去实现按月分表。

三、Demo 环境搭建

每学习一个新的技术点,亦或是引入一个新的技术,需要将该知识点最简化。先搭建一个 Demo 出来,然后在基于 Demo 进行扩展。我觉得这样是可以充分的降低出现预期外的问题,使我们的学习、引入或集成更加的轻便。


很快,我在网上下载好了 Mycat 的程序,进行按月分表的实操。


一切从简,我首先是创建了一个测试表,表里总共两个字段,在 Mycat 中配置使用很简单的针对日期分表的规则。此时是很成功的,内心是无比的喜悦,觉得这个东西也没啥,非常简单。当天就快快乐乐的下班啦~

3.1、初遇问题

然而,第二天上班的时候,我发现一个问题,就是原有 Mycat 程序提供的按月分表,仅支持 datedatetime 字段类型的分表。我们的订单表(m_order)的创建时间(created_time),是bigint类型的,也就是我们插入的创建时间是一个时间戳,而 Mycat 对时间戳方式的分表是不支持的,此时我上网找了半天,也没有针对时间戳进行分表的方案。

3.2、解决问题

突然想到 Mycat 是开源的,我是不是能增加一个按时间戳分表的方式呢?

说干就干,马上在 GitHub 上找到 Mycat 的源码,Fork 后拉取到本地。找到官方写的按月分表的类后,我也照着原有的代码,写了一个按时间戳分表的类,将其编译后,放入中间件源码包内,并配置分表规则。

四、方案制定

此时按时间戳分表方式我们也解决了。但是面临一个问题,就是 Leader 是否允许咱们这样做?

临时做了几个方案,将其汇报给了 Leader ,看是否开会讨论一下方案。方案如下:


  • 方案一:

  • 在需要分表的表中增加一个字段,例如插入时间(insertDate)类型为 datetime 或者 date,根据该插入字段进行分表。

  • 优点:满足现有分表规则,不需要修改中间件源码。缺点:需要修改代码,插入的时候,需要增加插入时间字段。

  • 方案二:

  • 修改源码,增加适配时间戳分表方式。

  • 优点:最大程度降低了代码和中间件的耦合度,代码几乎不需要进行更改。缺点:由于是自己写的分库(或分表)规则,对于以后中间件的升级不友好。

  • 方案三:

  • 按范围分表,提前规划好分表字段某个范围属于哪个分表。

  • 优点:满足现有分表规则。缺点:根据时间戳配置麻烦。

  • 方案四:

  • 选择其他分表方式,根据其他字段及规则进行分表。例如:取模。

  • 优点:易于配置。缺点:所有的表都会用起来,数据散列分布。


将这四个方案提给 Leader 后,跟 Leader 讨论后。 Leader 觉得不更改中间件源码,采用方案一,增加字段来进行分表。


原因就是觉得更改源码后,后续升级会比较麻烦。但是我觉得增加字段有点麻烦,此时这个分表的事情也不紧急,我就去问了一下 Mycat 的官方开发人员。如下图:


五、实战-项目集成

突然有一天下午,我们有一个地方项目爆出 MySQL 突然挂了,怎么也启动不起来,后面我们排查后发现是表损坏了。第二天上午,我们 Leader 就跟我们开了一个会,说单表数据量太大了,Mycat 分表这个得提上日程了,刚好最近有一个地方项目要进行升级,顺便就把这个 Mycat 分表的推上去用。接下来我就拉取了一个 Mycat 的分支版本,并搭建配置 Mycat 版本的环境。

5.1、再遇问题

我们将其配置好后,发现项目启动后疯狂报错,各种 SQL 不兼容的问题,当时我人都懵了。


经过排查,发现我们原先引入的 Activity 工作流完全没办法用了,里面一些内置的 SQL 是不支持的。这块我是考虑不周的,没有对 SQL 进行充分的兼容测试。当天下班,我都在自责。


然后我马不停蹄的去总结了一些 SQL 不兼容的地方。如下:


  • 增加(insert)

  • insert 插入的时候必须要带字段名,必须带分表字段

  • insert into x select from y 的 sql 语句不被支持

  • 删除(delete)

  • 支持子查询删除方式 delete from a where a.id in (select id from b), 但表不能起别名

  • 修改(update)

  • 不支持多表更新

  • 分表字段不能被更新

  • 查询(select)

  • select 中 DISTINCT 不支持对 a.*的查询

  • distinct 和 select 查询列中用子查询的会冲突,二者选其一

  • 子查询 where 条件中不支持使用 or

  • 查询最好能够按照分表字段,否则查询效率不是太好

  • 关于 order by 排序,Order by 后的排序字段必须是 select 的一部分,查询全局表的时候除外


然后我马不停蹄的将其汇报给 Leader ,并说明了我在这块考虑不周全,没有做好。

5.2、总结问题

此时我的问题已经很明显了。对新技术没有进行充分的了解和熟悉,没有对此项技术进行充分的测试,没有考虑到新技术引入进来所带来的耦合度的提升。各种各样的原因吧,没有考虑清楚。

六、持续引入集成

到这里了,大家可能会很好奇,为啥有这么多不支持的点了,还要继续引入呢?


结合当时的项目和业务使用场景,以及 Leader 对 Mycat 技术栈的信任,工作流模块是可以直接干掉的(因为这个东西没有什么人用)。我们就开会讨论,后续如何的集成 Mycat 分表;此时我们已经消耗了大半个月的时间了。紧接着我们就评估集成后的改动工作量。我和另一位后端同学评估出来的工作量大概是 10 个工作日,随后 Leader 就协调了一位后端同学跟我一起改,协调了另外一位测试同学帮助我们测试。

6.1、项目改动

集成 Mycat 后,项目 SQL 改动进行的如火如荼。发现了很多改动都是差不多的,大部分都是在子查询中加了 OR 的条件查询,改动起来也很快。


遇到一些查询结果不一致的,还需要在代码中调整。例如,连表查询统计数量的时候,我要统计近七天的数据,Mycat 会将每一个分表后的表的这个日期都统计一遍。假设我统计 2022-01-01 到 2022-01-07 的数据,此时我的订单表(m_order)分成了 12 个表,那么 2022-01-01 会有 12 条数据,加起来就一共有 7*12 = 84 条数据。接着我们还要通过代码进行分组(还好这块 JDK1.8 的 stream 流操作丝滑)。在这之中,也将之前一些同事写的 bug 优化了~

6.2、致命问题

我和另一位后端同学正改的起劲的时,突然发现一个致命的问题,就是有一个地方进行新增操作的时候,增加了 Spring 的注解 @Transactional 导致业务层代码一直挂起,无法响应。这里分享出来,感兴趣的同学可以看一下。代码如下:


Controller 层

@RestController@RequestMapping("/order")@Slf4jpublic class OrderController {
@Autowired private OrderService orderService;
@PostMapping("/save") public Object save(Order order) { int save = orderService.save(order); log.info("保存完成==>" + save); if(save > 0) { return "success"; } return "fail"; }}
复制代码


Service 层

public interface OrderService {
public int save(Order order); }
复制代码


Service 实现

@Service@Slf4jpublic class OrderServiceImpl implements OrderService {
@Autowired private OrderMapper orderMapper;
@Override public int save(Order order) { log.info("开始保存数据"); int insert = orderMapper.insert(order); log.info("插入数据==>" + insert); return insert; }}
复制代码


Mapper 层

@Mapperpublic interface OrderMapper extends BaseMapper<Order> {
}
复制代码


日志输出

开始保存数据插入数据==>1
复制代码


Controller 层的日志一直没有输出,也就是进入到 Service 层执行完业务代码后,一直没有出来。此时我也不知道啥问题,应该也有人遇到这个问题吧,我就打开了 GitHub,在 Issues 检索,发现了这个。如下图:


当时想,不妨试试,反正要不了多少时间。结果,还真的可以了,数据也进入到数据库了,此时有些人可能觉得已经解决了这个问题,但是并没有。事务是何等的重要,没有事务,无法保证程序数据的一致性和完整性,这将是致命的大问题。

6.3、寻找解决方案

我在找了一周的解决方案后,没有找到一个合适的解决方案。例如:XA 事务,虽然可以回滚,但是经过测试,是非隔离的,会出现更多的问题。


之后,我跟一位朋友聊天时,问了问他以前是否使用过 Mycat?如下是我跟朋友的聊天,大家可以感受一下。


我:你们以前用过 Mycat 吗?

朋友:用过,是好几年前的事情了,但是几年前 Mycat 停更过后,也就再也没有使用过 Mycat 了。

我:之前公司使用过 ShardingSphere-JDBC,但是觉得跟代码耦合度太高了。

朋友:ShardingSphere 有好几种模式,一种叫 ShardingSphere-JDBC,属于 SDK 形式嵌入的,还有跟 Mycat 对标的 ShardingSphere-Proxy,这个才是独立的部署服务器的,就看咱们怎么用。


虽然短短几句,我意识到自己有很多的不足。技术广度不够,没有仔细的去比对各项同类技术,导致技术选型的时候出现了许多的问题。其次是对技术的关注度不够,Mycat 已经停更过,咱都不知道。


后续就是朋友建议我把 Spring 的 DEBUG 日志和 Mycat 的 DEBUG 日志打出来,分析看看。我到现在也没分析出来啥问题(手动难过)。


第二种就是同事建议我是否可以手动的去打开、提交或者回滚事务,也是行不通的,根本不回滚。


这个问题困扰了我很久,迟迟无法解决(手动头痛)。


GitHub 上也有很多类似的问题,一直没有得到解决


6.4、最终方案

后来实在是解决不了了,就跟 Leader 说明了情况,从各个方面演示这个问题,以及我针对这个问题找的解决方案。他也暂时没有好的解决方法。


当时项目有新需求需要紧急开发了,也不消耗时间去考虑其他分表方案了。最终决定后续可能采用数据归档的方式来处理。

七、总结

经历了这件事情,从开始到后面不完美的闭环,意识到了自己很多的不足:


  • 学习一个新技术,只关注眼前,只听别人说有多好用,自己怀着猜想的方式去学习,别人说可以这样,殊不知还有很多坑等着自己去踩。

  • 在引入一个新的技术点,尤其是针对数据源的这类技术,考虑不全面,没有对整个项目的使用场景进行一个充分的测试。

  • 对技术的关注度不够,技术点是否有巨大变动,完全不知。

  • 技术广度不够,对于自己学习的技术,没有形成一个知识网络,导致技术选型的时候,没有方案可选。


读到这里,想必你也学习到了博主的一些经验,不管是之后学习或是工作或是其他方面有帮助的话,别忘了三连支持博主呀~我是微枫 Micromaple,期待你的关注~💪💪💪

发布于: 17 小时前阅读数: 67
用户头像

还未添加个人签名 2020.11.11 加入

还未添加个人简介

评论

发布
暂无评论
开源一夏 | 拥抱新技术?你需要考虑的方面_开源_微枫Micromaple_InfoQ写作社区