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)是最直接的升级路径。所有组件部署在同一台服务器上,架构清晰,运维简单。

单体架构单机ELK日志流 单体应用 app.log / access.log Logstash 日志采集 & 解析 Elasticsearch 存储 & 索引 Kibana 可视化 & 检索 运维/开发人员 所有组件部署在同一台服务器 日志文件通过Logstash采集

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的适用边界:
  • 单机ELK适合日志量 < 50GB/天、单节点可承载的场景。
  • 当应用拆分为微服务后,单机ELK会成为性能瓶颈和单点故障。
  • 日志轮转策略在单体阶段是“保底手段”,进入分布式阶段后需配合集中式采集。

单体架构的日志方案虽然简单,但为后续向分布式日志平台演进奠定了扎实的基础。理解本地文件日志、轮转策略和单机ELK的配置,是掌握更复杂日志体系的前提。