如何排查线上问题-日志系统

最近做的一个项目,线上时不时会出点问题,而组内就我一个人会后端,其他组员都是前端人员,出现线上问题后就只能我自己排查。因此我准备整理下线上问题的一些排查流程和方法,让大家都能处理类似的问题。

ELK

graph LR
A("Logstash-数据的收集、处理和转发") -->B("Elasticsearch-存储、搜索和分析") -->C(Kibana-可视化)

ELK 是一个流行的开源,用于处理和分析大量数据,特别是在日志管理和日志分析领域。ELK 代表三个主要组件:

Elasticsearch

一个基于 Lucene 的搜索和分析引擎,提供了全文搜索和分析的能力。Elasticsearch 能够存储、搜索和分析大数据集,并且具有高可扩展性和实时性。

Logstash

一个服务器端数据处理管道,可以同时从多个来源采集数据,转换数据,然后将数据发送到您指定的存储库中。Logstash 常用于日志数据的收集、处理和转发

Kibana

一个开源的数据分析和可视化平台,用于探索和可视化 Elasticsearch 中的数据。Kibana 允许用户创建仪表板,展示实时数据,并进行深入分析。

这三个工具共同工作,形成了一个强大的日志分析解决方案:
Logstash 负责从各种来源(如服务器、应用程序、网络设备等)收集日志数据,并进行预处理(如过滤、格式化等),然后将处理后的数据发送到 Elasticsearch。
Elasticsearch 负责存储、索引和搜索这些日志数据,使其可以快速检索和分析。
Kibana 则用于可视化这些数据,帮助用户理解数据模式、趋势和异常。

ELK 栈因其强大的搜索能力、灵活的数据管道和直观的可视化而受到广泛欢迎。它不仅可以用于日志分析,还可以用于监控、安全分析、业务智能等多种场景。随着技术的发展,ELK 栈也扩展到了更多的组件,如 Beats(轻量级的数据收集器)和 X-Pack(提供安全和高级功能),从而形成了更加完整的 Elastic Stack。

日志

优秀的日志信息是排查问题最好的指引。

为什么把日志放在第一位?因为你最了解程序的时候,一定是你写程序的时候。而这个时候添加的日志信息,是最能帮助你了解程序运行状态的。如果没有日志,那么一旦出现问题,要么你就只能靠经验去排查,要么就只能靠蒙。而这两者都很不靠谱,因为这可能导致你无法真实评估解决问题的成本以及恢复的时间。

日志的分类

服务器 Nginx 日志

这是用户请求到达服务端后的第一层我们能接触到的日志,一般我们从这个日志开始排查问题。

这是 Nginx 自带的,我们可以根据自己的需求对日志进行配置。但是注意不要在这里记录太多、太大的信息,比如 POST 请求的实体,一般就是不记录的,因为 Nginx 请求数量可能会很大(视用户规模和请求频次),而记录日志本身也是有开销的,如果这里记录的信息太多了,会导致影响用户请求的性能,也会浪费磁盘资源。

默认的 Nginx 日志格式类似这样:

1
log_format main '[$time_local] [$remote_addr] [$COOKIE_userid] [$request] [$status] [$body_bytes_sent] [$http_referer] [$http_user_agent] [$http_x_forwarded_for] [$request_time] [$upstream_addr] [$upstream_response_time] [$http_host] [$request_body] [$uri] [$server_port] [$remote_user] []';

应用框架自身的日志

我们用的是 Egg.js 这个框架,框架自身在运行期间会有一些过程和状态信息,会写入日志。

框架进程相关的日志,一般是写到/root/logs/目录下,比如:

1
2
/root/logs/master-stderr.log
/root/logs/master-stdout.log

举个例子:如果框架进程需要往某个文件里面写入信息,但是发现这个文件没有写入权限,那么就会在/root/logs/master-stderr.log 中记录一条日志信息。

框架的应用日志,一般是写到/root/logs/${appName}/目录下,比如:

1
2
3
4
/root/logs/resource/egg-agent.log
/root/logs/resource/egg-schedule.log
/root/logs/resource/egg-web.log
......

自定义的程序日志

我们在编写逻辑代码的时候,经常需要记录过程输出,帮助我们了解程序的运行状态,这部分就是程序日志了。为了让我们的线上日志能接入公司的 Kibana,方便我们在内网直接查看日志信息,我们的自定义日志需要符合一定的格式要求,这个下面会详细说一下。

自定义日志功能的实现,是扩展了 Egg 自身的日志功能,具体可以看下 app/extend/application.js 这个文件。

哪些内容应该/不应该记录为日志?

几个不能多记录的场景:

  • 请求级别(Context)的日志尽量少记
  • 频繁执行的脚本的过程日志尽量少记
  • 循环中的日志,需要谨慎思考后再记录

几个不能少的场景:

  • 长流程的过程日志,方便你知道程序执行到哪一个流程出问题了

日志应该包含什么信息?

日志是给我们排查问题的时候看的,所以一定要保证:

1、人能看懂(比如你记录一个“failed”,就什么帮助都没有)

2、带有对调试和修复问题有帮助的信息(比如请求出问题了,那么请求 url、参数、返回的请求头、返回结果等,都可以记录一下)

日志如何接入 Kibana?

具体操作流程可以参考这个生产环境日志接入

kibana 使用文档

日志格式规范

实时性与成本

ELK 常见问题汇总

graph LR
A("注册登记日志信息") -->B("按照格式规范写入容器的本地文件") -->C(平台自动同步采集)-->D(查看日志)

如何在内网查看日志?

kibana 使用文档

这里需要注意的是,查看日志要掌握一定的Lucene Query语法。

查询语法

注意:404应该选择正常的nginx日志,不是nginx_error

根据状态码查询:
status: 404

字符串匹配:
message: *micro*

监控工具

邮件/Vanish 报警/短信

一般我们用这种通知手段来进行如下情况的处理:

1、出现重要且紧急的问题(影响用户数达到一定规模,或者是核心重点功能),三种方式一起发,保证通知到位

2、中等以下紧急的事情(非核心功能出现问题,比如数据延迟、更新数据的接口报错等),以邮件+Vanish 的形式发送

3、一些定时的分析报告,以邮件的形式发送,比如某个应用的每日运行数据的统计这种,原因是邮件的表达能力更强一些(支持 HTML)

云平台监控工具

公司的云平台的监控工具的使用和分析。

正常值与异常值的感知

虽然很多监控工具自身已经能进行异常提醒和标注了,但是我们还是需要对一些常见的数据有一个概念,比如 I/O、CPU、内存、磁盘等等达到多少算是有问题,这样在查看监控工具的时候,才能知道到底目前的状态是否正常,以及可能导致问题的原因是什么。