日志的log中如何输出变量_9个技巧,解决K8s中的日志输出问题
来源|阿里巴巴云原生如何为 Kubernetes 构建一个日志系统?这是很多技术人关心的话题,日志越规范化,越能减少收集、解析、分析的代价。日前,阿里云存储服务技术专家元乙以系列文章的形式分享了 Kubernetes 日志系统的落地实操经验。该系列的第三篇文章列举了 Kubernetes 中,日志输出的常见注意事项,具体如下。1. 如何选择日志等级日志等级是用来区分日志对应事件严重程度的说明,这是
来源|阿里巴巴云原生
如何为 Kubernetes 构建一个日志系统?这是很多技术人关心的话题,日志越规范化,越能减少收集、解析、分析的代价。日前,阿里云存储服务技术专家元乙以系列文章的形式分享了 Kubernetes 日志系统的落地实操经验。该系列的第三篇文章列举了 Kubernetes 中,日志输出的常见注意事项,具体如下。
1. 如何选择日志等级
日志等级是用来区分日志对应事件严重程度的说明,这是所有日志中必须具备的一个选项。通常日志会分为 6 个不同的等级:
致命(FATAL):用来输出非常严重或预期中不会发生的错误,遇到此种错误应当立即报警并人工介入处理;
- 错误(ERROR):非预期中的错误,此种错误可能导致部分系统异常但不会影响核心业务和系统正常运行;
- 警告(WARN):潜在的危险或值得关注的信息(比较核心的路径);
- 信息(INFO):应用执行过程中的详细信息,一般通过该信息可以看到每个请求的主要执行过程;
- 调试(DEBUG):用于线下调试的日志信息,用于分析应用执行逻辑,线上应用切勿开启;
- 跟踪(TRACE):输出最细致的运行轨迹,可能包含涉及的数据内容。
作为程序员,一定要合理设置日志等级,元乙在开发过程中总结了以下几点经验:
- “致命”类型日志一定是非常严重的错误、需要人工处理的场景打印;
- “错误”和“警告”的区别,可以从告警角度考虑:“错误”一般需要告警,“警告”不需要;
- 日志等级一方面是为了能够表示日志的严重程度,另一方面也是为了控制应用程序的日志输出量,通常线上只能打开“信息”或“警告”的日志;
- “调试”日志可以多打,方便分析问题;
- 所有用户请求日志,必须记录;
- 对于不确定的外部系统调用,日志须尽可能覆盖周全;
- 程序中的日志库需要具备运行期间变更日志等级的能力,方便在遇到问题需要分析时临时更改日志等级;
- 在新功能上线时,涉及的日志可适当提升一个等级,方便实时观察和监控,待稳定后再调整到正常(记得加上注释,方便改回来)。
2. 日志内容规范
一个约束开发者的日志规范是有必要的,让所有日志看起来是一个人打印的而且是易于分析的,避免出现只有开发者自己才能看懂日志的情况,这很难进行分析和告警。
日志的字段
因为日志中通常必备的字段有:Time、Level、Location。对于特定模块 / 流程 / 业务,还需要有一些 Common 的字段,例如:
- 如果使用 Trace 系统,可以把 TraceID 附加到日志中;
- 固定的流程需要附加对应的字段;
- HTTP 请求需要记录:URL、Method、Status、Latency、Inflow、OutFlow、ClientIP、UserAgent 等,详情可以参考 Nginx 日志格式;
- 如果多个模块的日志都打印到同一个流 / 文件中,必须有字段标识模块名。
日志的字段规约最好由运维平台 / 中间件平台自顶向下推动,约束每个模块 / 流程的程序员按照规定打印日志。
日志表现形式
建议使用 KeyValue 对形式的日志格式,这种格式可以完全自解析且易于理解,同时便于日志采集时自动解析。也可以采用 JSON 日志格式,支持以 JSON 格式输出的日志库很多,而且大部分的日志采集 Agent 都支持 JSON 格式的日志收集。
另外,绝大部分场景中不建议使用非可读的日志格式,例如 ProtoBuf、Binlog 等。
单条日志换行问题
非必要情况下,尽量不要一条日志输出成多行,否则采集、解析和索引的代价都比较高。
3. 合理控制日志输出量
日志的输出量直接影响磁盘使用以及对于应用的性能消耗,日志太多不利于查看、采集、分析;日志太少不利于监控,同时在出现问题的时候没办法调查。
一般线上应用需合理控制日志的数据量:
- 服务入口的请求和响应日志没有特殊原因都要输出并采集,采集的字段可以根据需求调整;
- 错误日志一般都要打印,如果太多,可以使用采样方式打印;
- 减少无效日志输出,尤其是循环中打印日志的情况需尽量减少;
- 请求型的日志一般不超过 5MB/s,应用程序日志不超过 200KB/s。
4. 选择多种日志输出目标
建议一个应用不同类型的日志输出到不同的目标(文件),这样便于分类采集、查看和监控。例如:
- 访问日志单独放到一个文件,如果域名不多,可以按照一个域名一个文件的形式;
- 错误类的日志单独放一个文件,单独配置监控告警;
- 调用外部系统的日志单独放一个文件,便于后续对账、审计;
- 中间件通常都由统一的平台提供,日志一般单独打印一个文件。
5. 控制日志性能消耗
日志作为业务系统的辅助模块,一定不能影响到业务的正常工作,因此日志模块的性能消耗需要单独额外注意。在选择 / 开发日志库时,需要对日志库进行性能测试,确保正常情况下日志的性能消耗不超过整体 CPU 占用的 5%。另外,一定要确保日志打印是异步的,不能阻塞业务系统运行。
6. 如何选择日志库
开源的日志库非常多,基本每个语言都有数十种,选择一个符合公司 / 业务需求的日志库需要精挑细选,有一个简单的指导原则是尽可能使用比较流行的日志库的稳定版本,入坑的几率要小一点。例如:
- Java 使用 Log4J、LogBack;
- Golang 使用 go-kit;
- Python 默认集成的日志库大部分场景都够用,建议阅读一下 CookBook;
- C++ 推荐使用 spdlog,高性能、跨平台。
7. 日志形态选择
在虚拟机 / 物理机的场景中,绝大部分应用都以文件的形式输出日志(只有一些系统应用输出到 syslog/journal)。而在容器场景中,多了一个标准输出的方式,应用把日志打到 stdout 或 stderr 上,日志会自动进入 docker 的日志模块,可以通过 docker logs 或 kubectl logs 直接查看。
容器的标准输出只适应于比较单一的应用,例如 Kubernetes 中的一些系统组件,线上的服务类应用通常会涉及多个层级(中间件)和各种服务交互,日志都会分为好几类,如果全部打印到容器的标准输出,很难区分处理。
同时容器标准输出对于 DockerEngine 的性能消耗特别大,元乙实测 10W/s 的日志量会额外占用 DockerEngine 1 个核心的 CPU(单核 100%)。
8. 日志是否落盘以及落盘介质
在 Kubernetes 中,还可以将日志库直接对接日志系统,日志打印时不落盘而直接传输到日志系统后端。这种使用方式免去了日志落盘、Agent 采集的过程,整体性能会高很多。
在日志量极大的场景可以使用这种方式,普通情况下直接落盘。相比直接发送到后端的方式,落盘增加了一层文件缓存,在网络失败的情况下还能缓存一定的数据。在日志系统不可用的情况下,研发和运维同学可以直接查看文件日志,提高整体的可靠性。
Kubernetes 提供了多种存储方式,一般在云上,都会提供本地存储、远程文件存储、对象存储等方式。由于日志写入的 QPS 很高,和应用也直接相关,如果使用远程类型的存储,会额外多 2-3 次网络通信开销。建议使用本地存储的方式,可以使用 HostVolume 或者 EmptyDir ,尽可能小的影响写入和采集的性能。
9. 如何保证日志存储周期
相比传统虚拟机 / 物理机的场景,Kubernetes 对于节点、应用层提供了强大的调度、容错、缩 / 扩容能力。通过 Kubernetes ,很容易就能让应用获得高可靠运行、极致弹性。这些优势带来的一个现象是:节点动态创建 / 删除、容器动态创建 / 删除,这样日志也会随时销毁,没办法保证日志的存储周期满足 DevOps、审计等相关的需求。
在动态环境下实现日志的长期存储只能通过中心化的日志存储来实现,通过实时的日志采集方式,将各个节点、各个容器的日志在秒级内采集到日志中心系统上,即使节点 / 容器挂掉也能够通过日志还原当时的现场。
以上就是元乙解决 Kubernetes 日志输出问题的技巧,希望对你有所帮助。
更多推荐
所有评论(0)