2. 单体架构日志方案:本地文件日志、日志轮转策略、单机ELK搭建与配置
在单体应用架构阶段,所有业务逻辑、数据库访问、缓存操作均运行在同一个进程内。日志方案的核心诉求是简单、可靠、可排查,无需复杂的分布式追踪。本章聚焦于单体架构下最经典的日志实践:本地文件日志、日志轮转策略,以及单机版ELK(Elasticsearch + Logstash + Kibana)的搭建与配置。
2.1 本地文件日志:单体应用的基石
单体应用通常将日志直接写入操作系统的文件系统。这种方式零依赖、性能开销低,是故障排查的第一手资料。典型的日志文件布局如下:
| 日志文件 | 用途 | 示例路径 |
|---|---|---|
app.log |
业务日志(INFO/WARN/ERROR) | /var/log/myapp/app.log |
access.log |
HTTP请求访问日志 | /var/log/myapp/access.log |
error.log |
仅ERROR及以上级别日志 | /var/log/myapp/error.log |
gc.log |
JVM垃圾回收日志 | /var/log/myapp/gc.log |
/var/log/{应用名}/{模块名}.log 格式。避免将日志写入应用部署目录,防止版本更新时日志丢失。
2.2 日志轮转策略:防止磁盘写满
不进行轮转的日志文件会无限增长,最终耗尽磁盘空间,导致应用异常甚至系统崩溃。日志轮转(Log Rotation)通过按大小或按时间切割文件,并清理过期归档。
2.2.1 基于Linux logrotate的配置
Linux系统自带的 logrotate 是单体架构最常用的轮转工具。以下是一个针对Java应用的典型配置:
/var/log/myapp/*.log {
daily # 按天轮转
rotate 30 # 保留最近30个归档
compress # 压缩归档文件(gzip)
delaycompress # 延迟压缩,保留一个未压缩版本
missingok # 日志文件不存在时不报错
notifempty # 空文件不轮转
copytruncate # 先拷贝再截断,不影响应用写入句柄
dateext # 使用日期作为归档后缀
dateformat -%Y%m%d
postrotate
# 通知应用重新打开日志句柄(如Java的Logback)
kill -USR1 `cat /var/run/myapp.pid` 2>/dev/null || true
endscript
}
copytruncate:对于Java应用至关重要,因为JVM不会主动重新打开日志文件。该参数先复制当前日志内容到归档,然后清空原文件,应用继续写入原文件句柄。postrotate:发送USR1信号给应用进程,触发Logback或Log4j的重新加载,确保日志句柄指向新文件。
2.2.2 轮转策略对比
| 策略 | 触发条件 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 按大小轮转 | 文件达到指定阈值(如100M) | 日志量波动大的应用 | 单文件大小可控 | 归档数量不可控 |
| 按时间轮转 | 到达指定时间点(如每天0点) | 日志量稳定的应用 | 归档时间规律,便于检索 | 高峰日可能单文件过大 |
| 混合策略 | 大小或时间任一条件满足 | 生产环境推荐 | 兼顾文件大小和时间规律 | 配置稍复杂 |
2.3 单机ELK搭建与配置
当单体应用日志量增长到需要集中检索和分析时,单机ELK(Elasticsearch + Logstash + Kibana)是最直接的升级路径。所有组件部署在同一台服务器上,架构清晰,运维简单。
2.3.1 环境准备与版本选择
建议使用ELK 7.x或8.x版本,确保组件间兼容。以下为CentOS 7/8环境下的安装步骤:
# 1. 导入Elastic GPG密钥
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
# 2. 配置YUM仓库(以Elasticsearch为例)
cat > /etc/yum.repos.d/elastic.repo <<EOF
[elasticsearch]
name=Elasticsearch repository
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
EOF
# 3. 安装Elasticsearch
yum install --enablerepo=elasticsearch elasticsearch -y
# 4. 安装Logstash
yum install --enablerepo=elasticsearch logstash -y
# 5. 安装Kibana
yum install --enablerepo=elasticsearch kibana -y
2.3.2 Elasticsearch配置
单机部署需调整JVM堆内存和网络配置,避免默认配置导致启动失败:
# /etc/elasticsearch/elasticsearch.yml
cluster.name: myapp-logs
node.name: node-1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 127.0.0.1
http.port: 9200
discovery.type: single-node
# /etc/elasticsearch/jvm.options
-Xms1g
-Xmx1g
discovery.type: single-node,否则Elasticsearch会因无法发现其他节点而启动失败。JVM堆内存建议不超过物理内存的50%,且最大不超过32GB。
2.3.3 Logstash配置:采集单体应用日志
Logstash通过input插件读取本地日志文件,使用filter插件解析日志格式,最后输出到Elasticsearch:
# /etc/logstash/conf.d/myapp.conf
input {
file {
path => "/var/log/myapp/*.log"
start_position => "beginning"
sincedb_path => "/var/lib/logstash/sincedb"
codec => "plain"
}
}
filter {
# 解析JSON格式日志(如果应用输出JSON)
if [message] =~ /^{/ {
json {
source => "message"
}
}
# 解析标准日志格式:时间戳 [级别] 类名 - 消息
else {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} \[%{LOGLEVEL:level}\] %{JAVACLASS:class} - %{GREEDYDATA:message}" }
}
}
date {
match => [ "timestamp", "ISO8601" ]
target => "@timestamp"
}
mutate {
remove_field => [ "timestamp" ]
}
}
output {
elasticsearch {
hosts => ["http://127.0.0.1:9200"]
index => "myapp-logs-%{+YYYY.MM.dd}"
user => "elastic"
password => "changeme"
}
stdout { codec => rubydebug } # 调试时开启
}
2.3.4 Kibana配置与首次访问
# /etc/kibana/kibana.yml
server.port: 5601
server.host: "0.0.0.0" # 允许外部访问(生产环境建议绑定内网IP)
elasticsearch.hosts: ["http://127.0.0.1:9200"]
kibana.index: ".kibana"
i18n.locale: "zh-CN" # 启用中文界面
启动所有服务后,访问 http://服务器IP:5601,进入Kibana管理界面。首次使用需创建索引模式(Index Pattern),匹配Logstash写入的索引名 myapp-logs-*,即可在Discover页面检索日志。
2.4 单体架构日志方案的局限性
- 单机ELK适合日志量 < 50GB/天、单节点可承载的场景。
- 当应用拆分为微服务后,单机ELK会成为性能瓶颈和单点故障。
- 日志轮转策略在单体阶段是“保底手段”,进入分布式阶段后需配合集中式采集。
单体架构的日志方案虽然简单,但为后续向分布式日志平台演进奠定了扎实的基础。理解本地文件日志、轮转策略和单机ELK的配置,是掌握更复杂日志体系的前提。