背景介绍:试用报告数据在DB底层打通评价数据,报告数据就分散到评价的32个数据库,2048张表里。因为基本的业务需求是打通数据并且将报告接入搜索。为了考虑业务灵活性,选择终搜平台来完成报告的全量和增量。全量模块通过Tsearch
基于评价以及IC的云梯表,join做的全量dump。因为增量通过sql的增量方式,会给DB造成很大的压力,尤其是在gmt_modified 没有索引的情况,并且数量级百亿的数据源中增量百万级的数据。
本文主要介绍用Mysql的binlog解析得到的稳定增量数据源来解决非sql增量的方案。
一、整体设计
先看一下全量和增量整体的项目架构图
上图左边部分是全量部分,通过hadoop
写全量job去dump数据。右半部分是增量模块,通过DRCDataSource实现获取Mysql解析binlog 得到的modified数据,主要是通过DRC(Data Replication Center)平台提供消息数据接口。然后应用通过接收数据更新消息,获得增量数据源,并将处理分解后的数据更新到终搜的增量数据源中,通过实现终搜定制的DataProvider来让终搜增量定时任务扫描每2分钟的增量。
二、增量方案
增量的系统交互时序图如下:
增量的数据目的地是增量索引文件。那么索引文件的数据来自于搜索平台提供的一个SourceDataProvider。在这里,是应用自己实现的dataProvider,命名为ReportDataProvider。数据提供格式是List<SourceDataProvider>
splitList。也就是说,我们需要填充增量数据到这个list中。再往下一步这个list数据就来源于DRC平台。然后DRC平台通过解析Mysql的binlog来获得数据库的实时变更数据。应用平台需要做的就是接收变更数据的消息,将变更数据的行数据put到dump需要的分块数据(也就是上述splitList)中。
加上构建搜索增量索引部分的流程,整体增量时序图如下:
三、binlog解析及实时增量技术
在了解了增量设计方案之后,我们可以继续深入到数据源的获取和解析。下面简单介绍下mysql日志模块的一些基本概念,以及通过ROW模式解析binlog,获取到元数据MetaData以及数据行信息的方式。
1、mysql
log介绍
Mysql
的日志类型有查询日志、错误日志、慢查询日志以及二进制日志等。这里简单说一下二进制日志(binlog),二进制日志记录了对数据库的更改操作,如create,insert,drop,update等。通过二进制日志可以对数据库进行数据恢复以及数据复制。
2、binlog 几种模式介绍
开启二进制日志是需要手动指定参数,但是开启日志也会对性能造成一定影响,这个可以参看Mysql官方手册不同版本的影响。但是考虑其可以用在复制和恢复数据的作用上,可以通过手动配置一些参数来最大化利用好二进制日志。其中binlog_format参数在Mysql5.1之后可以用STATEMENT,ROW,MIXED三种模式。
STATEMENT是Mysql一直以来支持的格式,记录的是日志的逻辑语句。ROW格式下就可以记录行的更改情况,对于数据复制和恢复的可靠性更好,但同时也会增加二进制文件的大小。MIXED格式是综合了前两者,具体要看存储引擎的支持情况。InnoDB和MyISAM是STATEMENT,ROW两者都支持的。
3、binlog
解析
(细化,图形加例子描述)
binlog文件就像一个流文件,它每一条记录没有明显的开始及结束标志,它是通过长度来判断一条记录的结束位置,所以在分析binlog文件的时候总是必须从头开始,然后依次一条一条的读取。Binlog的头信息是固定的,要分析数据其实要读完整个文件。Mysql官方有提供了mysqlbinlog 工具来查看日志。当然我们也可以通过程序去解析二进制文件成我们想要看到的输出格式。
把binlog分成几个模块来看的话,开始的部分都是由fe
62 69 6e4个字节组成的魔数,接下来的部分就是Common-Header,再后面就是body部分。下面简单列举下代码模块,看一下解析过程
1.获取binlog文件,解析固定的魔数组:
public InputStream parseInit(String path)throws Exception{ InputStream try{ finalbyte[] finalbyte[] inputMagic inputStream.read(inputMagic, 0, if(!Arrays.equals(inputMagic, binlogMagic)){ // throw new Exception }
return inputStream; }catch(Exception inputStream.close(); throw e; } }
|
2.解析Common-Header部分
也就是将header的固定字节数的部分读出来。下面代码模块表示了每个解析模块代表的含义以及字节数。
long timeStamp= inputStream.readLong(4);//操作前的时间戳 int type= inputStream.readInt(1);// 事件类型,标记了操作类型,事务提交或者查询等。 long serverId= inputStream.readLong(4);// 事件创建的server id。 int eventLength= inputStream.readInt(4);// 该条记录的size long nextPosision= inputStream.readLong(4);//下条记录起始位点 int flag= inputStream.readInt(2);
|
3. 解析Event
Binlog记录的Event有20多种,每个ddl会出发多个event。比如update,insert,delete 等操作都会触发产生TABLE_MAP_EVENT 来获取数据库的元数据,对于库、表的信息。所以下面的解析就要针对event。因为具体的event所对应的数据格式,字节分配都是不同的。这里不列举具体某个解析代码,在设计的过程中,可以参考Visitor模式 来设计。如下图:
针对不同的Event有不同的实现。BinlogEvent可以作为Observer,只需要关注自己的解析方法。而主题BinlogParser有对于event的引用,作为主题(Subject)来管理Event集合,并调用相应的Event实现的parse()方法触发相应的Event解析过程。这里省略了具体的实现,只是提供一个设计的参考。当然,在实际的编码和开发过程中,需要考虑更多的因素,比如过滤操作,只让客户端获取关注的ddl,需要用到filter,或者说建立监听模式等。
四、总结
综上,在我们考虑介入增量搜索的时候,可以考虑对于DB压力更小,性能更优的方式来dump数据源。尤其,未来业务快速发展,报告的数据也不再局限在一张逻辑表里面的时候,用好二进制日志,可以帮助我们更好地去做好数据的过滤、组合,处理。本文只是对于增量搜索一个既有实施方案的设计以及思考。对于不同的应用场景,需要未来进一步地探讨,以及更加适合应用和优性能的方案。