【前提】
目前公司订单数据库虽然使用了索引、缓存、读写分离等,由于业务本身复杂以及数据量的不断上涨,导致查询出现了瓶颈,海量数据查询对于APP有时候甚至出现超时现象,不得不对这种情况做出处理。其中可行解决方案比如:分库分表、使用ElasticSearch检索、优化索引等,最终组内评定,选择了通过ElasticSearch来解决这个问题。
【设计思想】
如图所示,类似数据库的读写分离,增删改操作直接操作数据库,查询操作,利用ES快速检索的能力,直接从ElasticSearch中通过DSL语句进行查询。
针对于这种情况,我们不需要重构系统,只需要将ES查询这部分设计成组件,插入到原有的系统当中。其中我们的设计是这样的:
1.单独为ES查询新建了项目,通过RPC的形式,来请求查询;
2.在系统Service层统一通过配置中心设计一组“开关”,防止elasticsearch崩溃时,紧急将底层查询切换回Mysql数据库。
【数据同步】
由上可知,基本的思想是读写分离到ES,解决慢查询问题,那么mysql的数据是如何同步到elasticsearch中呢?
binlog + cancel + blukAPI(ElasticSearch)
从Mysql实时同步到ES,我采取了上述技术栈组合的方案。当然,对于es官方给出的同步策略以及开源出来的同步策略主要包含: 1.elasticsearch-jdbc | https://github.com/jprante/elasticsearch-jdbc 2.elasticsearch-river-MySQL | https://github.com/scharron/elasticsearch-|river-mysql 3.go-mysql-elasticsearch https://github.com/siddontang/go-mysql-|elasticsearch (国内) 4.logstash-input-jdbc https://github.com/logstash-plugins/logstash-|input-jdbc (Addition:每种插件的github地址,已列出)
如上所述的这4种方案,都可以实时地将Mysql数据同步到ES中,在“铭毅天下”大神的博客中,看到了这4种插件优劣性的对比:
上图来自:
如上,普遍问题在于不能实现同步删除功能,恰巧公司数据平台组同事做了一套支持通过binlog做数据同步的系统,尝试了一下从mysql到es的实时同步可用,而且增量、全量都可以做,于是乎就采用了这种方式。其中主要用了阿里开源的canal 以及ES中的Bluk API。
一、Canal
canal项目目前已经开源:https://github.com/alibaba/canal
canal原理:
Mysql理解为图中Master,Elastic理解为途中slave。主要过程分三步:
1.master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
2.slave将master的binary log events拷贝到它的中继日志(relay log);
3.slave重做中继日志中的事件,将改变反映它自己的数据。
二、Bulk API
The bulk API makes it possible to perform many index/delete operations in a single API call. This can greatly increase the indexing speed.
关于Bulk API的使用,参考官方:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
【注意点】
1.数据同步之前,提前建好Elasticsearch的index、type结构,并设定好分片数量,因为后期分片不可变。
2.就index中字段的设计,遵循一个index下对应一个type,因为最新版本的elasticserach会渐渐去掉type的概念。
3.从Mysql同步到elastic的原理还是基于mysql的binlog,对于订单查询条件维度太多,虽然多张表可以合并到一个index中,但
如果是1对多或者多对多关系,不要关联到一个index里。
4.对于列表查询,目前es 查询不支持连接,所以关联查询要么用范式二做冗余设计表,要么自应用里自己做关联。
周末愉快
That's all.