某电商大促系统崩溃运维三天找不到错误日志改用ELK日志分析工具后两分钟定位故障根源
这事发生在去年双十一前夕,我们公司那套电商系统上线了新的推荐算法模块,说是能提升转化率。结果大促第一天,下午三点多,系统直接崩了。
崩溃那天,我们真的慌了
下午三点,监控告警响了。客服那边开始收到用户反馈,说下单页面加载不出来。运维负责人老张第一时间冲进会议室,我们一群技术人围着一排屏幕,发现系统响应时间从200毫秒飙到了12秒,然后全部超时。
“重启!”老张喊了一声,两个微服务被重启了,但问题依旧。
接下来的三天,我们像无头苍蝇一样乱撞。
第一个小时,我们排除了数据库连接池的问题,查看了监控面板,CPU和内存使用率都正常,磁盘I/O也没问题。
第二个小时,我们开始翻日志。问题来了——日志太多了。我们用的是Spring Boot微服务架构,每个服务都有各自的日志文件,分散在不同的服务器上。有的服务日志按天切割,有的按小时切割,有的根本没做切割。光是一个用户请求链路,就要跨七个服务,每个服务产生几十行日志。
我们 tried everything。
第三天下午,老张红着眼睛说:”三天了,连个错误日志都没找到,用户投诉已经排到后面去了,再这样下去,公司要赔钱。”
我坐在那儿,看着满屏幕的日志文件,突然想到一个问题:我们到底是在找错误,还是在找一根针?
那天晚上,我决定赌一把。
为什么三天找不到错误日志
说实话,这件事让我深刻反思了几个问题。
第一,日志散乱无章。 我们的七个微服务分散在七台服务器上,每台服务器上跑着多个容器,每个容器都有自己的日志文件。没有统一的日志收集系统,想找一条日志,就像在图书馆里找一本没有书名的书。
第二,日志格式不统一。 有的服务用JSON格式,有的用纯文本,有的连时间戳都没有。不同语言的日志格式还不一样,Java的栈trace和Python的traceback长得不一样,混在一起根本没法看。
第三,查询效率极低。 我们用grep命令在服务器上搜关键字,搜”exception”,搜”error”,搜”timeout”。结果呢?grep出来几百万行日志,要手动过滤、比对、拼接请求链路。三天时间,大部分都花在这件事上了。
第四,缺乏日志监控和告警。 我们没有设置任何基于日志的告警规则,错误日志只是静静地躺在文件里,没人知道它们存在,直到系统出问题后才想起去翻。
ELK是怎么救场的
第二天早上,我带着团队开了一个紧急会议,决定引入ELK日志分析平台。
ELK是Elasticsearch、Logstash、Kibana三个工具的缩写。我简单解释一下它们各自是干什么的:
- Logstash 是一个日志收集和处理工具,它可以从各个服务器、各个服务把日志收集起来,进行格式化处理,然后发送给Elasticsearch。
- Elasticsearch 是一个搜索引擎,它能把所有日志存储起来,并提供强大的搜索和分析能力。你可以用简单的查询语句,快速找到某条特定的日志。
- Kibana 是一个可视化界面,它可以把Elasticsearch里的数据做成图表、仪表盘,让你一眼就能看到系统状态。
我们花了半天时间搭建了ELK平台。Logstash配置了从七台服务器收集日志的规则,Elasticsearch创建了对应的索引,Kibana搭好了仪表盘。
然后,我们重新搜索那三天崩溃期间的日志。
两分钟。
真的,就两分钟。
我在Kibana的搜索框里输入了这样一条查询:
@timestamp:2024-11-11T15:00:00 TO 2024-11-11T15:30:00 AND (level:ERROR OR level:FATAL)
搜索结果出来了,几十条错误日志。我点进去一看,发现了一个规律——所有错误都指向同一个服务:recommendation-service(推荐服务)。
再往下翻,找到了一条关键的异常信息:
java.lang.OutOfMemoryError: Java heap space
at com.example.recommendation.service.RecommendAlgorithm.calculate(RecommendAlgorithm.java:127)
at com.example.recommendation.controller.RecommendController.recommend(RecommendController.java:45)
原来如此!推荐算法模块在计算用户画像时,加载了过大的内存数据集,导致JVM堆内存溢出。这个服务在重启后内存恢复正常,但当用户量增加时,问题又会复现,只是这次我们不知道原因。
ELK为什么能这么快
回过头来想,为什么三天找不到,两分钟就找到了?
首先是日志集中。 ELK把七个服务、七台服务器的日志全部收集到了一个地方,统一存储,统一搜索。不用再一台一台服务器去登、去翻。
其次是搜索能力强大。 Elasticsearch支持全文搜索、过滤、聚合等高级查询功能。你可以按时间范围、按日志级别、按服务名、按关键字随便组合查询,几秒钟就能筛出目标日志。
第三是可视化直观。 Kibana的仪表盘让你一眼就能看到系统的关键指标,错误率、响应时间、流量趋势,一目了然。不用手动看日志,系统会自动帮你发现问题。
第四是实时性强。 ELK平台可以实时收集和处理日志,发现问题可以即时告警,不用等用户投诉了才去查。
搭建ELK的基本思路
如果你也想搭建类似的日志分析平台,这里有一个简单的思路:
第一步:收集日志
用Logstash或者Filebeat(轻量级日志采集器)从各个服务器收集日志。配置方式大概是这样的:
input {
file {
path => "/var/log/myapp/*.log"
start_position => "beginning"
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}" }
}
date {
match => [ "timestamp", "ISO8601" ]
}
}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "myapp-logs-%{+YYYY.MM.dd}"
}
}
这段配置的意思是:从指定目录收集日志文件,用grok插件解析日志格式,提取时间戳和日志级别,然后把处理后的日志发送到Elasticsearch,按天创建索引。
第二步:存储和搜索
Elasticsearch接收日志后,会建立倒排索引,支持快速搜索。你可以用Kibana的Discover页面做各种查询,也可以用Elasticsearch的API直接查询。
第三步:可视化和告警
Kibana可以创建各种仪表盘和图表,把关键指标展示出来。同时可以设置告警规则,当某个指标超过阈值时,自动发送通知。
从这次事件中我们学到了什么
这次事件给了团队一记响亮的耳光。
我们之前总觉得日志收集是小事,等出了问题再去想办法。结果这次吃了大亏,三天找不到问题,用户投诉、公司损失,代价太大了。
现在我们的系统里,ELK平台是标配。所有服务必须把日志输出到标准输出,由Logstash统一收集。所有日志必须包含时间戳、日志级别、服务名、请求ID这些基本信息。我们还设置了日志告警规则,关键错误会即时通知运维人员。
有时候我觉得,运维这件事就像医生看病。你总不能等病人病危了才去查病因吧?平时就得做好体检,发现问题及时处理。日志分析平台就是我们的体检中心,能帮我们提前发现隐患,把问题消灭在萌芽状态。
那次崩溃之后,老张在团队群里说了一句让我印象很深的话:”我们不是在找日志,我们是在找用户。每一行日志背后都是一个真实的用户,他们在购物,在付款,在期待。我们查不清问题,就是在辜负他们的信任。”
这话我记到现在。
技术这东西,说到底是为了人服务的。能帮用户解决问题,能减少他们的困扰,这才是我们做系统的意义。ELK也好,其他工具也好,都是手段,不是目的。关键是我们有没有用心去用它,去把事情做好。
现在每次大促,我都不会太紧张了。因为我知道,就算出了问题,我们也有能力快速定位和解决。这得益于ELK平台,也得益于那次崩溃让我们真正重视起来了日志管理这件事。
如果你也在为日志管理头疼,不妨试试ELK。它不会让你一夜之间变成运维专家,但绝对能帮你省掉很多翻日志的煎熬。