日志平台设计时考虑的一些问题
日志其实也是一种时序数据,在典型的opentsdb中,时序数据模型包括metricname,value,ts(tiimestamp)以及若干tagkey,tagvalue这些字段
在metrics体系中,value一般是数值类型,整体的数据结构、数据类型相对固定。
而日志虽然也是时序的,但是它的value却是一行或者几行文本,通常不是结构化的,数据大小有几K,一些没有规范约束的情况下,用户的单行日志可能到几M。
应用日志有个特点,就是经常会被调整内容,日志是为了帮助开发者了解程序运行的一些状况,因此在迭代的过程中,程序员修改打印的日志信息是很常见的。
在使用日志平台的时候,用户其实有几个基本的需求:
1是类似用shell命令的tailf -f的方式实时观察日志输出,即livetail
2是查找关键字,比如exception,或者业务相关的一些信息,希望搜索出来出现关键字的日志前后片段,帮助他分析问题,就好像在看服务器上实际的日志文件一样
3是要统计分析,通过统计发现问题,比如500状态码每天出现了多少次,异常调用的情况有多少等等。
要满足这些基本的需求,日志搜集到平台,要提供几个基本的功能
1、按照时间排序,即数据展示的时候,要有顺序,有时候光有时间还不够,还需要文件的offset帮助,才能实现上下文分析
2、搜索过滤的能力,查询性能越快越好
3、日志搜索查询时的再处理能力
第3点是什么意思呢,比如我们使用es过程中,也有一些痛点,我要统计一些字段的时候,需要在写入之前将这个字段从文本数据中解析出来,单独作为一个字段写进es(有些情况下,可能还需要对部分字段做mapping设置固定数据类型,而es因为有字段类型,所以每次插入一条数据,还要做去全局的数据类型冲突检查,性能会比较差),
在kibana上面我才能统计分析这个字段,如果没有事先解析,用的时候就没有办法针对这个字段做统计,比如查询的时候对message字段再分词,再groupby等等,就不支持。
日志分析往往带有随意性,即时性,事先就把字段拆出来再入库,对于经常变化的日志来讲,很棘手。今天要提取N个字段,明天可能要增加到M,用户应用迭代升级,日志格式可能发生了调整,解析日志然后写es的程序就会失败,导致日志丢失。
解决这种问题的办法只有一个,就是在分析查询的时候,提供灵活强大的再解析,再计算的能力,这其实也是一种tradeoff,为什么呢?
日志其实是一个流量比较大的数据流,一个公司各个应用,设备,服务器等产生的日志汇集到你的日志平台,可能达到几十万甚至百万行每秒,因此日志平台的写性能一定要高,你不能在写的时候做很多流程很长,耗时很久的动作,要快速的持久化。最合理的方案就是顺序写,像kafka那样顺序写,只有顺序写才能获得性价比最高的写性能。
但是仅仅像kafka那样顺序写,还不够,因为仅仅有时间一个维度的索引,查询性能会比较差,还要加入一些必要的索引,让数据定位尽量快速,而不是扫描大量的无用数据
索引还不能太多,索引到极致等于是做倒排,因此这里还有很多的tradeoff。
日志通过必要的索引找到之后,要实现搜索,分析,统计,那么就要对这些数据进行处理,因为是分布式的,所以还要汇总聚合处理后的结果,相当于做一个分布式的内存MapReduce操作
通过时间和标签索引找到的数据,说白了要做关键词过滤,搜索,因为没有额外的索引信息,就只能做内存的grep了,当然我们在存储的时候可以增加一些hash过滤器,bloom过滤器等加快过滤的速度;在分析统计方面,需要一个分布式的MapReduce过程,这方面我们可以借助一些可嵌入的一些计算框架。
日志其实是比较容易获得高压缩比的一种数据类型,压缩比可能有8-10,这可以大大节省存储空间,同时也可以提升数据处理速度,比如我要加载10个G的原始数据然后处理,跟加载1个G的压缩后的数据再解压处理,哪个更快?显然压缩后的速度更快。