- 一、架构设计
- 1、基于Canal
- 2、ES文档更新
- 3、完整架构
- 二、底层原理
- 1、生命周期
- 2、命令执行
- 3、binlog数据处理过程
- 4、文件目录规范
- 5、程序设计规范
- 三、部署过程
- 四、参考文档
Canal提供了数据库增量订阅与消费的功能,不需要业务代码的侵入和依赖,通过读取MQ,即可获取到数据库的增量更新
对于数据源为数据库(如MySQL)的ES文档更新,主要有全量更新和增量更新两种方案
-
全量更新 :脚本全量查询数据库,统一写入至ES中
-
增量更新 :双写或读取
binlog
,实现ES的增量更新
ESUpdater就是读取binlog
,实现ES文档增量更新的一种解决方案
ESUpdater提供了从消费Kafka中的数据库增量数据,到ES文档增量更新的一个完整业务框架,方便业务的扩展。
Consumer
进程 :订阅Kafka队列,实时获取数据库的增量变更Worker
进程 :操作业务逻辑,将数据更新至ES文档
ESUpdater的核心由Consumer
进程和Worker
进程组成,其中根目录下的/esupdater.php
为入口文件
Consumer
进程和Worker
进程的生命周期都是由命令控制
Consumer
进程由php esupdater.php start
命令启动,由php esupdater.php stop
命令停止
当Consumer
进程从Kafka中拿到消息后,会通过exec
的方式执行php esupdater work
命令,以启动一个新的PHP进程,即Worker
进程。
Worker
进程会分为后台和非后台两种执行方式,使用哪种执行方式取决于当前Worker
进程的数量,如果少于配置的max_worker_count
会使用后台执行的方式,否则使用非后台执行的方式。通过这种方式可以在加快消费速度的同时,保证稳定性。
所以Worker进程的启动完全由Consumer
控制,如果想要停止Worker
进程,必须先停止Consumer
进程,然后等待Worker
进程正常执行结束即可
当使用php esupdater.php start
命令时,会启动一个进程,这个进程会以阻塞主进程的方式订阅Kafka消息,所以这个进程叫做Consumer
进程
Consumer
进程启动后会先在/runtime
目录下写/runtime/esupdater-consumer.pid
文件和esupdater-consumer.status
文件,分别记录进程它的进程ID和消费状态start
。
在Consumer
进程消费kafka消息的同时,会每隔配置的check_status_interval_seconds
时间检测一次消费状态(esupdater-consumer.status
文件),当消费状态变为stop
时,进程会停止消费,此时Consumer
进程会完全结束。
当使用php esupdater.php stop
命令时,会启动一个进程,这个进程会向/runtime/esupdater-consumer.status
文件中写入stop
指定。
然后每隔一秒钟就会检测Consumer
进程和Worker
进程是否都已经完全结束,如果已经检测10秒钟还未完全结束就会通知停止失败,否则停止成功。
当Consumer
进程使用php esupdater work
命令启动Worker
进程时,Worker
进程会记录下/runtime/esupdater-worker-{pid}.pid
进程ID文件,只有当结束后才会删除此文件。
处理过程为binlog => canalData => urlencode(canalData)
,可以参考文件 /framework/Canal.php
- Canal将
binlog
数据解析为json
格式并投递至kafka - Consumer进程消费kafka,使用
urlencode
方式编码获取到的消息数据 - Consumer进程把编码后的消息数据,传递至Worker进程
- Worker进程再依次拆解数据即可
app
目录 :应用目录config
目录 :项目的唯一配置入口doc
目录 :项目文档目录framework
目录 :项目的核心框架目录install
目录 :安装目录runtime
目录 :服务运行时产生的中间文件目录,如PID文件,但不包括日志文件。设计思想基于/proc/test
目录 :单元测试目录/
目录 :根目录下存放所有上述目录,和必要的一级文件如.gitignore
文件
shell
脚本不能省略.sh
后缀,且统一以bash xxx.sh
的方式执行- 文档统一以大写英文命名,如
README.md
/HELP.md
关于设计规范可以参考文章 漫谈编程之编程规范
- 调用类的时候使用命名空间前缀,不使用在头部声明
use
的方式
容器化部署方案依赖于
phpkafka
镜像,所以请确保phpkafka
镜像已经生成。为了避免重复构建耗时,建议把phpkafka
镜像推到Docker远程仓库中。
容器构建主要通过根目录下的/Dockerfile
镜像文件,它会基于phpkafka
镜像构建一个新的镜像,名为esupdater
。
当执行如下命令时,会使用/Dockerfile
文件创建esupdater
镜像,并创建esupdaterContainer
容器,最后通过在容器中执行php esupdater.php start
命令实现服务的启动
bash ./start.sh
启动成功后,除命令行输出Start success
外,在宿主机/home/log/esupdater/info.log.{date}
日志中会输出启动日志,如下图所示
当执行以下命令时,会先在容器中执行php esupdater.php stop
命令,等待容器内Consumer
进程和Worker
进程全部停止后,删除镜像和容器
bash ./stop.sh
停止成功后,除命令行输出Stop success
外,同样的在宿主机/home/log/esupdater/info.log.{date}
日志中会输出停止成功日志,如下图所示
当执行以下命令时,会先执行bash stop.sh
命令,再执行bash start.sh
命令,以防止出现重复启动的问题
bash ./restart.sh