节点分配:
192.168.24.41= node1:Elasticsearch + Kibana(存储+展示层)
192.168.24.42= node2:Logstash(数据处理层)
192.168.24.43= node3:Filebeat(日志采集层)
一、整体架构与原理
简述原理流程:
node3作为采集层、node2作为处理层、node1作为存储展示层,全链路通过轻量协议串联,支持断点续传和流量削峰。首先业务系统或系统服务(如sshd、内核)在node3上产生日志并写入/var/log/messages等文件,Filebeat作为轻量采集器,通过filestream插件实时监控文件变更,将读取进度记录到registry文件避免重复采集,再通过Beats私有协议把原始非结构化日志推送到node2的5044端口;随后Logstash作为数据处理中枢,先通过beats输入插件接收数据,再用grok插件把杂乱的syslog文本解析为带syslog_timestamp、syslog_hostname、syslog_message的结构化字段,date插件将日志自带的时间校准为@timestamp作为官方时间戳,mutate插件剔除agent.version、ecs这类冗余字段降低存储开销,之前调试用的stdout插件就是把处理后的结构化日志打印到控制台,方便验证解析规则是否正确,最后通过elasticsearch输出插件把数据批量发送到node1的9200端口;Elasticsearch作为分布式搜索引擎,按logs-YYYY.MM.dd的规则按天创建索引,将日志以JSON文档形式存储,通过倒排索引实现毫秒级检索,单节点模式下自动适配无副本的存储策略;最终Kibana作为可视化前端,通过REST API从ES拉取索引数据,在Discover页面提供时间范围筛选、关键词搜索、字段过滤能力,把结构化的JSON日志转化为可视化的表格,还可进一步生成统计仪表盘、配置异常告警,整套链路中Filebeat负责"轻量采集"、Logstash负责"清洗加工"、Elasticsearch负责"高效存储"、Kibana负责"直观展示",各环节解耦可独立扩缩容,完美支撑从日志产生到问题排查的全生命周期需求。
1.1 架构流程图

1.2 核心原理
| 组件 | 核心逻辑 | 遇到的坑 |
|---|---|---|
| Filebeat | 轻量采集器,记录日志偏移量到registry,避免重复采集 |
① 两个output冲突 ② registry路径错 ③ 没权限读/var/log/messages |
| Logstash | 日志处理中枢,ES8.x默认开启数据流 ,传统index配置会被静默拒绝写入 |
没加data_stream => false导致ES一直没索引 |
| Elasticsearch | 分布式搜索引擎,单节点默认创建1个副本,无第二节点时副本无法分配,索引显示yellow |
之前看到yellow索引是正常现象 |
| SELinux | 强制访问控制,默认拦截Filebeat读取系统日志 | 之前关了SELinux后才通 |
二、前置准备(所有节点执行)
2.1 基础环境配置
1. 关闭SELinux
、也可以打标签放行,这里不是学习重点可以关闭
# ★ 永久关闭,避免重启后失效
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
setenforce 0
getenforce # 输出Permissive/Disabled才算成功
2. 关闭防火墙/开放端口
# 测试环境直接关
systemctl stop firewalld
systemctl disable firewalld
# 生产环境建议只开必要端口:
# node1开9200/9300/5601,node2开5044
3. 配置主机名解析(所有节点都要做)
cat >> /etc/hosts << EOF
192.168.24.41 node1
192.168.24.42 node2
192.168.24.43 node3
EOF
4. 时间同步查看(避免日志时间错乱)
yum install -y chrony
systemctl enable --now chronyd
chronyc sources -v # 看到^*开头说明同步成功
时间同步配置
1. 修改 node1 的 Chrony 配置(作为Server):
vim /etc/chrony.conf
添加或修改:
# 允许局域网内的节点同步
allow 192.168.24.0/24
# 即使断网,也使用本地硬件时钟作为备用
local stratum 10
重启:systemctl restart chronyd
2. 修改 node2 和 node3 的配置(作为Client):
vim /etc/chrony.conf
注释掉公网 NTP,指向 node1:
#pool 2.rhel.pool.ntp.org iburst
server 192.168.24.41 iburst prefer
指定要同步的上游 NTP 服务器地址。
iburst (重点,非常实用) 作用:加速初始同步。
prefer (优先级标记) 作用:标记为首选服务器
重启:systemctl restart chronyd
3. 验证集群内同步:
在 node2 或 node3 上执行:
chronyc sources -v
[root@node3 ~]# chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* node1 2 6 17 19 -2149ns[ -17us] +/- 36ms
意义:node2/node3 直接同步 node1,时间源完全一致,消除了公网延迟带来的微小差异。
第四步:硬件时钟同步(防止重启后漂移)
系统时间(Software)重启后会丢失,需要从硬件时钟(RTC/BIOS)读取。必须确保两者一致。
# 1. 查看硬件时钟
hwclock -r
# 2. 如果系统时间准,但硬件时间不准,把系统时间写入硬件(非常重要!)
hwclock -w
# 3. 设置系统时区(ELK日志强烈建议使用UTC或统一时区)
timedatectl set-timezone Asia/Shanghai
# 或者统一用UTC(推荐,避免夏令时问题)
# timedatectl set-timezone UTC
第五步:终极一致性验证(你想要的"同一个时间")
在三个节点上同时执行,看时间戳是否大概一致:
有些许误差是能够接受的
for i in 192.168.24.41 192.168.24.42 192.168.24.43; do
echo -n "$i: "
ssh $i "date +'%Y-%m-%d %H:%M:%S.%3N'"
done
root@192.168.24.41's password:
2026-07-22 19:29:47.650
root@192.168.24.42's password:
2026-07-22 19:29:49.988
root@192.168.24.43's password:
2026-07-22 19:29:52.234
2.2 系统依赖与调优
1. 安装JDK(ELK基于Java开发)
dnf install -y java-25-openjdk
java -version # 验证安装成功
[root@node1 ~]# java -version
java version "25.0.3" 2026-04-21 LTS
Java(TM) SE Runtime Environment (build 25.0.3+9-LTS-195)
Java HotSpot(TM) 64-Bit Server VM (build 25.0.3+9-LTS-195, mixed mode, sharing)
2. 创建ELK专用用户(禁止root运行,安全要求)
useradd elk
mkdir -p /opt/elk /opt/logs/{elasticsearch,logstash,filebeat}
chown -R elk:elk /opt/elk /opt/logs
3. 内核参数调优(ES强制要求)
# 最大文件句柄数/进程数
cat >> /etc/security/limits.conf << EOF
elk soft nofile 65535
elk hard nofile 65535
elk soft nproc 40960
elk hard nproc 40960
EOF
# 虚拟内存参数(ES用mmap锁内存,必须改)
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
sysctl -p
原理解释:
limits.conf里的配置是为elk用户专门设置的资源门槛,nofile控制单进程最多能同时打开的文件句柄数,Elasticsearch和Logstash需要频繁读写大量日志文件和网络连接,默认1024的上限会直接导致服务崩溃,65535是确保高并发下稳定运行的基础保障;nproc则是限制用户能创建的最大进程数,防止日志采集和处理的子进程耗尽系统资源。soft是运行时的软限制,hard是系统允许的最高上限,软限制不能超过硬限制。
vm.max_map_count是Linux内核允许一个进程拥有的虚拟内存区域数量上限,Elasticsearch重度依赖mmap(内存映射)技术将磁盘上的索引文件直接映射到内存中进行高效读写,默认65530的数值远不能满足ES创建大量内存映射区的需求,262144这个值是官方经过大规模测试验证的最低要求,低于这个值ES会启动失败,调整它能确保ES在索引和搜索海量日志时不会因为内存映射区不足而报错。
三、分节点部署
3.1 node1(192.168.24.41):Elasticsearch + Kibana
3.1.1 Elasticsearch部署
Elasticsearch:官方分布式搜索和分析引擎 | Elastic
su - elk
cd /opt/elk
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.18.8-linux-x86_64.tar.gz
tar -zxvf elasticsearch-8.18.8-linux-x86_64.tar.gz
ln -s /opt/elk/elasticsearch-8.18.8 /opt/elk/elasticsearch
exit
2. 核心配置/opt/elk/elasticsearch/config/elasticsearch.yml
cluster.name: elk-cluster
node.name: node1
path.data: /opt/logs/elasticsearch
path.logs: /opt/logs/elasticsearch
network.host: 0.0.0.0
http.port: 9200
# 单节点模式(当前只有1个ES节点,后续扩集群再改)
discovery.type: single-node
# 测试环境关闭安全认证(生产环境务必开启)
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
3. JVM内存配置(根据你的机器内存调整,不要超过物理内存50%)
vim /opt/elk/elasticsearch/config/jvm.options
# 4G内存机器改这个:
-Xms1g
-Xmx1g
4. 配置systemd服务
cat > /usr/lib/systemd/system/elasticsearch.service << EOF
[Unit]
Description=Elasticsearch Service
After=network.target
[Service]
User=elk
Group=elk
ExecStart=/opt/elk/elasticsearch/bin/elasticsearch
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
5. 启动验证
systemctl daemon-reload
systemctl enable --now elasticsearch
# 等10秒后验证
curl http://192.168.24.41:9200
# 预期返回包含"You Know, for Search"的JSON
tail -f /opt/logs/elasticsearch/elasticsearch.log # 看启动日志

3.1.2 Kibana部署
1. 下载解压
su - elk
cd /opt/elk
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.18.8-linux-x86_64.tar.gz
tar -zxvf kibana-8.18.8-linux-x86_64.tar.gz
ln -s /opt/elk/kibana-8.18.8 /opt/elk/kibana #这里相当于软链接的方式,也可以和之前一样移动过去
exit
2. 核心配置/opt/elk/kibana/config/kibana.yml
需修改的地方
server.port: 5601
server.host: "0.0.0.0"
# ★ 指向你的node1的ES地址
elasticsearch.hosts: ["http://192.168.24.41:9200"]
i18n.locale: "zh-CN"
server.host: "0.0.0.0" 表示让 Kibana 监听服务器上的所有网络接口。简单来说,它告诉 Kibana:"不管请求是从本机的回环地址(127.0.0.1)、内网网卡(192.168.24.41),还是其他任何网卡发过来的,只要是访问 5601 端口的,统统都要接受。" 这里一般生产按需求写,不然就相当于裸奔很不安全,但是只有一个如果ip变化也容易导致服务挂
3. 配置systemd服务
cat > /usr/lib/systemd/system/kibana.service << EOF
[Unit]
Description=Kibana Service
After=network.target elasticsearch.service
[Service]
User=elk
Group=elk
ExecStart=/opt/elk/kibana/bin/kibana
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
4. 启动验证
systemctl daemon-reload
systemctl enable --now kibana
ss -tlnp | grep 5601 # 验证端口监听
# 浏览器访问 http://192.168.24.41:5601 即可打开Kibana

3.2 node2(192.168.24.42):Logstash部署
3.2.1 基础部署
1. 下载解压
su - elk
cd /opt/elk
wget https://artifacts.elastic.co/downloads/logstash/logstash-8.18.8-linux-x86_64.tar.gz
tar -zxvf logstash-8.18.8-linux-x86_64.tar.gz
ln -s /opt/elk/logstash-8.18.8 /opt/elk/logstash
exit
2. 核心管道配置 /opt/elk/logstash/config/log-pipeline.conf
input {
beats {
port => 5044 # 接收Filebeat发送的日志
}
}
filter {
# 只处理Filebeat标记的syslog类型日志
if [type] == "syslog" {
grok {
match => {
"message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}"
}
}
date {
# 用日志自带时间作为@timestamp,避免用采集时间
match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]
target => "@timestamp"
}
}
mutate {
# 删除冗余字段,节省存储空间
remove_field => ["[agent][version]", "ecs"]
}
}
output {
elasticsearch {
# ★ 指向你的node1的ES地址
hosts => ["http://192.168.24.41:9200"]
index => "logs-%{+YYYY.MM.dd}"
# ★ 之前卡的核心点:关闭ES8.x默认的数据流,否则写不进去
data_stream => false
}
# 控制台输出调试,之前就是在这里看到rubydebug日志的
#stdout { codec => rubydebug }
}
注意:
注释掉 stdout { codec => rubydebug } 是为了保障生产性能,因为该配置会强制 Logstash 将每一条流经的日志同步打印到控制台,在高并发场景下会造成严重的 I/O 瓶颈和 CPU 开销,甚至导致日志堆积或进程崩溃;它应当仅在排查数据解析异常、验证 Grok 规则或确认字段映射时临时打开,作用是让你在不中断数据流的情况下,直观地观测日志经过 Filter 处理后的原始数据结构,从而快速定位配置错误。
开启后你既能在终端前台运行时看到满屏的 JSON 日志,也能通过 journalctl -u logstash -f 在后台实时追踪这些数据。
3. JVM内存配置
vim /opt/elk/logstash/config/jvm.options
# 处理层内存不用太大,512M足够
-Xms512m
-Xmx512m
4. 配置systemd服务
cat > /usr/lib/systemd/system/logstash.service << EOF
[Unit]
Description=Logstash Service
After=network.target
[Service]
User=elk
Group=elk
# 指定自定义管道配置
ExecStart=/opt/elk/logstash/bin/logstash -f /opt/elk/logstash/config/log-pipeline.conf
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
5. 启动验证和查看管道状态
systemctl daemon-reload
systemctl enable --now logstash
ss -tlnp | grep 5044 # 验证5044端口监听
tail -f /opt/elk/logstash/logs/logstash-plain.log # 看启动日志
[root@node2 ~]# ss -lntup | grep 5044
tcp LISTEN 0 4096 *:5044 *:* users:(("java",pid=8147,fd=122))
[root@node2 logs]# curl -s http://localhost:9600/_node/stats/pipeline
{"path":"/_node/stats/pipeline","status":404,"error":{"message":"Not Found"}}[root@node2 logs]# curl -s http://localhost:9600/_node/pipelines/main?pretty
{
"host" : "node2",
"version" : "8.18.8",
"http_address" : "127.0.0.1:9600",
"id" : "841fe993-fccd-46e5-8de5-882e08990e09",
"name" : "node2",
"ephemeral_id" : "03c83ae1-95b5-4ca0-bd38-f4227a5c7112",
"snapshot" : false,
"status" : "green",
"pipeline" : {
"workers" : 4,
"batch_size" : 125,
"batch_delay" : 50
},
"pipelines" : {
"main" : {
"ephemeral_id" : "64639abe-9b50-462f-80f5-72452e0bb62c",
"hash" : "822ca5d59d4db87e99ebf8a804dec461707e7a468d632b2ed11cf5d0c5f7bf07",
"workers" : 4,
"batch_size" : 125,
"batch_delay" : 50,
"config_reload_automatic" : false,
"config_reload_interval" : 3000000000,
"dead_letter_queue_enabled" : false
}
}
}[root@node2 logs]#
看logstash是否接受到filebeat的数据
[root@node2 logs]# curl -s http://localhost:9600/_node/stats/events?pretty
{
"host" : "node2",
"version" : "8.18.8",
"http_address" : "127.0.0.1:9600",
"id" : "841fe993-fccd-46e5-8de5-882e08990e09",
"name" : "node2",
"ephemeral_id" : "03c83ae1-95b5-4ca0-bd38-f4227a5c7112",
"snapshot" : false,
"status" : "green",
"pipeline" : {
"workers" : 4,
"batch_size" : 125,
"batch_delay" : 50
},
"events" : {
"in" : 1102,
"filtered" : 1102,
"out" : 1102,
"duration_in_millis" : 4285,
"queue_push_duration_in_millis" : 17
}
in > 0 且持续增长 → Logstash 确实在源源不断收到数据
in ≈ filtered ≈ out → 数据处理正常,没有积压
如果 in 为 0 → 说明 Filebeat 根本没把数据送过来,问题在 node3 或网络
例子:
"events": {
"in": 293658, // 收到的事件总数
"filtered": 293658, // 经过 filter 处理的事件数
"out": 293658 // 发送给 output 的事件数
}
3.3 node3(192.168.24.43):Filebeat部署
3.3.1 基础部署
1. 下载解压
su - elk
cd /opt/elk
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.18.8-linux-x86_64.tar.gz
tar -zxvf filebeat-8.18.8-linux-x86_64.tar.gz
ln -s /opt/elk/filebeat-8.18.8 /opt/elk/filebeat
exit
2. 核心配置/opt/elk/filebeat/filebeat.yml
###################### Filebeat inputs #########################
filebeat.inputs:
# filestream 是 8.x 推荐的类型,相比旧的 log 类型性能更好,占用资源更低
- type: filestream
enabled: true
# 采集路径:这里配置了两个目标
# /tmp/test_elk.log 是之前为了排除干扰创建的测试文件(权限最松)
# /var/log/messages 和 /secure 是正式的系统日志
paths:
- /tmp/test_elk.log
- /var/log/messages
- /var/log/secure
# 自定义字段:给日志打上一个标记,告诉 Logstash "这是 syslog"
fields:
type: syslog
# ★ 关键配置:将 fields 提到根级别
# 如果不设此项,Logstash 里要用 [fields][type] 才能取到值
# 设了此项,Logstash 里直接用 [type] 即可,简化了 grok 的条件判断
fields_under_root: true
###################### Output (只留 Logstash) #########################
# ★ 核心点:确保只有一个 output
output.logstash:
# 指向 node2 的 Logstash 地址
# Filebeat 会通过 Beats 协议将数据发送到此端口
hosts: ["192.168.24.42:5044"]
###################### Setup (全部关闭) #########################
# 关闭索引生命周期管理:因为你使用的是自定义的 Logstash 索引名(logs-*)
# 如果不关,Filebeat 可能会尝试去连接 ES 管理策略,导致冲突
setup.ilm.enabled: false
# 关闭 Kibana 自动配置:我们不通过 Filebeat 去配置 Kibana 的仪表盘
# 而是由我们在 Kibana 界面手动创建 Index Pattern
setup.kibana.enabled: false
###################### Processors #########################
processors:
# 添加主机元数据:自动把 hostname、IP 地址等信息塞进日志里
# 这样你在 Kibana 里就能看到这条日志来自哪台机器
- add_host_metadata:
# 过滤条件:如果没有包含 forwarded 标签,才执行这个 processor
# 防止日志被多次转发时重复添加主机信息
when.not.contains.tags: forwarded
###################### Logging (排错用) #########################
# ★ 排错神器:开启 Debug 模式
logging.level: debug
# 指定 Debug 的范围:只关心输入(采集)、收割(读取文件)、发布(发送数据)
# 不关心内部琐碎逻辑,避免日志刷屏
logging.selectors: ["input", "harvester", "publish"]
# 日志输出到文件(而不是 stdout),方便持久化查看
logging.to_files: true
logging.files:
# Filebeat 自己的日志存放路径
path: /opt/elk/filebeat/logs
name: filebeat
# 保留最近 7 个日志文件,防止硬盘爆满
keepfiles: 7
3. 解决权限问题(之前遇到的/var/log/messages读不了的问题)
# 把elk加入系统日志读取组
usermod -aG adm elk
# 修改日志文件权限,让elk能读
chmod 640 /var/log/messages /var/log/secure
chown root:adm /var/log/messages /var/log/secure
-aG:是两个参数的组合。
-G:修改用户的附加组(Supplementary Groups)。
-a(append,追加):极其重要。它表示"在原有附加组的基础上,新增一个组"。
如果不加 -a,直接执行 -G adm elk,会把 elk 用户原本加入的其他附加组(如果有的话)全部清空,只保留 adm 组,容易造成事故。
adm:是 Linux 系统的一个内置用户组。在 Debian/Ubuntu 和 RHEL/CentOS 系统中,/var/log/ 目录下的多数日志文件(如 messages、secure)的属组通常都是 adm,并且权限设置为 640(root:adm 可读)。
4. 配置校验(必做,避免启动失败)
sudo -u elk /opt/elk/filebeat/filebeat test config -c /opt/elk/filebeat/filebeat.yml
# 输出Config OK才算合格
[root@node3 ~]# sudo -u elk /opt/elk/filebeat/filebeat test config -c /opt/elk/filebeat/filebeat.yml
Config OK
[root@node3 logs]# sudo -u elk /opt/elk/filebeat/filebeat test output -c /opt/elk/filebeat/filebeat.yml
logstash: 192.168.24.42:5044...
connection...
parse host... OK
dns lookup... OK
addresses: 192.168.24.42
dial up... OK
TLS... WARN secure connection disabled
talk to server... OK
5. 配置systemd服务
cat > /usr/lib/systemd/system/filebeat.service << EOF
[Unit]
Description=Filebeat Log Collector
After=network.target
[Service]
User=elk
Group=elk
ExecStart=/opt/elk/filebeat/filebeat -c /opt/elk/filebeat/filebeat.yml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
6. 启动验证
systemctl daemon-reload
systemctl enable --now filebeat
systemctl status filebeat # 状态为active (running)
# 看Filebeat日志,确认没有报错
journalctl -u filebeat -f
四、全链路验证
4.1 基础服务状态验证
# node1验证
systemctl status elasticsearch kibana
# node2验证
systemctl status logstash
# node3验证
systemctl status filebeat
所有服务均为active (running)。
4.2 生成测试日志(和你之前的操作一致)
在node3上写入唯一标识的测试日志:
echo "ELK_TEST_$(date +%s)" >> /var/log/messages
或者:
logger -t "ELK_VERIFY" "CHAIN_OK_$(date +%s)"
以下图片测试语句:
[root@node3 logs]# logger -t "ELK_FINAL_CHECK" "IF_YOU_SEE_THIS_IN_KIBANA_IT_IS_100_PERCENT_WORKING_$(date +%s)"
4.3 Logstash侧验证
在node2上执行:
tail -f /opt/elk/logstash/logs/logstash-plain.log
4.4 ES侧验证
在node1上执行:
curl -s http://192.168.24.41:9200/_cat/indices?v | grep logs
[root@node1 ~]# curl -s http://192.168.24.41:9200/_cat/indices?v | grep logs
green open .internal.alerts-observability.logs.alerts-default-000001 tTry6Fj4RwezJru7i58OqA 1 0 0 0 249b 249b 249b
yellow open logs-2026.07.21 4Q87_1qCS7GnsO3UpE1lng 1 1 6944 0 2.8mb 2.8mb 2.8mb
yellow open logs-2026.07.22 zODPvn8KRESte0GwCVmOnQ 1 1 3825 0 1.9mb 1.9mb 1.9mb
[root@node1 ~]#
logs-2026.07.22 业务日志
yellow是单节点正常现象:
节点一 查询测试日志(message自己改一下就行)
[root@node1 ~]# curl -s "http://192.168.24.41:9200/logs-2026.07.22/_search?pretty" -H "Content-Type: application/json" -d '{"query":{"match":{"message":"TEST"}},"size":1}'
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 12.600115,
"hits" : [
{
"_index" : "logs-2026.07.22",
"_id" : "7UcGip8B2Lbiy6X6gLYw",
"_score" : 12.600115,
"_source" : {
"@version" : "1",
"message" : "TEST_LOG_VIA_SSH: 1784727095",
"type" : "syslog",
"host" : {
"architecture" : "x86_64",
"mac" : [
"00-0C-29-49-94-58",
"16-D7-54-06-48-C9",
"3E-9B-46-61-8B-BE",
"7A-89-D0-7E-A5-00",
"C2-28-AC-45-A8-5E",
"CE-81-17-7C-BF-88",
"F2-17-96-10-05-C3"
],
"id" : "2007d48c709543b69c75168429fc3c77",
"hostname" : "node3",
"name" : "node3",
"os" : {
"platform" : "rhel",
"codename" : "Coughlan",
"type" : "linux",
"version" : "10.1 (Coughlan)",
"family" : "redhat",
"name" : "Red Hat Enterprise Linux",
"kernel" : "6.12.0-124.8.1.el10_1.x86_64"
},
"containerized" : false,
"ip" : [
"192.168.24.43",
"fe80::20c:29ff:fe49:9458",
"172.17.0.1",
"172.18.0.1",
"fe80::c028:acff:fe45:a85e",
"fe80::cc81:17ff:fe7c:bf88",
"fe80::7889:d0ff:fe7e:a500",
"fe80::f017:96ff:fe10:5c3",
"fe80::3c9b:46ff:fe61:8bbe"
]
},
"@timestamp" : "2026-07-22T13:31:39.572Z",
"agent" : {
"name" : "node3",
"id" : "7a74921a-4792-4902-8e08-4550f1a20464",
"ephemeral_id" : "b3643330-abb2-4fde-a413-fc9507452bcc",
"type" : "filebeat"
}
}
}
]
}
}
[root@node1 ~]#
4.5 Kibana侧验证
-
访问
http://192.168.24.41:5601打开Kibana -
左侧Discover ,时间范围选
All time,搜索KQL语句,即可看到日志。 -
或者左侧日志,里面也有详细的内容

查询测试日志(左侧Discover)

一、为什么感觉"测试日志诞生得晚"?
测试时并不能马上查询到,以下时间参考,可能会更长
1. Filebeat 的采集间隔(最主要原因)
Filebeat 不是"文件一变就立刻读",而是有一个扫描周期 (默认 scan_frequency: 10s)。
-
它每 10 秒才去检查一次
/var/log/messages有没有新内容。 -
你写入日志后,最多可能要等 10 秒,Filebeat 才会发现文件变了并开始读取。
-
这是设计如此,避免高频扫描拖垮磁盘 I/O。
2. Logstash 的批处理机制(次要原因)
Logstash 不是"收到一条就立刻转发一条",而是攒批:
-
pipeline.batch.size: 125:要攒够 125 条才发一批。 -
pipeline.batch.delay: 50:最多等 50ms 凑批。 -
如果你只写了一条测试日志,Logstash 会等够 125 条或超时后才发给 ES。
-
之前看到 ES 里一次性多了几千条,就是因为之前积压的旧日志被批量刷过去了。
3. Kibana 的刷新间隔
Kibana Discover 页面默认不会自动刷新,即使 ES 里已经有新数据,你不点刷新按钮或改时间范围,它就一直显示旧的查询结果。
五.后续操作
-
关掉Filebeat的Debug日志(不然会占满磁盘):
vim /opt/elk/filebeat/filebeat.yml # 把 logging.level: debug 改成 logging.level: info systemctl restart filebeat -
把Logstash的batch_size改回默认值(提高吞吐量):
vim /opt/elk/logstash/config/pipeline/log-pipeline.conf
# 把 batch_size => 1 改回 batch_size => 125
systemctl restart logstash
pipeline.workers: 4 # 默认是CPU核数,不用改
pipeline.batch.size: 250 # 默认125,日志量大可以翻倍
pipeline.batch.delay: 50 # 默认50ms,攒批超时时间
-
Kibana里保存查询模板:
在Discover页面搜
TEST_LOG_VIA_SSH,点击右上角「保存」,以后直接打开就能看实时日志。 -
扩展采集其他日志(比如Nginx/Java/Docker日志):
只要在node3的
filebeat.yml里加对应的paths,比如采集Nginx访问日志:paths: - /var/log/nginx/access.log - /var/log/nginx/error.log -
设置索引生命周期(避免磁盘爆满):
在Kibana的
Stack Management → Index Lifecycle Policies里,给logs-*索引设置自动删除30天前的旧日志。