近期在集成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改为MappingMetadata2、ESConnection类的421行return restHighLevelClient.bulk(bulkRequest)修改为return restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);3、将ESTemplate类的494行MappingMetaData改为MappingMetadata4、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 failedjava.lang.IllegalStateException: Extension instance(name: es, class: interface com.alibaba.otter.canal.client.adapter.OuterAdapter) could not be instantiated: class could not be foundat 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 failedjava.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: XXXat 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即可;




