编程入门之日志聚合系统
一、啥是日志, 为啥要聚合
面试初级同学常问的问题之一就是,一个在线运行的生产系统,如果出现了一些在测试环境复现不了的bug该如何处理啊?错误回答:“我们的系统从没有出过问题”,正确回答:“加日志”。
对于不能稳定复现,或者不方便调试的场景, 通过在程序的执行路径上增加一些文字的记录,输出为文件,供后续分析查看程序的执行过程,是谓之日志。日志可以24小时,无人值守的忠实记录程序的执行过程,是排查偶发问题,以及运维监控利器。
日志一般都存在级别(error,warn,info,debug)的概念,详尽程度依次递增, 因为写日志本身也会产生磁盘IO,占用系统资源,所以在生产环境一般不会输出debug级别日志。日志文件的扩展名通常为.log.
if(a>1){ log.i("a>1"); //日志 }else{ log.i("a不大于1"); //日志 }
——日志
那为啥是日志聚合呢?实际场景中,日志文件通常不会是简简单单的一份, 例如现在流行的微服务,或者分布式部署。一个系统各个模块被运行在不同的系统进程,甚至于不同的物理服务器上。这样就会产生数个日志文件, 分布在不同的文件夹或者不同的计算机上。 如果我想完整的跟踪一个用户操作(如下订单),如果这不是一个简单的单进程服务器,那我只能去依次打开,各个模块所输出的日志文件,然后根据时间人肉拼凑在一起看。由于系统是多线程多用户的,在多个日志文件中关联追踪一笔业务的发生过程,会非常繁琐。
文章图片
——模拟多线程,多用户系统的日志文件内容
聚合就可以理解为把这些分散的日志文件,合并到一起,可以统一的查询,过滤。
二、日志收集系统原理组成
如何可以把日志收集到一起,并方便查看呢? 比如一个简单直接的想法就是各模块都把日志存储到一个统一的数据库中,这样就可以统一存储,查询了。其实日志收集系统的基本原理也是如此。基本分为
收集器 —— 可以看做数据库的客户端驱动,读取日志文件,通过网络发送给存储中心。
日志存储(数据库)—— 可以看做数据库,把收集器收集到的文件存储下来,并提供查询功能。通常支持特定的简单查询语言,可以通过编写脚本的方式查询。
查询界面 —— 类似于图形界面的数据库查询工具,提供直观的操作交互,比黑洞洞的控制台体验好的多。
文章图片
——日志被自下而上收集,用户通过图形界面统一查询
三、全文索引与轻量化
【编程入门之日志聚合系统】在日志收集的这三个角色中,日志收集器与图形界面都相对简单,容易理解,而日志的存储查询部分则要复杂一些。
日志通常条数众多,一个有一定有户数的WEB系统,每天产生个几千上万个W条数的日志,都是毫不意外地。对于这样多的日志数据,如何提供快速查询能力,是要想点特殊的办法的。简单的记事本字符串查询的方式,等结果可能会到天荒地老。
全文索引 —— 就是对一段特定的文本进行预处理,生成一个处理结果,这个结果记录了,每个文字/单词,在文档中出现的位置,并将这个结果存储起来,后续利用这个预处理结果,当你想查找一个文字/单词时,就可以快速的给出,包含这个字词的行数。
第一行:我很丑可是我很温柔 第二行:我很丑可是我有音乐和啤酒索引 我: 第一行,第二行 丑:第一行,第二行 音乐:第二行。 ……
——全文索引简单原理说明,搜索我时,则可以快速的定位到第一第二行。
从上面的简单介绍可以看出,如何分词是有很有技术含量的,分词方法会影响索引结果的大小,进而与查询效率有关。而通常索引文件都是大于被索引的内容本身的。
对日志内容进行全文索引,优点是可以提供较好的查询效率,缺点则是需要更多的存储空间,更大的磁盘,更好的硬件则意味更多的¥ :-)。著名的ELK日志聚合解决方案中的存储部分Elasticsearch就是采用全文索引技术,提供搜索优化的。
轻量化 —— 如果没有¥,但是有时间,也是有解决方案的。比如我有多套开发,测试,联测环境,用ELK这类全文索引类的存储太占地方。不做全文索引,用蛮力进行字符串搜索的方案也是存在的,如Grafana Labs 的 Loki。像标称的那样,的确很轻量化,安装简单,配置简单,不需要太多的存储空间,在处理的日志不是太多时,搜索效率完全可以接受。更多信息:https://grafana.com/oss/loki/
四、滚(Rolling)
只要程序在运行,日志就会源源不断产生。于是终于有一天会占满全部硬盘,然后就没有然后了。所以日志文件的生成,要记得配置滚动周期,让超期的日志文件自动删除。这点对于日志聚合系统来说也非常重要,可能更加重要,因为毕竟是一个存储中心,会存储多个收集器同步的日志文件,不定时清理,会很快被塞满。
~~最后, 希望能帮助入门的同学,愿世界和平~~~!
推荐阅读
- Three.js之绘制中文文字并跟随物体
- 分析机器学习之决策树Python实现
- javascript之Object.assign()的痛点分析
- 关于Java错误提示之找不到或无法加载主类的问题及正确处理方法
- 历史上的今天|【历史上的今天】1 月 31 日(Python 之父出生;宏碁大战联想;SBC 收购 AT&T)
- 详解HTTP 与 HTTPS 的不同之处
- [Golang]力扣Leetcode—中级算法—其他—两整数之和(位运算)
- Linux性能优化实战CPU篇之软中断(三)
- 02|02 - 入门 & Nginx 服务 & Docker 概念【合集】
- Vue|Vue 源码解读(8)—— 编译器 之 解析(下)