搜索功能的技术方案(二)
0X00 弃用canal
上一回说到,我在调研搜索功能的实现方案上选用了canal组件。然而,经过实际使用,发现存在比较大的问题
- 不支持全量同步
- 搭建起来比较复杂
- 长期不维护
0X01 选用Flink-CDC
这种同步数据的中间件叫做CDC。CDC是Change Data Capture(变更数据获取)的简称。核心思想是,监测并捕获数据库的变动(包括数据或数据表的插入、更新以及删除等),将这些变更按发生的顺序完整记录下来,写入到消息中间件中以供其他服务进行订阅及消费。
于是在众多的CDC中选用组件肯定是没错的,于是我选用了著名的Apache Flink。顺带一提,我在小米时,内部大量使用了Flink,这也是促使我选用它的主要原因。
0X02 配置Flink-CDC
也许是在小米时培养的容器化思想,我也想将Flink-CDC进行容器化,以便于将它快速启动,快速迁移,而且解除它与ES和项目代码的耦合,也即它只做一件事——同步MySQL的数据到ES中。
0x0201
下载Apache Flink:https://flink.apache.org/downloads/
这里我使用的是V1.16.1:https://www.apache.org/dyn/closer.lua/flink/flink-1.16.1/flink-1.16.1-bin-scala_2.12.tgz
解压后在其中的lib目录增加flink-sql-connector-elasticsearch7-1.16.0.jar和flink-sql-connector-mysql-cdc-2.3.0.jar
下载地址为:
https://repo1.maven.org/maven2/com/ververica/flink-sql-connector-mysql-cdc/2.3.0/flink-sql-connector-mysql-cdc-2.3.0.jar
https://repo.maven.apache.org/maven2/org/apache/flink/flink-sql-connector-elasticsearch7/1.16.0/flink-sql-connector-elasticsearch7-1.16.0.jar
配置flink参考链接:https://ververica.github.io/flink-cdc-connectors/master/content/quickstart/mysql-postgres-tutorial.html
0x0202 制作一个包含Flink 1.16.1的基础镜像并上传至aliyun(此处省略...)
0x0203 制作Dockerfile
通过上述的镜像,制作Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/xxxx/base-common:flink-1.6.1
ENV JAVA_HOME /jdk1.8.0_371
ENV PATH $JAVA_HOME/bin:$PATH
WORKDIR /flink-1.16.1/bin
EXPOSE 8081
CMD ./start-cluster.sh && ./sql-client.sh -i init.sql -f job.sql && tail -f /dev/null
其中,init.sql的内容为:
SET execution.checkpointing.interval = 3s;
job.sql的内容为:
CREATE TABLE competition (
id INT,
title STRING,
status STRING,
content STRING,
coverUrl STRING,
startTime TIMESTAMP(0),
endTime TIMESTAMP(0),
PRIMARY KEY (id) NOT ENFORCED
) WITH (
'connector' = 'mysql-cdc',
'hostname' = 'xxx.xxx.xxx',
'port' = '3306',
'server-time-zone' = 'Asia/Shanghai',
'username' = 'my_mysql_username',
'password' = 'my_mysql_password',
'database-name' = 'ideameeting',
'table-name' = 'competition'
);
CREATE TABLE idm_competition (
id INT,
title STRING,
status STRING,
content STRING,
coverUrl STRING,
startTime TIMESTAMP(0),
endTime TIMESTAMP(0),
PRIMARY KEY (id) NOT ENFORCED
) WITH (
'connector' = 'elasticsearch-7',
'hosts' = 'http://172.22.48.1:9200',
'index' = 'my_index',
'username' = 'my_es_username',
'password' = 'my_es_password'
);
insert into idm_competition select c.id, c.title, c.status, c.content, c.coverUrl, c.startTime, c.endTime from competition as c;
使用以下命令编译成最终镜像
docker build -t flink-v1.16.1:v1 .
得到的这个镜像就可以随时启动,并且启动后开始同步MySQL的数据到ES中
0x03 给es添加用户名和密码
docker run -it -d -p 9200:9200 9300:9300 -e "discovery.type=single-node" elasticsearch:v7.16.1
进入容器后,修改config/elasticsearch.yml的内容,添加:
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
然后执行./bin/elasticsearch-setup-passwords interaactive 设置密码
0x04 安装ik分词器
在准备就绪后,搜索时发现新的问题:搜索中文时,只支持搜索单个字符,不支持搜索词语。
这显然是分词器的问题,于是配置ik分词器
进入容器执行
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.16.1/elasticsearch-analysis-ik-7.16.1.zip
接下来,需要给索引需要搜索的字段添加mapping(无法给已存在的索引字段添加ik分词,因此需要删除原来的索引)
删除后,就可以添加配置ik分词了:
PUT http://xx.xx.xx.xx:9200/idm_competition
Content-Type: application/json
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart"
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
然后启动flink的镜像,数据就会同步到ES中了,并且title和content字段都会开启ik分词