基于 EleasticSearch 和 Kibana 的运营数据可视化后台

2017-10-02

前一段时间在研究 ELK 这个东西,之前也用过一点,但都没有深入研究,其实这回也没有深入研究,但我找到了在现在情况下我该怎么用这个东西的方法。

ELK 是一个日志系统的全家桶工具,Elasticsearch 用的人比较多,很多人把这个当作搜索后台,如果你选择了 Django 这样的框架的话也很容易继承搜索功能进去,比如用这个库 django-haystack,当然很多人是用来做日志存储。

L 是 Logstash,经过我的调研就发现这个玩意其实不太好用,性能差是主要原因。这个东西的用途就是一个中间件,把多个平台的不同格式的日志全部进行预处理,然后再存入 ES 中,但是作为一个还很小,没那么复杂的后台服务来说,用不着,只有一个日志来源,日志格式也是固定的,一条日志里面有四个 JSON object,每个 object 的 key 不是固定的,只要处理一下时间戳就行了,其他都不用动,直接 mapping 到 ES 中,刚开始我甚至还用到了 filebeat,先用 filebeat 监控文件,然后 filebeat output 给 logstash,然后 logstash 再 output 给 ES,简直了,测试的时候没什么问题,但一上线过了两三天日志数量多了起来我就发现问题了,数量不对,每天都在累加前一天的日志条数,等于说是 tail 文件没成功,每次都从头开始读文件了,外加用了 rsync 这个东西从生产服务器上同步日志到 ES 机器上,我也没整明白到底是哪里出了问题,索性直接弃用 logstash 和 filebeat,只用 ES 和 kibana,我自己写脚本监控文件、把日志写入 ES 中,也把日志按天切分成文件,简单又靠谱。

运营数据日志的日志内容其实和消息系统很像,我就直接引用这里的概念 AVOTActor/Verb/Object/Target。举例说明: xxx 关注了 yyyxxx 是 Actor,关注 是 Verb,yyy 是 Target,这里没有 Object,再举一个例子,xxx 将 uuu 添加到了 yyy 中,这里的 Verb 是 添加,Object 是 uuuActor/Object/Target 就是模型,当然我们不用把模型的全部字段都放进去,放个 type/id/name 就够了。按照这样的规则规定好日志内容之后就简单了,在每个需要记录日志的地方进行埋点,这个就是比较麻烦的地方,如果业务比较复杂的化,埋点很多,写的时候一定要一次性写对 Object 和 Target,不要写了一次之后复制粘贴,很容易搞错,一个个写。还有一点就是 Actor/Object/Target 的 id 都转成字符串存储,因为用户的 id 是 uuid,日志 object 直接 to_json(),django logger 直接用,用户 id 会变成字符串,其他 model 的 id 还是 int,类型如果不一致再存到 ES 里面数据会有冲突。

最终的日志格式示例:

1
2
{"target": {"type": "xxxx", "title": "xxxxxx", "id": "791", "owner": "xxx"}, "object": {}, "actor": {"agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36", "accept_language": "en-US,en;q=0.8", "username": "xxx", "host": "www.example.com", "referer": "www.example.com"}, "verb": "点赞", "time": 1507000406.305043}
{"target": {"type": "xxx", "id": "fcc3837f-1a61-4d2c-bdbf-0961085547a3", "owner": "ddd"}, "object": {}, "actor": {"agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", "accept_language": "zh-CN,zh;q=0.8", "username": "", "host": "www.example.com", "referer": "www.example.com"}, "verb": "注册", "time": 1507000688.429523}

我用了 Elasticsearch 的官方 Python API elasticsearch-py,脚本放在了 Gist 里面。

日志存到 ES 中是这个样子:

2

Kibana

Kibana 是一个可是化工具,能看到 ES 中的数据,做一些报表,只要把数据导入到 ES 中,做报表就很简单了,简单的也是有前提的,前提是你要定义好日志的内容。

比如点赞数量,在 Visualize 里面新建一个柱状图,搜索 item.verb="点赞",然后第一个 Y 轴聚合搜索出来的日志条数,就是点赞的数量,再添加一个 Y 轴 Unique Count item.actor.username.keyword 就能得出多少个用户产生了这么多赞,X 轴就是按照时间,我都是按天来,选择 Date HistogramIntervalDaily,如果你的日志系统要求的实时性比较高,还能选择 Hourly,然后把实时刷新打开,就能看到比较实时的数据了。

3
4

Kibana 最终是这个样子:

0
1

过几天我把这个东西拆分出来变成一个仓库再详细写一下教程。