1. 项目概述:构建高可用日志收集系统的必要性
在分布式系统架构中,日志管理一直是个令人头疼的问题。当你有10台服务器时,还能勉强用grep命令应付;但当服务器数量达到100台甚至更多时,传统的日志管理方式就完全失效了。这就是为什么我们需要构建一个集中式的日志收集系统。
我最近在Rocky Linux 9.6上部署了一套基于ELK 7.17.10和Redis 5.0.7的Nginx日志收集系统,这套方案有几个显著优势:首先,Redis作为缓冲队列,能有效应对日志量突增的情况;其次,ELK Stack提供了从收集、存储到可视化的一站式解决方案;最后,Rocky Linux作为RHEL的替代品,提供了企业级的稳定性和安全性。
这套系统特别适合以下场景:
- 日访问量在百万级以上的Web应用
- 需要实时监控业务异常的中大型系统
- 有合规性审计需求的金融、政务类应用
2. 环境准备与组件选型
2.1 操作系统选择:为什么是Rocky Linux 9.6?
Rocky Linux作为RHEL的完美替代品,继承了其所有优点:
- 长期支持周期(通常5年以上)
- 稳定的软件包版本
- 完善的安全更新机制
在Rocky Linux 9.6上,我们需要先做一些基础配置:
# 更新系统 sudo dnf update -y # 安装常用工具 sudo dnf install -y vim wget curl net-tools epel-release # 设置时区(以上海为例) sudo timedatectl set-timezone Asia/Shanghai注意:生产环境建议禁用SELinux或设置为permissive模式,避免权限问题影响日志收集。
2.2 组件版本选择考量
选择ELK 7.17.10和Redis 5.0.7有几个关键原因:
- 版本稳定性:这两个版本都是各自系列中的长期支持(LTS)版本,经过了充分的生产环境验证
- 兼容性:ELK 7.x与Redis 5.x有良好的兼容记录
- 功能平衡:新版本往往追求新特性而牺牲稳定性,这两个版本在功能和稳定性上达到了最佳平衡
3. Redis部署与配置
3.1 Redis安装与基础配置
Redis在这里扮演着日志缓冲区的角色,防止Elasticsearch因突发的日志洪峰而崩溃。
# 安装Redis sudo dnf install -y redis # 修改关键配置 sudo vim /etc/redis.conf需要修改的配置项:
bind 0.0.0.0 protected-mode no maxmemory 2gb maxmemory-policy allkeys-lru appendonly yes启动Redis并设置开机自启:
sudo systemctl enable --now redis3.2 Redis高可用方案
生产环境建议至少部署3个节点的Redis哨兵集群:
- 主从复制配置:
# 在从节点上配置 replicaof <master-ip> 6379- 哨兵配置示例:
sentinel monitor mymaster <master-ip> 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000经验分享:Redis内存大小应根据日志量设置,一般建议保留最近2小时的日志量。我们曾遇到过因内存不足导致日志丢失的情况,后来通过监控Redis内存使用率解决了这个问题。
4. ELK Stack部署
4.1 Elasticsearch集群部署
Elasticsearch是整个系统的存储核心,建议至少3个节点组成集群。
# 导入Elasticsearch GPG key sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch # 添加ELK仓库 sudo tee /etc/yum.repos.d/elasticsearch.repo <<EOF [elasticsearch-7.x] name=Elasticsearch repository for 7.x packages baseurl=https://artifacts.elastic.co/packages/7.x/yum gpgcheck=1 gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch enabled=1 autorefresh=1 type=rpm-md EOF # 安装Elasticsearch sudo dnf install -y elasticsearch-7.17.10关键配置(/etc/elasticsearch/elasticsearch.yml):
cluster.name: nginx-logs node.name: ${HOSTNAME} network.host: 0.0.0.0 discovery.seed_hosts: ["node1", "node2", "node3"] cluster.initial_master_nodes: ["node1", "node2", "node3"]4.2 Logstash配置详解
Logstash负责从Redis读取日志,处理后写入Elasticsearch。
sudo dnf install -y logstash-7.17.10配置文件示例(/etc/logstash/conf.d/nginx.conf):
input { redis { host => "redis-host" port => 6379 data_type => "list" key => "nginx_logs" threads => 4 } } filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } date { match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ] } geoip { source => "clientip" } } output { elasticsearch { hosts => ["http://es-node1:9200", "http://es-node2:9200"] index => "nginx-logs-%{+YYYY.MM.dd}" } }4.3 Kibana安装与可视化
Kibana提供了强大的日志分析界面。
sudo dnf install -y kibana-7.17.10关键配置(/etc/kibana/kibana.yml):
server.host: "0.0.0.0" elasticsearch.hosts: ["http://es-node1:9200"]5. Nginx日志收集配置
5.1 Nginx日志格式优化
标准的Nginx日志格式信息有限,建议自定义:
log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status": "$status",' '"body_bytes_sent":"$body_bytes_sent",' '"http_referer":"$http_referer",' '"http_user_agent":"$http_user_agent",' '"http_x_forwarded_for":"$http_x_forwarded_for",' '"request_time":"$request_time",' '"upstream_response_time":"$upstream_response_time"' '}'; access_log /var/log/nginx/access.log json_combined;5.2 Filebeat配置
Filebeat轻量高效,适合收集Nginx日志并发送到Redis。
sudo dnf install -y filebeat-7.17.10配置文件示例(/etc/filebeat/filebeat.yml):
filebeat.inputs: - type: log enabled: true paths: - /var/log/nginx/access.log json.keys_under_root: true json.add_error_key: true output.redis: hosts: ["redis-host:6379"] key: "nginx_logs" db: 0 timeout: 56. 系统调优与问题排查
6.1 Elasticsearch性能优化
- JVM堆内存设置(/etc/elasticsearch/jvm.options):
-Xms4g -Xmx4g- 索引模板优化:
{ "index_patterns": ["nginx-logs-*"], "settings": { "number_of_shards": 3, "number_of_replicas": 1, "refresh_interval": "30s" } }6.2 常见问题与解决方案
问题1:Redis队列积压严重
- 检查Logstash处理速度:
top -p $(pgrep -f logstash) - 增加Logstash worker线程数
- 考虑升级Redis配置或分流部分日志
问题2:Elasticsearch集群变黄/红
- 检查磁盘空间:
df -h - 检查节点状态:
curl -XGET 'http://localhost:9200/_cluster/health?pretty' - 调整索引生命周期策略,删除旧索引
问题3:Nginx日志解析失败
- 测试Grok模式:
bin/logstash -e 'filter { grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } }' - 使用自定义模式匹配特殊日志格式
7. 安全加固措施
7.1 网络层防护
- 使用防火墙限制访问:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="9200" protocol="tcp" accept' sudo firewall-cmd --reload- 为Elasticsearch和Kibana配置基础认证:
# Elasticsearch配置 xpack.security.enabled: true # Kibana配置 elasticsearch.username: "kibana_system" elasticsearch.password: "your_strong_password"7.2 日志数据保护
- 敏感信息过滤(在Logstash中):
filter { mutate { gsub => [ "message", "(password=)[^&]*", "\1[REDACTED]", "message", "(credit_card=)\d+", "\1[REDACTED]" ] } }- 定期备份Elasticsearch数据:
# 创建快照仓库 PUT _snapshot/my_backup { "type": "fs", "settings": { "location": "/mnt/backups/elasticsearch" } } # 手动创建快照 PUT _snapshot/my_backup/snapshot_18. 监控与告警配置
8.1 ELK组件健康监控
- Elasticsearch监控:
# 集群健康状态 curl -XGET 'http://localhost:9200/_cluster/health?pretty' # 节点状态 curl -XGET 'http://localhost:9200/_nodes/stats?pretty'- 使用Prometheus + Grafana监控ELK:
- 通过Elasticsearch Exporter暴露指标
- 配置关键指标的告警规则(如JVM使用率、索引延迟等)
8.2 业务日志告警
在Kibana中设置异常日志告警:
- 进入Management > Stack Management > Rules and Connectors
- 创建基于日志条件的告警规则,例如:
- 5分钟内出现10次500错误
- 关键接口响应时间超过2秒
- 配置告警动作(邮件、Slack、Webhook等)
9. 高级功能扩展
9.1 多租户日志隔离
对于SaaS类应用,可能需要隔离不同客户的日志:
- 在Nginx日志中添加租户ID字段
- 使用Elasticsearch索引别名和权限控制:
PUT /nginx-logs-tenant1 { "aliases": { "tenant1-logs": {} } }- 通过Kibana Spaces实现可视化隔离
9.2 机器学习异常检测
利用Elasticsearch的机器学习功能自动发现异常模式:
- 在Kibana中进入Machine Learning > Anomaly Detection
- 创建针对以下指标的作业:
- 异常状态码频率
- 请求量突增/突降
- 地理位置异常访问
10. 实际运维经验分享
经过半年多的生产环境运行,我们总结了以下宝贵经验:
容量规划:每100万条日志大约需要1GB存储空间(含副本)。我们最初低估了存储需求,导致频繁扩容。
索引策略:按天创建索引虽然管理方便,但对于小规模应用可能造成索引过多。我们后来调整为按周创建索引,显著提升了查询性能。
冷热数据分离:使用ILM策略将30天前的索引自动迁移到冷节点,节省了60%的硬件成本。
日志采样:对于超高流量应用(日PV>1亿),我们实现了采样率可调的日志收集,在保证关键信息不丢失的前提下,减少了70%的存储压力。
测试环境隔离:最初开发人员在测试环境执行大量查询影响了生产集群性能,后来我们严格分离了测试和生产集群。