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

简介:

背景

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

 

过程

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

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

 

原因

 

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


1.public class RegexFunction extends AbstractFunction {  
2.  
3.    private Map<String, Pattern>  patterns = null;  
4.    private final PatternCompiler pc       = new Perl5Compiler();  
5.  
6.    public RegexFunction(){  
7.        patterns = new MapMaker().softValues().makeComputingMap(new Function<String, Pattern>() {  
8.  
9.            public Pattern apply(String pattern) {  
10.                try {  
11.                    return pc.compile(pattern, Perl5Compiler.CASE_INSENSITIVE_MASK);  
12.                } catch (MalformedPatternException e) {  
13.                    throw new CanalSinkException(e);  
14.                }  
15.            }  
16.        });  
17.    }  
18.  
19.    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {  
20.        String pattern = FunctionUtils.getStringValue(arg1, env);  
21.        String text = FunctionUtils.getStringValue(arg2, env);  
22.        Perl5Matcher matcher = new Perl5Matcher();  
23.        boolean isMatch = matcher.matches(text, patterns.get(pattern));  
24.        return AviatorBoolean.valueOf(isMatch);  
25.    }  
26.  
27.    public String getName() {  
28.        return "regex";  
29.    }  
30.  
31.}  

说明:

 

  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是非线程安全的)


 

我做了个测试:


1.public class MutliAviaterFilterTest {  
2.  
3.    @Test  
4.    public void test_simple() {  
5.        int count = 5;  
6.        ExecutorService executor = Executors.newFixedThreadPool(count);  
7.  
8.        final CountDownLatch countDown = new CountDownLatch(count);  
9.        final AtomicInteger successed = new AtomicInteger(0);  
10.        for (int i = 0; i < count; i++) {  
11.            executor.submit(new Runnable() {  
12.  
13.                public void run() {  
14.                    try {  
15.                        for (int i = 0; i < 100; i++) {  
16.                            doRegexTest();  
17.                            // try {  
18.                            // Thread.sleep(10);  
19.                            // } catch (InterruptedException e) {  
20.                            // }  
21.                        }  
22.  
23.                        successed.incrementAndGet();  
24.                    } finally {  
25.                        countDown.countDown();  
26.                    }  
27.                }  
28.            });  
29.        }  
30.  
31.        try {  
32.            countDown.await();  
33.        } catch (InterruptedException e) {  
34.        }  
35.  
36.        Assert.assertEquals(count, successed.get());  
37.        executor.shutdownNow();  
38.    }  
39.  
40.    private void doRegexTest() {  
41.        AviaterRegexFilter filter3 = new AviaterRegexFilter("otter2.otter_stability1|otter1.otter_stability1|"  
42.                                                            + RandomStringUtils.randomAlphabetic(200));  
43.        boolean result = filter3.filter("otter1.otter_stability1");  
44.        Assert.assertEquals(true, result);  
45.        result = filter3.filter("otter2.otter_stability1");  
46.        Assert.assertEquals(true, result);  
47.    }  
48.  
49.}  

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

结果:

 

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

错误2: 

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

 

 

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

 

总结

正确的代码写法:

 

1.public RegexFunction(){  
2.        patterns = new MapMaker().softValues().makeComputingMap(new Function<String, Pattern>() {  
3.  
4.            public Pattern apply(String pattern) {  
5.                try {  
6.                    <span style="color: rgb(255, 0, 0);">PatternCompiler pc = new Perl5Compiler();</span>  
7.                    return pc.compile(pattern, Perl5Compiler.CASE_INSENSITIVE_MASK<span style="color: rgb(255, 0, 0);"> | Perl5Compiler.READ_ONLY_MASK</span>);  
8.                } catch (MalformedPatternException e) {  
9.                    throw new CanalSinkException(e);  
10.                }  
11.            }  
12.        });  
13.    }  

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

 

相关文章
|
1月前
|
分布式计算 测试技术 Apache
如何不加锁地将数据并发写入Apache Hudi?
如何不加锁地将数据并发写入Apache Hudi?
32 0
|
11月前
|
消息中间件 Java Kafka
Apache Kafka-通过concurrency实现并发消费
Apache Kafka-通过concurrency实现并发消费
358 0
|
测试技术 Apache
Apache Bench - AB 压测模拟并发
Apache Bench - AB 压测模拟并发
155 0
Apache Bench - AB 压测模拟并发
|
测试技术 Apache
Apache ab并发负载压力测试
ab命令原理 Apache的ab命令模拟多线程并发请求,测试服务器负载压力,也可以测试nginx、lighthttp、IIS等其它Web服务器的压力。 ab命令对发出负载的计算机要求很低,既不会占用很多CPU,也不会占用太多的内存,但却会给目标服务器造成巨大的负载,因此是某些DDOS攻击之必备良药,老少皆宜。
1187 0
|
安全 Unix Linux
Apache优化:修改最大并发连接数
Apache是一个跨平台的web服务器,由于其简单高效、稳定安全的特性,被广泛应用于计算机技术的各个领域。现在,Apache凭借其庞大的用户数,已成为用户数排名第一的web服务器。
1549 0
|
负载均衡 应用服务中间件 Apache
关于配置并发访问的服务器apache、nginx
一、 apache,nginx比较     关于Apache与Nginx的优势比较  (apache计算密集型   nginx io密集型  各有优势,不存在谁取代谁) 二、nginx 基于nginx的tomcat负载均衡和集群(超简单)  侧重点简单配置,缺点多人访问时,session ...
1232 0
|
网络协议 Linux Apache
查看Apache并发请求数及其TCP连接状态
[文章作者:张宴 本文版本:v1.1 最后修改:2007.07.27 转载请注明出处:http://blog.s135.com] 这两天搭建了一组Apache服务器,每台服务器4G内存,采用的是prefork模式,一开始设置的连接数太少了,需要较长的时间去响应用户的请求,后来修改了一下Apache 2.
855 0
|
Apache
Apache限制IP连接数与并发数设置
http://cicl.javaeye.com/blog/348136 http://www.
648 0

热门文章

最新文章

相关实验场景

更多

推荐镜像

更多