日志服务(SLS / CloudWatch)入门
说实话,我做了七八年运维和Serverless开发,最怕的不是代码抛异常,而是系统跑着跑着突然“没声音了”——你不知道它在干嘛,它也不知道你急不急。那时候你就会明白,日志不是什么“事后诸葛亮”,而是系统的体检报告和黑匣子。
但直接写日志文件不行。你想想看,一个微服务集群每天产生几百GB的日志,你难不成一台台机器上去tail -f?我们得有个“日志采集中台”,把分散的日志统一收上来,再让你能搜、能看、能设告警。这一章,我就带你把这个“中台”搞明白。
1. 日志采集中台的基本概念
什么是日志采集中台?说白了,就是个“日志路由器”。它的职责很简单:统一接入、结构化存储、快速查询。
我习惯把它拆成三层:
- 采集层:Logtail(阿里云)、CloudWatch Agent(AWS)、Fluentd/Logstash 等,负责从各种源头拉日志。
- 存储层:SLS Logstore、CloudWatch Logs Group,核心是写索引+存储原始数据。
- 查询层:提供SQL-like查询语法,实时检索或者跑统计分析。
嗯,你在云平台上看到的“日志服务”页面,其实就是这三层的整合界面。之前我在一个IoT项目里,设备每天上报几百万条状态日志,如果直接从业务数据库里查,数据库早就挂了。后来我把它们全扔进SLS,按小时建索引,查询从秒级降到了毫秒级。这就是中台的威力。
2. 日志组与日志流
刚接触日志服务时,我总觉得“日志组”和“日志流”这两个概念有点绕。我试着用一句话说清楚:
日志组(Log Group) 是一个逻辑容器,它包含一组相关的日志流。通常你可以按项目、环境或应用来划分。而日志流(Log Stream) 是真正写入日志数据的通道,每个日志流对应一个日志来源(如一台ECS、一个Pod、一个Lambda实例)。
举个例子,我在管理一个电商系统时,会把“订单服务”放到一个日志组里,该组下面有10个日志流,每个对应一个订单服务的Pod。
我曾经犯过一个错误:把所有服务的日志都塞进同一个日志组。结果查询时,日志流太多,索引分片被打满,写入限流了。你想想看,故障发生时不仅看不到日志,还影响了后续写入——这叫“二次故障”,特别要命。
每个微服务对应一个日志组,日志组下按实例或容器创建日志流。不要把所有POD塞到同一个日志流,会导致写入竞争和查询慢。
3. 索引与查询
日志不建立索引,就像书没有目录——你只能一页页翻。你肯定不想在几十TB的日志里用grep,对吧?
SLS和CloudWatch日志服务的索引分为两类:
- 全文索引:对日志的全文内容进行分词和倒排索引。适合“我随便搜关键字”的场景。
- 键值索引:对特定的字段(如
status、duration_ms)建立索引。适合做统计分析、告警和精确查询。
我建议你在正式上线前,先想清楚需要查询哪些字段,提前建好键值索引。上次有个客户抱怨日志查不到,我一看,他开了全文索引就以为万事大吉,但实际需要按 user_id 查某用户的请求记录——这不建索引,当然慢。
查询语法也值得一说。阿里云SLS用 search | sql 的管道方式,AWS CloudWatch用 filter + stats。下面是个经典查询,用来查某个API在过去1小时的调用量和平均延迟:
# SLS 示例
* | SELECT
count(*) as call_count,
avg(latency_ms) as avg_latency
WHERE api_name = '/order/create'
GROUP BY time_series(__time__, '1h')
# CloudWatch Logs Insights 示例
fields @timestamp, latency_ms
| filter api_name = '/order/create'
| stats count() as call_count, avg(latency_ms) as avg_latency by bin(1h)
我见过很多开发者在查询时忽略 __time__ 或 @timestamp 字段,结果查询范围是“所有时间”,扫了全量索引,费用直接翻了几倍。嗯,这里要提醒你:查询时务必加上时间范围,这既省时间又省钱。
4. 日志存储周期与费用
日志存储多久?我遇到的新手最容易踩的坑就是“全量永久保留”。你觉得几块钱一GB好像不贵,但你算过一个月100GB日志存365天的费用吗?
让我们来拆解一下日志服务的计费模型:
| 费用项 | 说明 | 优化建议 |
|---|---|---|
| 写入流量 | 每写入1GB数据收取xxx元 | 压缩日志或关闭不必要的debug日志 |
| 存储空间 | 按每天实际存储容量计费,单价通常按“GB/天”算 | 设置合理的生命周期,非核心日志保留7天即可 |
| 索引流量 | 建立索引也会产生流量费用 | 只对必要字段建键值索引 |
| 查询扫描数据量 | 按每次查询扫描的日志量计费 | 缩小时间范围、使用精确的查询语句 |
error_code、request_id、latency_ms 三个字段建索引,费用直接降了80%。别学他的“全裸奔”策略。
- 生产环境错误日志:30天
- 审计与合规日志:90天~180天
- Debug/Trace日志:3~7天
- 超过保留期的日志自动过期删除——别手动删,靠配置。
5. 一张图看懂日志服务的核心结构
为了让你更直观地理解,我画了张结构图。它展示了日志采集中台的核心组成部分和数据流动方向。
你从图里可以看到,日志从采集层进入日志组,再往下分到各个日志流。日志流的内容同时写入索引和原始存储,最后供查询与分析层使用。每个日志流都绑定了一个具体的日志来源(一台机器、一个Pod或一个函数实例),这样你在排查问题时就能精准定位到“哪个实例在异常”。
我个人习惯在创建日志组时就规划好命名规范:{project}-{env}-{service}。比如 mall-prod-order、mall-dev-user。这样后面查日志、配告警都清晰很多。