- 浏览: 1601324 次
- 性别:
- 来自: 杭州
-
文章分类
最新评论
-
jsrgzhangzhiyong:
关于null值的转换还是感觉不太友好,就像 mapstruct ...
我也造了个轮子:BeanMapping(属性拷贝) -
he037:
a417930422 写道引用使用EPHEMERAL会引出一个 ...
基于zookeeper的分布式lock实现 -
seancheer:
qianshangding 写道首先节点启动后,尝试读取本地的 ...
zookeeper学习记录三(session,watcher,persit机制) -
雪夜归人:
您好,我想咨询一下,开源的canal都能支持mysql的哪些版 ...
Canal BinlogChange(mysql5.6) -
zhoudengyun:
copy 一份做记录,后续学习,请知悉
阿里巴巴开源项目: 基于mysql数据库binlog的增量订阅&消费
背景
距离上一篇文章已经有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"; } }
说明:
- 使用了aviator做为表达式引擎( http://code.google.com/p/aviator/),扩展了一个regex表达式语法的支持。(默认是自带了jdk pattern的正则)
- 使用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); } }
说明:
- 每次构造一条正则(固定的字符串 + 一段200个字符的随机值)
- 多线程并发的进行compiler , matcher操做
结果:
- 单线程测试顺利通过
- 多线程测试,没加200字符的随机值,尝试到20,30并发都没有发现failed
- 多线程测四和,正则表达式加上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); } } }); }
看来在使用一些三方库时要多注意一些细节,尽管你之前已经对该三方库使用已经比较久,但未必不会出问题,只不过是你的运气好与不好而已。
发表评论
-
yugong QuickStart
2016-03-05 01:52 0几点说明 a. 数据迁移的方案可参见设计文档,oracl ... -
阿里巴巴开源项目: 阿里巴巴去Oracle数据迁移同步工具
2016-03-05 18:29 6587背景 08年左右,阿里巴巴开始尝试MySQL的相关 ... -
愚公performance
2016-03-02 17:29 0性能测试 全量测试 场景1 (单主键, ... -
yugong AdminGuide
2016-03-02 16:40 0环境要求 操作系统 数据库 迁移方案 部署 ... -
Tddl_hint
2014-01-27 13:52 0背景 工作原理 Hint格式 direct模 ... -
tddl5分库规则
2014-01-26 14:41 0背景 工作原理 构建语法树 元数据 基于 ... -
tddl5优化器
2014-01-22 15:12 0背景 工作原理 构建语法树 元数据 抽象语 ... -
Canal BinlogChange(mariadb5/10)
2014-01-20 17:25 4665背景 先前开源了一个 ... -
asynload quickstart
2013-10-08 22:49 0几点说明: 1. asyncload是做为一个j ... -
网友文档贡献
2013-09-18 15:50 01. Otter源代码解析系列 链接:http://e ... -
Manager配置介绍
2013-09-16 13:00 0通道配置说明 多种同步方式配置 a. 单向同步 ... -
canal&otter FAQ
2013-09-05 17:30 0常见问题 1. canal和 ... -
阿里巴巴开源项目:分布式数据库同步系统otter(解决中美异地机房)
2013-08-22 16:48 40529项目背景 阿里巴巴B2B公司,因为业务的特性 ... -
Otter AdminGuide
2013-08-19 11:06 0几点说明 otter系统自带了manager,所以简化了一 ... -
Otter高可用性
2013-08-17 23:41 0基本需求 网络不可靠,异地机房尤为明显. man ... -
Otter数据一致性
2013-08-17 23:39 0技术选型分析 需要处理一致性的业务场景: 多地修改 ( ... -
Otter扩展性
2013-08-17 22:20 0扩展性定义 按照实现不同,可分为两类: 数据处理自定 ... -
Otter双向回环控制
2013-08-17 21:37 0基本需求 支持mysql/oracle的异构数据库的双 ... -
Otter调度模型
2013-08-17 20:13 0背景 在介绍调度模型之前,首先了解一下otter系统要解 ... -
Otter Manager介绍
2013-08-16 11:16 0背景 otter4.0发布至 ...
相关推荐
Jakarta ORO库的一个显著优点是它支持多线程环境,这意味着在并发应用中,多个线程可以安全地使用同一个`Pattern`实例,而不需要每次匹配都重新编译正则表达式,这大大提高了性能。 此外,Jakarta ORO还提供了其他...
Apache FtpServer是一个100%纯Java的、基于现有开放式协议基础上、完整、小巧的FTP服务器。此外,FtpServer还可以作为Windows服务器、Unix / Linux后台程序或是被嵌入在Java应用程序而独立运行。有了MINA...
### Apache Java项目全介绍 #### 一、Apache与Jakarta **Apache Software Foundation (ASF)** 是一个非营利性组织,其主要目标是提供开源软件产品和服务。ASF旗下有许多知名的项目,其中**Jakarta**是ASF早期的一...
如果需要处理大量文件或并发下载,可能需要引入多线程技术,如使用`ExecutorService`和`Callable`来并行执行任务,提高效率。 8. **性能优化**: 考虑到网络延迟和I/O操作的影响,可能需要优化文件下载和解析的...
使用Apache FTPClient时,开发者首先需要将这两个JAR文件添加到项目的类路径中。然后,可以通过创建FTPClient实例,设置服务器地址、端口、用户名和密码来建立连接。接着,可以调用各种方法来执行FTP操作,如`...
DBCP依赖于Jakarta POI、Jakarta ORO和Jakarta Pool等组件。使用DBCP时,开发者需要配置数据库连接参数,如URL、用户名、密码和最大连接数等,然后通过连接池获取和释放连接。 2. C3P0:C3P0是一个开源的JDBC连接池...
为了更好地理解和使用SSH框架,我们有必要深入解析这些框架中所涉及的关键Jar包及其功能。 #### 1. **antlr-2.76.jar** - **用途**:ANTLR(ANother Tool for Language Recognition)是一个强大的解析工具,主要...