我参与阿里巴巴 ASoC-Seata 的一些感悟

作者 | 侯志
来源|阿里巴巴云原生公众号

看一看日历
这个不同寻常的 2020 年,马上就要结束了。
这一年,有幸参与阿里巴巴组织 ASoC 活动,有一段让我难忘的不平凡经历。
这一年,却已可以称为是国际开源实习发展历程中不平凡的一年。

参与的起因

初心
Beginner’s mind

唯有守得住初心,才能日益精进。

我先来说说 Seata 这个项目的 idea 是怎么来的。一直就有参与开源项目的打算,一个事物的兴起必定或大或小引发一定的问题,微服务就是这样,分布式事务概念泛化的同时,也带来了一个技术问题,微服务架构下分布式数据一致性该如何保证?这几年涌现出不少分布式事务框架,比如 ByteTCC、TCC-transaction、EasyTransaction 以及最近很火爆的 Seata。想要破解罪恶,就必须接近它,甚至成为它。我是去年 8 月份从 GitHub 开始关注 Seata 项目的,初步熟悉后,我觉得它的设计理念非常好,并对它产生了浓厚的兴趣,那个时候就萌发了我要成为这个项目的贡献者。偶然的机会看到 Seata issue,发现了 ASoC 这个活动。

参与的过程

  • 有期待,更美好
    Expect better

在参与活动之前我就先从官方文档开始了解过 Seata ,并根据自己的了解,做了一些简单的梳理。看 Seata 源码,继续深入研究,更多的是关注于 SqlParser 模块,在这个过程中,我发现 SqlParser 模块是用 Druid 实现,(Druid 不过多介绍),且 Seata 对于 SqlParser 部分解析功能受限于 Druid,为了方便用户使用,Seata 更加灵活使用数据库语言解析, 有必要扩展一种新的 SqlParser 方案。由于之前有了解过 Antlr,感觉其更加灵活、拓展性更强、层次清晰更易维护。例如 Hive 和 Spark 使用 Antlr 生成词法语法解析器,Twitter 使用 Antlr 来解析用户输入的查询内容,Oracle 把 Antlr 的功能内嵌在 SQL 开发 IDE 中,NetBeans IDE 使用 Antlr 解析 C ++ 语言,也有公司使用 Antlr 来从文件中抽取信息等等…

Antlr 无疑是 Seata SqlParser 另一个更好的选择。于是我想把 Antlr 带到 Seata 中。

  • 迷惑
    Confuse   

在开发任务期间,Antlr 模块是一个 feature 的实现,涉及 Seata 关于数据库语言解析的一块(有前辈开发者使用 Druid 去处理相关数据库语言数据,因此我进行了 Druid 源码深入研究,基本类似于使用 Antlr 实现一种轻量级别的 Druid),而整个实现过程,太多的地方需要确定,包括实现数据库种类、Antlr 源文件、Antlr 模块划分,以及明确上下游 API 接口等等。在实现解析数据库每种语法语句的时候,比如 Mysql 新增语法,使用 Antlr Visitor 模式,并不兼容查询、修改、删除语法,不断打翻之前的代码,不断调试,甚至导致 Antlr 源文件变动(Antlr 官方提供的源文件过大,改动很头疼)。最终采用 Antlr 两种解析模式去解析。Listener 针对于查询、修改,删除语法包括批量操作,最终问题得以解决。

  • 顿悟
    Epiphany

字符串流重写 LA 遍历方法。这里使用 Antlr v4.0.0 字符串流重写 LA 遍历方法,否则大小写转换出错,调用 MySqlLexer 进行词法分析、CommonTokenStream 符号分析、MySqlParser 执行语法规则分析,调用我们自定义的 InsertSpecificationSql,visit 去遍历 Ast 树,把解析出的信息用 MySqlContext 展示。过程很简单,但是在实际过程中可能会遇到很多问题,比如新增语法、查询语法、修改语法、删除语法以及它们语法规则是否有通用性、实现的方法是否可以公用;不同的 sql 语法,是否同一个方法能支持;批量 sql 的话,怎么去处理等等问题。

在解析 mysql 原生 sql 语句时候,遇到这样一个问题,解析出的 sql 明明是对的,Ast 视图树中也正确,但是返回给客户会出现下面这种情况:

次.png

原生 sql 居然把空格都给省略掉,一开始我先执行 Ast 树,查询解析结果,发现没有问题,一激灵我想到不是有词法关键词吗,分析时候肯定是基于 Mysql 关键字的,然后把使用到 Mysql 关键词的字符加了空格,重写生成文件,发现是没有问题的。但这词法太多了吧,我都改掉解析会不会出现问题?果真好多解析出现了问题,导致 Seata 生成前后镜像出现问题。遇到事情不能急躁,冷静…它不是有 Ast 树吗,我在它遍历 Ast 树的时候给它加上空格不就好了吗?这样原生的词法文件根本不需要动,也不会引起后续问题,我赶紧阅读起了 Antlr java 源码,功夫不负有心人,果真找到了解决办法,我重写了 visitTerminal 方法:


@Override
    public StringBuilder visitTerminal(TerminalNode node) {
        String text = node.getText();
        if (text != null && !"".equals(text.trim())) {
            if (shouldAddSpace(text.trim())) {
                sb.append(" ");
            }
            sb.append(text);
        }
        return sb;
    }

    private boolean shouldAddSpace(String text) {
        if (sb.length() == 0) {
            return false;
        }
        char lastChar = sb.charAt(sb.length() - 1);
        switch (lastChar) {
            case '.':
            case ',':
            case '(':
                return false;
            default:
                break;
        }

        switch (text.charAt(0)) {
            case '.':
            case ',':
            case ')':
                return false;
            default:
                break;
        }
        return true;
    }

 

收获与体会

思维-编程能力

Thinking-programming ability

参与 Seata 过程中在社区认识了很多优秀的开发者,这些开发者很多是值得我去学习的,有不理解的地方我的前辈导师包括社区朋友都热心帮我解决。每个阶段完成后,都会有一个小的总结,还参与了 PR Code Review,学习到了开源项目常用的设计模式、SPI 和结构设计等。可以说是学到了优秀的编码习惯和思维方式。

参与到开源项目中并贡献自己的一份力量并没有想象中的难,凡事不要太着急,一步一步、脚踏实地的稳步前进,每天都要有点收获就会不断的成长,开源项目中的大牛很多,参与开源会使自己变得更加谦卑,还会让自己的思维变得更开阔,不会局限于自我。

出色完成工作所带来的成就感,实在是种难以言喻的宝贵体验。还有什么更好的选择能比加入开源项目带来更为广阔的平台?为开源项目作出贡献能够让你体会到从无到有构建成果的满足感,并因此得到承认与感激。必须承认的是,拥有开源软件贡献经历能够让我们的简历变得光彩照人。而朋友们恰好都在使用这款软件,由此带来的激励效果要远远超过每天枯燥完成的业务应用代码。这种感觉很赞,真的很赞。

导师的帮助-Mentor’s help

季敏(slievrly)前辈是我的导师,从学习 Seata 到第一次提交 Seata pr 期间,前辈总是很耐心地回答我的每一个问题,即使是在他比较忙的时候。有时会自己会问一些比较白痴的问题,他总是细心的给我指点迷津、点出问题所在以及为什么会导致这个问题;有时遇到一些技术方向的问题时,前辈也会给出具有指导性的意见。可以说,一直是他推着我前进,因此在这里感谢前辈的耐心指导,同时也感谢社区张嘉伟大佬、陈健斌大佬、钟正涛大佬在我的编程之夏之旅中提供的帮助。

总结

目前 Seata 已经是 Github 上一个大热的项目,Seata 社区非常活跃,并且在快速更新迭代。项目的技术思想是好的,分布式事务的模式也不止一种,使用方便、高效。本文主要讨论了 Seata 结合 antlr 实现 sqlparser 方面的相关内容,如果有对 Seata 项目或是对 sqlparser 方面、antlr 领域熟悉感兴趣的朋友,期待你们加入 Seata 社区一起交流学习!相信 Seata 会成为万众瞩目的分布式事务解决方案。

K8S中文社区微信公众号

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址