`
agapple
  • 浏览: 1596010 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

apache oro使用注意细节(并发问题)

    博客分类:
  • java
阅读更多

背景

  距离上一篇文章已经有4个多月了,这4个多月一直在忙着做一个数据库同步产品的代码研发和测试,现在基本运行稳定。 本文主要介绍一下,当时使用apache oro包进行正则过滤时,使用时出现的一个并发问题,排查了好几天才找到原因。希望大家使用时引以为戒,望周知。

 

过程

简单的描述下,我使用apache oro的场景: 进行数据库同步时,我们会根据定义的表名进行匹配,从binlog的数据流中提取出我们关心的表,然后进行解析,压缩,传输,写入目标库等一系列动作。 

然而在线下测试环境中,冒出一个比较异常的情况,数据没有被正常的同步到目标库(概率发生的比较小,每次jvm重启后才可能出现),一节一节的往上查,最后定位是正则匹配时出的问题。

 

原因

 

出问题的代码: (这是当时出问题的代码,犯了多个错误)

 

public class RegexFunction extends AbstractFunction {

    private Map<String, Pattern>  patterns = null;
    private final PatternCompiler pc       = new Perl5Compiler();

    public RegexFunction(){
        patterns = new MapMaker().softValues().makeComputingMap(new Function<String, Pattern>() {

            public Pattern apply(String pattern) {
                try {
                    return pc.compile(pattern, Perl5Compiler.CASE_INSENSITIVE_MASK);
                } catch (MalformedPatternException e) {
                    throw new CanalSinkException(e);
                }
            }
        });
    }

    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
        String pattern = FunctionUtils.getStringValue(arg1, env);
        String text = FunctionUtils.getStringValue(arg2, env);
        Perl5Matcher matcher = new Perl5Matcher();
        boolean isMatch = matcher.matches(text, patterns.get(pattern));
        return AviatorBoolean.valueOf(isMatch);
    }

    public String getName() {
        return "regex";
    }

}

说明:

 

  1. 使用了aviator做为表达式引擎( http://code.google.com/p/aviator/),扩展了一个regex表达式语法的支持。(默认是自带了jdk pattern的正则)
  2. 使用google collection,将pattern进行lazy-init处理,多线程共享。(map中没有对应pattern,就进行compiler)

错误1:  

1.  Perl5Compiler是有状态的,会在compiler过程中产生一些上下文状态。 (之前先入为主的认为类似于Compiler基本都是单例使用,线程安全,基本我自己写代码和命名是这个习惯)

 

对应的Perl5Compiler的javadoc:  (已经比较明确的指出,Perl5Compiler和Perl5Matcher是非线程安全的)


 

我做了个测试:
public class MutliAviaterFilterTest {

    @Test
    public void test_simple() {
        int count = 5;
        ExecutorService executor = Executors.newFixedThreadPool(count);

        final CountDownLatch countDown = new CountDownLatch(count);
        final AtomicInteger successed = new AtomicInteger(0);
        for (int i = 0; i < count; i++) {
            executor.submit(new Runnable() {

                public void run() {
                    try {
                        for (int i = 0; i < 100; i++) {
                            doRegexTest();
                            // try {
                            // Thread.sleep(10);
                            // } catch (InterruptedException e) {
                            // }
                        }

                        successed.incrementAndGet();
                    } finally {
                        countDown.countDown();
                    }
                }
            });
        }

        try {
            countDown.await();
        } catch (InterruptedException e) {
        }

        Assert.assertEquals(count, successed.get());
        executor.shutdownNow();
    }

    private void doRegexTest() {
        AviaterRegexFilter filter3 = new AviaterRegexFilter("otter2.otter_stability1|otter1.otter_stability1|"
                                                            + RandomStringUtils.randomAlphabetic(200));
        boolean result = filter3.filter("otter1.otter_stability1");
        Assert.assertEquals(true, result);
        result = filter3.filter("otter2.otter_stability1");
        Assert.assertEquals(true, result);
    }

}
 说明:
  1. 每次构造一条正则(固定的字符串 + 一段200个字符的随机值)
  2. 多线程并发的进行compiler ,  matcher操做 

结果:

 

  1. 单线程测试顺利通过
  2. 多线程测试,没加200字符的随机值,尝试到20,30并发都没有发现failed
  3. 多线程测四和,正则表达式加上200字符的随机值,尝试2个并发就遇到了failed情况
看来需要有足够的碰撞才行,通过增加表达式长度,增加了compiler的编译时间,增加了多线程碰撞的几率,从而造成编译出的Pattern是一个不正确的状态机。

错误2: 

2. Pattern在不同的参数编译下,会有不同的结果,也会有并发问题。 (对应javadoc中也已经有了说明)

 

 

我也做了个类似测试,在20,30的并发度下,也没有发现failed情况。后续可以在更高的压力,更复杂的正则表达式进行匹配,估计碰撞的概率就会比较高

 

总结

正确的代码写法:

 

public RegexFunction(){
        patterns = new MapMaker().softValues().makeComputingMap(new Function<String, Pattern>() {

            public Pattern apply(String pattern) {
                try {
                    PatternCompiler pc = new Perl5Compiler();
                    return pc.compile(pattern, Perl5Compiler.CASE_INSENSITIVE_MASK | Perl5Compiler.READ_ONLY_MASK);
                } catch (MalformedPatternException e) {
                    throw new CanalSinkException(e);
                }
            }
        });
    }

 

 

看来在使用一些三方库时要多注意一些细节,尽管你之前已经对该三方库使用已经比较久,但未必不会出问题,只不过是你的运气好与不好而已。 

 

  • 大小: 42.9 KB
  • 大小: 31.4 KB
分享到:
评论

相关推荐

    Apache ORO

    然而,随着JDK的发展,自1.4版本起,Java开始内置了java.util.regex包,提供了对正则表达式全面的支持,这使得Apache ORO的重要性相对减弱,但仍有一些开发者因其特定的功能和历史积累而继续使用。 Apache ORO库的...

    ant-apache-oro-1.6.3.jar.zip

    "ant-apache-oro-1.6.3.jar"是Apache ORO库的JAR文件,这个文件包含了所有必要的类和资源,可以在Java环境中直接使用,以实现Perl兼容的正则表达式功能。开发者可以通过引入这个JAR文件,将Apache ORO的功能集成到...

    ant-apache-oro.jar.zip

    《Ant Apache ORO库的深度解析与应用》 在Java开发领域,Ant是一个广泛使用的构建自动化工具,而Apache ORO则是Ant...同时,理解并熟练运用Apache ORO库,能够提升开发者解决复杂问题的能力,使项目管理变得更加高效。

    ant-apache-oro.jar ant-apache-regexp.jar ant-apache-resolver.jar

    标题中的"ant-apache-oro.jar", "ant-apache-regexp.jar", 和 "ant-apache-resolver.jar" 是三个与Apache Ant相关的Java库文件。Apache Ant是一个由Apache软件基金会开发的Java构建工具,它广泛用于自动化Java项目的...

    ant-apache-oro-1.6.5.jar.zip

    除了主要的"ant-apache-oro-1.6.5.jar"文件,压缩包中的"ant.license.txt"文件包含了Apache ORO的许可协议,它是Apache软件基金会发布的开源许可证,允许自由使用、修改和分发该库,只要遵循其条款。 总的来说,Ant...

    java 正则表达试

    import org.apache.oro.text.regex.MalformedPatternException; import org.apache.oro.text.regex.MatchResult; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.PatternCompiler; ...

    ant-apache-oro-1.7.0.jar

    标签:ant-apache-oro-1.7.0.jar,ant,apache,oro,1.7.0,jar包下载,依赖包

    ant-apache-oro-1.8.2.jar

    标签:ant-apache-oro-1.8.2.jar,ant,apache,oro,1.8.2,jar包下载,依赖包

    ant-apache-oro-1.6.2.jar.zip

    在Java开发领域,Ant是一个广泛使用的自动化构建工具,它基于XML来定义项目构建过程,而Apache ORO则是Ant中一个重要的组件,为Java程序提供了强大的正则表达式处理能力。在本文中,我们将深入探讨Ant Apache ORO ...

    ant-apache-oro-1.9.4.jar

    标签:ant-apache-oro-1.9.4.jar,ant,apache,oro,1.9.4,jar包下载,依赖包

    com.springsource.org.apache.oro-2.0.8.jar

    jar包,官方版本,自测可用

    com.springsource.org.apache.oro-sources-2.0.8.jar

    jar包,官方版本,自测可用

    ant-apache-oro-1.6.4.jar.zip

    标题中的"ant-apache-oro-1.6.4.jar.zip"是一个压缩文件,它包含了一个名为"ant-apache-oro-1.6.4.jar"的Java档案(JAR)文件以及一个"ant.license.txt"的文本文件。这个JAR文件是Apache Ant项目的一部分,其中集成...

    ant-apache-oro-1.9.1.jar

    标签:ant-apache-oro-1.9.1.jar,ant,apache,oro,1.9.1,jar包下载,依赖包

    ant-apache-oro-1.9.1-sources.jar

    标签:ant-apache-oro-1.9.1-sources.jar,ant,apache,oro,1.9.1,sources,jar包下载,依赖包

    apache的FTP包commons-net-1.4.1.jar,jakarta-oro-2.0.8.jar

    如果在特定环境中仍遇到乱码问题,开发者可能需要检查服务器的配置,或者在进行文件名操作时特别注意编码转换。 总的来说,这两个JAR包的组合为Java开发者提供了一个强大且可靠的FTP客户端解决方案。使用它们,...

    apache-jakarta-oro.jar.zip

    Jakarta-ORO是最全面以及优化得最好的bai正则表达式API之一,duJakarta-ORO库以前叫做zhiOROMatcher,是由Daniel F. Savarese编写,后来他将其赠与daoJakarta Project。是面向JAVA的正则表达式库

    ant-apache-oro-1.7.1.jar

    标签:ant-apache-oro-1.7.1.jar,ant,apache,oro,1.7.1,jar包下载,依赖包

    ant-apache-oro-1.8.4.jar

    标签:ant-apache-oro-1.8.4.jar,ant,apache,oro,1.8.4,jar包下载,依赖包

    ant-apache-oro-1.8.3.jar

    标签:ant-apache-oro-1.8.3.jar,ant,apache,oro,1.8.3,jar包下载,依赖包

Global site tag (gtag.js) - Google Analytics