本篇分享最近把elasticsearch当作时序数据库来用的心得。
• 需求
需求是这样的:提供一个后台,选用户画像标签(多选),点确认后弹出“选出了xxx个用户”,再继续点就把用户dump出来、推送消息。现在要做这个后台的数据仓库层。
详细分析一下需求:
1. 我们的用户画像走流式计算,每秒大量更新,所以对插入/更新性能要求很高。
2. 查询条件翻译成sql就是类似 select count(*) from `table` where (`tags` like '%tag1%') and (`tags` like '%tag2%') and (`tags` like '%tag3%') and ...,常规数据库算起来比较慢。
需要一个数据仓库,支持大量插入/更新、大量导出、快速多字符串匹配查询。

很不幸的是,单机版influxdb在压测环节爆了,顶不住插入/更新的量。而分布式influxdb又闭源了。接下来尝试了一下elasticsearch,于是就有了这篇文章了。
• es能干这个事么?
还真能。
1. 插入/更新性能高
es通过bulk接口,可以做到批处理,拥有相当高的插入/更新性能。
2. 查询效率高
3. 导出效率高
用es的scroll接口可以做到这么一件事:1)进行一个查询,指定翻页大小、本次查询的索引保存时间,获取一个scroll_id;2)通过scroll_id不断地翻页。可以实现大批量导出一个查询的所有数据,不需要重复计算。
4. 高可用与横向扩展能力
就不赘述了。
• 实现与优化
1. 用了3个node组成的集群,全ssd。3个刚好是满足高可用的最小master node数量。每个node的内存开到31g。
2. es前面顶一层logstash,logstash开一个http-input和elasticsearch-output,用http keep-alive来接流量。关键配置有:
1)input.http.threads默认是4,要开大;
2)output.elasticsearch.action => "update",output.elasticsearch.doc_as_upsert => true,这样可实现upsert操作;
3)pipeline.workers跟pipeline.output.workers开到跟核数一致;
4)pipeline.batch.size跟output.elasticsearch.flush_size适度开大。
3. 整个流程是数据怼logstash、logstash怼es,所以会有es的数据延后几秒才更新的情况,这样可能会引起一些问题,需要务必留意。
4. es5.0取消了ttl,所以数据的过期要另外处理。
5. es的scroll查询中,通过配置_source来提取部分字段,可以大幅降低网络i/o。
• 一些惊喜
我们往es里存的标签是没去重的原始数据,就是说一个用户的标签可能长这样:
a b a a a c d a
而es本质上是个搜索引擎,使用默认的bm25算法搜索用户,排在前面的就自然是重度用户。
非常不错。
• 总结
elasticsearch除了用来干搜索、运维监控之外,还能用来当时序数据库。在这个case里,算是对influxdb等时序数据库产品做降维打击了,真乃居家旅行、杀人越货的神器。