暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Canal-adapter1.1.4集成Elasticsearch7.8.0排坑指南及在本地环境运行canal-adapter项

加耀 2021-03-07
2358

近期在集成canal过程中,遇到了各种各样的问题,在网上看到了很多的答案,对答案质量都不是很满意,于是自己下载编码在本地编译后,逐一排查,得出以下结论;

 

常见问题如下:

1、网上都说canal-adapter1.1.4不支持ES7系列,如何使其支持

2、常见报错信息

3、canal-adapter1.1.4具体支持的版本号范围

 

 

问题一:让canal-adapter支持ES7系列

首先从github上下载canal对应的版本的源码到本地,使用编码工具打开;

 

因为canal1.1.4最高支持的版本是6.4.3,在canal-adapter的elasticsearch模块中,引用的ES版本号为6.4.3,所以第一步需要先将ES的依赖版本号升起来;如下图所示

 

修改完毕后,重新编译项目会发现有几处代码编译报错,因为不同版本的ES的代码语法有所不同,只需要稍微改动一下即可;改动如下

编译报错地方修改:
1、ESConnection类 找不到MappingMetaData类;将类的118行 getMetaData() 改为 getMetadata(),
同时将代码中的MappingMetaData改为MappingMetadata
2、ESConnection类的421return restHighLevelClient.bulk(bulkRequest)修改为return restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
3、将ESTemplate类的494行MappingMetaData改为MappingMetadata
4、ESAdapter类的225行修改为 long rowCount = response.getHits().getTotalHits().value;
再次重新编译即可通过
复制

 

代码编译通过后,修改canal-adapter下的launcher模块中的application.yml文件,修改后的示例如下图所示

 

修改完配置文件后,下一步我们可以来配置关于数据库与ES索引的对应关系;位于elasticsearch模块下的资源文件目录下的es文件夹下,默认有3个文件,为了方便演示,我这边在本地先删除了两个;如下图所示:

 

然后我们在ES中先创建好对应的mapping结构,用于将数据库数据同步到ES中,如下

PUT /gw_es_lexicon
{
"settings": {
"number_of_shards": "1",
"number_of_replicas": "0"
},
"mappings": {
"properties": {
"lexicon_text":{
"type": "text"
},
"lexicon_type":{
"type": "integer"
},
"lexicon_status":{
"type": "integer"
},
"del_flag":{
"type": "integer"
},
"create_time":{
"type": "date"
},
"lexicon_type_b":{
"type": "integer"
}
}
}
}
复制

 

完成上述步骤后,即可启动canal-adapter本地项目;

 

 

 

问题二:关于常见的报错信息

canal-adapter在使用过程中,通常会遇到很多的报错,下面逐一为大家解答;

 

采坑点之一:在本地运行前一定选在maven的root模块下先install安装,安装完毕后再运行CanalAdapterApplication启动类;给大家看看不安装直接运行的效果

 

没有先install运行后启动报错:

2021-03-04 13:13:29.630 [main] ERROR c.a.o.canal.adapter.launcher.loader.CanalAdapterLoader - Load canal adapter: es failed
java.lang.IllegalStateException: Extension instance(name: es, class: interface com.alibaba.otter.canal.client.adapter.OuterAdapter) could not be instantiated: class could not be found
at com.alibaba.otter.canal.client.adapter.support.ExtensionLoader.createExtension(ExtensionLoader.java:186)
at com.alibaba.otter.canal.client.adapter.support.ExtensionLoader.getExtension(ExtensionLoader.java:142)
at com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterLoader.loadAdapter(CanalAdapterLoader.java:151)
at com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterLoader.init(CanalAdapterLoader.java:71)
at com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterService.init(CanalAdapterService.java:58)
复制

 

通过报错信息可以看到OuterAdapter类找不到一个叫做 es的实现类;进入源码可以看到OuterAdapter接口一共有4个实现类,其中有一个ESAdapter类的别名就是 es;


通过报错信息可以发现,当前提示是 ESAdapter这个类找不到,根据抛出异常代码所在行通过源码打断点进一步排查,如下图所示:

 

在canal-adapter项目的ExtensionLoader类的265行,获取本地编译后的文件路径,找到target目录下的plugin目录下面的jar包,结果发现找不到了;于是异常就来了;

 

有两种方式可以解决这个问题,第一种就是在canal-adapter项目的launcher模块下的main方法下面新建文件夹 canal-adapter/plugin文件夹,将编译后的es的jar包放进去;然后修改源码中关于本地文件加载的路径即可,如下图所示;

 

另外一种方法就是,运行前还是先老老实实的使用maven的install安装一下吧;

 

通过这两种方式都可以解决could not be instantiated: class could not be found的问题;如果你们这边依然有这个问题,那么不妨看看是什么原因导致几个实现类没有被代码加载吧,网上看到的很多的博客,都没有在根源上描述清楚当前问题的本质所在;

 

 

 

采坑点之二:报错信息 Config dir not found

2021-03-04 14:07:42.497 [main] ERROR c.a.o.canal.adapter.launcher.loader.CanalAdapterLoader - Load canal adapter: es failed
java.lang.RuntimeException: java.lang.RuntimeException: Config dir not found.
at com.alibaba.otter.canal.client.adapter.es.ESAdapter.init(ESAdapter.java:137)
at com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterLoader.loadAdapter(CanalAdapterLoader.java:172)
at com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterLoader.init(CanalAdapterLoader.java:71)
at com.alibaba.otter.canal.adapter.launcher.loader.CanalAdapterService.init(CanalAdapterService.java:58)
复制

 

在本地调试过程中,发现有报错Config dir not found.于是通过报错行打断点进一步排查,发现是项目启动完毕后在执行数据初始化阶段,没有找到配置文件所导致的异常;由于我在application.yml文件中配置的存储方为es,于是项目在启动完毕后,检查es的配置文件,发现没有找到,于是抛出当前异常;断点截图如下:

 

从上图可以看到,程序在运行结束调用初始化方法ESAdapter.init(ESAdapter.java:137)时,检查编译后的目录下的es文件夹,但是没有找到这个文件夹,于是抛出了异常;

 

这个问题也比较好解决,我们可以在canal-adapter的launcher模块的配置文件中新建一个叫es的文件夹,把elasticsearch模块下的es文件夹拷贝过来,即可解决这个问题;如果是在服务器上出现的这个问题,则需要排查一下为什么没有加载到当前目录;

 

 

采坑点之三:报错Elasticsearch exception[type=index_not_found_exception, reason=no such index [XXXX]]

这个问题,大家可以检查一下ES里面对应的索引名称是否存在,索引的mapping结构是否已经创建;当然,可能还有其他的情况下导致出现这个问题,暂时没有遇到;

 

 

采坑点之四:报错Not found the mapping info of index: XXX

这个问题从报错信息来看,总感觉像是ES中索引的Mapping结构没有创建好,我用多种方式进行mapping结构的创建,可一直报错;报错信息如下

 

Caused by: java.lang.IllegalArgumentException: Not found the mapping info of index: XXX
at com.alibaba.otter.canal.client.adapter.es.support.ESTemplate.getEsType(ESTemplate.java:497)
at com.alibaba.otter.canal.client.adapter.es.support.ESTemplate.getValFromData(ESTemplate.java:345)
at com.alibaba.otter.canal.client.adapter.es.support.ESTemplate.getESDataFromDmlData(ESTemplate.java:376)
at com.alibaba.otter.canal.client.adapter.es.service.ESSyncService.singleTableSimpleFiledInsert(ESSyncService.java:433)
at com.alibaba.otter.canal.client.adapter.es.service.ESSyncService.insert(ESSyncService.java:133)
  at com.alibaba.otter.canal.client.adapter.es.service.ESSyncService.sync(ESSyncService.java:93)
复制

 

根据报错堆栈信息,通过打断点的方式进一步排查,我们会看到在ESConnection类的137行有这样一些被注释了的代码

// try {
// response = restHighLevelClient
// .indices()
// .getMapping(request, RequestOptions.DEFAULT);
// // 6.4以下版本直接使用该接口会报错
// } catch (Exception e) {
// logger.warn("Low ElasticSearch version for getMapping");
response = RestHighLevelClientExt.getMapping(restHighLevelClient, request, RequestOptions.DEFAULT);
// }
复制

 

这也正是canal-adapter1.1.4为什么不支持ES7以上的版本了,我们只需要将这些被注释的代码打开即可解决这个问题;改完后代码如下:

try {
response = restHighLevelClient
.indices()
.getMapping(request, RequestOptions.DEFAULT);
// 6.4以下版本直接使用该接口会报错
} catch (Exception e) {
logger.warn("Low ElasticSearch version for getMapping");
// response = RestHighLevelClientExt.getMapping(restHighLevelClient, request, RequestOptions.DEFAULT);
}
复制

  

然后顺手把146行的IOException改为Exception即可;重新install安装一下,再运行一遍,完美解决;

 

所以通过上述代码大家也就明白了,为什么canal-adapter1.1.4网上都说不支持ES7以上版本了;

 

 

 

测试效果

通过上述代码的改造,我们可以对改完后的内容进行测试,全量同步数据和增量同步数据;

 

canal-adapter为我们提供了全量同步数据的接口,我们在canal-adapter的launcher模块的com.alibaba.otter.canal.adapter.launcher.rest目录下可以看到有一个类叫做 CommonRest;其里面有提供全量同步数据的方法和条件同步数据的方法,如下图

 

直接使用postman发送如下请求即可完成数据的全量同步,效果如下图,同时,如果数据库当前表的数据发生变更,canal-adapter也能及时监听到并且同步到ES中;

POST  127.0.0.1:8081/etl/es/mytest_user.yml
复制


上面的URL中,etl表示的是语法,es表示访问文件夹名称,后面的yml文件则为访问具体目录下的具体文件。执行结果如下:

 

关于canal-adapter配置文件当面的,大家可以参考一下官网文档:https://github.com/alibaba/canal/wiki/Sync-ES

 

另外还有一个网上经常提到的 name: es6 和 es7 ,通过观察源码,在adapter1.1.4版本中,直接使用es即可;

 


文章转载自加耀,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论