• 拥抱新技术?你需要考虑的方面


    前言

    大家好,本文是博主在负责对企业项目新技术引入时,考虑不周的点,文中以第一视角对整个过程进行复盘以及事后分析。以 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 后拉取到本地。找到官方写的按月分表的类后,我也照着原有的代码,写了一个按时间戳分表的类,将其编译后,放入中间件源码包内,并配置分表规则。具体可以看我之前写的博客。

    Mycat实现单库水平分表、按月分表:

    https://micromaple.blog.csdn.net/article/details/125395498
    
    • 1

    四、方案制定

    此时按时间戳分表方式我们也解决了。但是面临一个问题,就是 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")
    @Slf4j
    public 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";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Service层

    public interface OrderService {
    
        public int save(Order order);
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Service实现

    @Service
    @Slf4j
    public 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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Mapper层

    @Mapper
    public interface OrderMapper extends BaseMapper<Order> {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    日志输出

    开始保存数据
    插入数据==>1
    
    • 1
    • 2

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

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

    6.3、寻找解决方案

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

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

    我:你们以前用过 Mycat 吗?

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

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

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

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

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

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

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

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

    6.4、最终方案

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

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

    七、总结

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

    • 学习一个新技术,只关注眼前,只听别人说有多好用,自己怀着猜想的方式去学习,别人说可以这样,殊不知还有很多坑等着自己去踩。
    • 在引入一个新的技术点,尤其是针对数据源的这类技术,考虑不全面,没有对整个项目的使用场景进行一个充分的测试。
    • 对技术的关注度不够,技术点是否有巨大变动,完全不知。
    • 技术广度不够,对于自己学习的技术,没有形成一个知识网络,导致技术选型的时候,没有方案可选。

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

  • 相关阅读:
    YOLOv7训练自己的数据集(超详细)
    如何在Access2007中使用日期类型查询数据
    【Linux】Systemd 中的单元(Unit)和单元文件(Unit File)怎么理解?
    深度学习入门(五十六)循环神经网络——循环神经网络RNN
    Pytorch利用ddddocr辅助识别点选验证码
    Android中eBPF使用原理以及 kprobe dmabuf_setup实例
    15、Mybatis获取参数值的情况1(mapper接口方法的参数为单个字面量类型)
    2023上半年薪资报告出炉!人均月入过万?!
    python合集1
    java 三元运算符
  • 原文地址:https://blog.csdn.net/qq_41779565/article/details/126282841