elk部署和kibana图形化展示

ELK日志环境搭建

环境规划

192.168.3.61 logstash、filebeat 、kibana 、es

192.168.3.62 es

192.168.3.63 es

配置主机名

复制代码
hostnamectl set-hostname ela1.com
hostnamectl set-hostname ela2.com
hostnamectl set-hostname ela3.com

配置hosts文件解析

复制代码
cat >> /etc/hosts << EOF
192.168.3.61 ela1 ela1.com
192.168.3.62 ela2 ela2.com
192.168.3.63 ela3 ela3.com
EOF

修改三台主机免密ssh登录

复制代码
ssh-keygen -f ~/.ssh/id_rsa -P '' -q
ssh-copy-id 192.168.3.61
ssh-copy-id 192.168.3.62
ssh-copy-id 192.168.3.63
安装filebeat
复制代码
tar -xf filebeat-7.13.2-linux-x86_64.tar.gz
mv filebeat-7.13.2-linux-x86_64 /usr/local/
mv /usr/local/filebeat-7.13.2-linux-x86_64/ /usr/local/filebeat
mkdir /usr/local/filebeat/logs -p

filebeat启动

复制代码
cat >> /usr/local/filebeat/start.sh << EOF
nohup /usr/local/filebeat/filebeat -e -c /usr/local/filebeat/filebeat.yml > /usr/local/filebeat/logs/filebeat.log 2>&1 &
EOF

chmod +x /usr/local/filebeat/start.sh
/usr/local/filebeat/start.sh

-e 的作用是让 Filebeat 把日志打到 stderr,然后配合 > logs/filebeat.log 2>&1 将这些日志统一重定向到 logs/filebeat.log 文件中。

等价于 --stderr,强制 Filebeat 把日志输出到 stderr

Filebeat简单使用

准备测试数据

复制代码
cat >> /tmp/access.log << EOF
123.127.39.50 - - [04/Mar/2026:10:50:28 +0800] "GET /logo.jpg HTTP/1.1" 200 14137 "http://81.68.233.173/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36" "-"
EOF

配置Filebeat 的输入和输出

复制代码
vim /usr/local/filebeat/filebeat.yml
yaml 复制代码
filebeat.inputs:
- type: log
  enabled: true  # 改
  paths:  
    - /tmp/*.log # 改

# 设置 filebeat 输出的位置为终端 ,filebeat 的输出位置只能有一个,其他 output 位置需要注释
# ---------------------------- Elasticsearch Output ----------------------------
# output.elasticsearch:   			  #  注释这行
#   hosts: ["localhost:9200"]  		  #  注释这行

output.console:  # 添加 输出到终端即屏幕上
  pretty: true


# 以下配置无需修改了 默认即可
processors:
  - add_host_metadata:  # 主机的源数据信息到输出数据中,比如 IP MAC OS 等信息
      when.not.contains.tags: forwarded

# ============================== Filebeat modules ==============================
# 模块相关配置 内置了些模块,配置模块后就可以采集相关的日志
filebeat.config.modules: # 内置的收集日志的模块配置文件的存放路径
  path: ${path.config}/modules.d/*.yml
  reload.enabled: false  # 当模块的配置文件有更新时,此程序是否要自动加载,false不加载,true 加载
setup.template.settings:
  index.number_of_shards: 1

启动测试

默认日志位置在logs下

shell 复制代码
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml

{
  "@timestamp": "2026-07-11T11:52:25.970Z",
  "@metadata": {
    "beat": "filebeat",
    "type": "_doc",
    "version": "7.13.2"
  },
  "ecs": {
    "version": "1.8.0"
  },
  "host": {
    "containerized": false,
    "ip": [
      "192.168.3.61",
      "fe80::ec9:9d78:e02b:d35d",
      "fe80::ed28:4363:215e:a0c1"
    ],
    "mac": [
      "00:0c:29:58:70:56"
    ],
    "hostname": "ela1.com",
    "architecture": "x86_64",
    "os": {
      "name": "CentOS Linux",
      "kernel": "3.10.0-957.el7.x86_64",
      "codename": "Core",
      "type": "linux",
      "platform": "centos",
      "version": "7 (Core)",
      "family": "redhat"
    },
    "name": "ela1.com",
    "id": "89b07113c20b441e8d5a8dcadb27e658"
  },
  "agent": {
    "type": "filebeat",
    "version": "7.13.2",
    "hostname": "ela1.com",
    "ephemeral_id": "275e2495-ec11-4703-aabf-e3f4ee93bf2d",
    "id": "504e778c-506f-4d96-9aae-b30c252cce1f",
    "name": "ela1.com"
  },
  "log": {
    "offset": 0,
    "file": {
      "path": "/tmp/access.log"
    }
  },
  "message": "124.127.39.50 - - [04/Mar/2021:10:50:28 +0800] \"GET /logo.jpg HTTP/1.1\" 200 14137 \"http://81.68.233.173/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36\" \"-\"",
  "input": {
    "type": "log"
  }
}

停止

复制代码
ps -ef | grep filebeat.yml | grep -v grep | awk '{print $2}' | xargs kill -9

filebeat重读日志

有时候处于实验目的,可能需要重新读取日志文件,这个时候需要删除安装目录下的 data 文件夹,重新运行 filebeat 即可。

复制代码
[root@ela1 filebeat]# ls
data        filebeat                filebeat.yml          kibana       logs    modules.d   README.md
fields.yml  filebeat.reference.yml  filebeat.yml.yuanshi  LICENSE.txt  module  NOTICE.txt

# 删除 data 即可重读日志
rm -rf data
安装Logstash
复制代码
tar -xf logstash-7.13.2-linux-x86_64.tar.gz -C /usr/local/
mv /usr/local/logstash-7.13.2/ /usr/local/logstash

执行启动命令

复制代码
/usr/local/logstash/bin/logstash -e ''

-e 选项用于设置 Logstash 处理数据的输入和输出

-e '' 等同于 -e input { stdin { type => stdin } } output { stdout { codec => rubydebug } }

input { stdin { type => stdin } }

​ 表示 Logstash 需要处理的数据来源来自于标准输入设备

output { stdout { codec => rubydebug } }

​ 表示 Logstash 把处理好的数据输出到标准输出设备

执行 bin/logstash -e '' 命令后 在终端中输入abcd 后有以下输出即说明安装无误

复制代码
abcd
{
          "host" => "ela1.com",
       "message" => "abcd",
      "@version" => "1",
    "@timestamp" => 2026-07-11T12:30:12.994Z,
          "type" => "stdin"
}

配置输入和输出

生产中,Logstash管道要复杂一些:它通常具有一个或多个输入,过滤器和输出插件。

本部分中,将创建一个Logstash管道,该管道使用标准输入来获取Apache Web日志作为输入,解析这些日志以从日志中创建特定的命名字段,然后将解析的数据输出到标准输出(屏幕上)。并且这次无需在命令行上定义管道配置,而是在配置文件中定义管道。

创建任意一个文件,并写入如下内容,作为 Logstash 的管道配置文件

复制代码
vim /usr/local/logstash/config/first-pipeline.conf

input { 
    stdin { } 
} 
output { 
    stdout {}
}

配置文件语法测试

复制代码
/usr/local/logstash/bin/logstash -f config/first-pipeline.conf --config.test_and_exit

运行如下命令启动 Logstash

复制代码
/usr/local/logstash/bin/logstash -f config/first-pipeline.conf

启动后复制如下内容到命令行中,并按下回车键

复制代码
83.149.9.216 - - [04/Jan/2025:05:13:42 +0000] "GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1" 200 203023 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"

将会看到如下输出

复制代码
{
      "@version" => "1",
       "message" => "83.149.9.216 - - [04/Jan/2015:05:13:42 +0000] \"GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1\" 200 203023 \"http://semicomplete.com/presentations/logstash-monitorama-2013/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
    "@timestamp" => 2026-05-02T11:37:23.956Z,
          "host" => "ela1"
}
使用Grok过滤器插件解析Web日志

现在有了一个工作管道,但是日志消息的格式不是理想的。你想解析日志消息,以便能从日志中创建特定的命名字段。为此,应该使用grok过滤器插件。

使用grok过滤器插件,可以将非结构化日志数据解析为结构化和可查询的内容。

grok 会根据你感兴趣的内容分配字段名称,并把这些内容和对应的字段名称进行绑定。

grok 如何知道哪些内容是你感兴趣的呢?它是通过自己预定义的模式来识别感兴趣的字段的。这个可以通过给其配置不同的模式来实现。

这里使用的模式是 %{COMBINEDAPACHELOG}

{COMBINEDAPACHELOG 使用以下模式从Apache日志中构造行:

原信息 对应新的字段名称
IP 地址 clientip
用户 ID ident
用户认证信息 auth
时间戳 timestamp
HTTP 请求方法 verb
请求的 URL request
HTTP 版本 httpversion
响应码 response
响应体大小 bytes
跳转来源 referrer
客户端代理(浏览器) agent

这里要想实现修改配置文件之后自动加载它,不能配置 inputstdin。所以, 这里使用了 file ,创建示例日志文件

复制代码
vim /var/log/httpd.log

83.149.9.216 - - [04/Jan/2026:05:13:42 +0000] "GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1" 200 203023 "http://semicomplete.com/presentations/logstash-monitorama-2013/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36"

修改好的管道配置文件如下:

复制代码
vim /usr/local/logstash/config/first-pipeline.conf

input {
    file {
        path => ["/var/log/httpd.log"]
        start_position => "beginning"
    }
}

filter {
    grok {  # 对 web 日志进行过滤处理,输出结构化的数据
    	  # 在 message 字段对应的值中查询匹配上 COMBINEDAPACHELOG
         match => { "message" => "%{COMBINEDAPACHELOG}" }    }
    }

output {
    stdout {}
}

match => { "message" => "%{COMBINEDAPACHELOG}"} 的意思是:

当匹配到 "message" 字段时,用户模式 "COMBINEDAPACHELOG}" 进行字段映射。

配置完成后,再次进行验证

复制代码
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf

下面是输出内容

复制代码
{
           "path" => "/var/log/httpd.log",
       "clientip" => "83.149.9.216",
      "timestamp" => "04/Jan/2015:05:13:42 +0000",
       "response" => "200",
           "verb" => "GET",
          "bytes" => "203023",
          "agent" => "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
       "@version" => "1",
        "message" => "83.149.9.216 - - [04/Jan/2015:05:13:42 +0000] \"GET /presentations/logstash-monitorama-2013/imageskibana-search.png HTTP/1.1\" 200 203023 \"http://semicomplete.com/presentations/logstash-monitorama-2013/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
           "host" => "ela1",
           "auth" => "-",
        "request" => "/presentations/logstash-monitorama-2013/imageskibana-search.png",
       "referrer" => "\"http://semicomplete.com/presentations/logstash-monitorama-2013/\"",
    "httpversion" => "1.1",
     "@timestamp" => 2026-05-02T11:39:44.349Z,
          "ident" => "-"
}

你会发现原来的非结构化数据,变为结构化的数据了。

细心的你一定发现原来的 message 字段仍然存在,假如你不需要它,可以使用 grok 中提供的常用选项之一: remove_filed 来移除这个字段。

remove_field 可以移除任意的字段,它可以接收的值是一个数组。

rename可以重新命名字段

修改后管道配置文件如下:

复制代码
vim /usr/local/logstash/config/first-pipeline.conf

input {
    file {
        path => ["/var/log/httpd.log"]
        start_position => "beginning"
    }
}

filter {
    grok {
         match => { "message" => "%{COMBINEDAPACHELOG}" }    }
         mutate {
            #重写字段
                rename => {
                        "clientip" => "cip"
                }
        }
         mutate {
                #去掉没用字段
                remove_field => ["message","input_type","@version","fields"]
        }
}

output {
    stdout {}
}

增加新日志

复制代码
vim /var/log/httpd.log 
# 新加入一行日志

再次测试,你会发现 message 不见了,而且clientip重命名成了cip:

复制代码
/usr/local/logstash/bin/logstash -f config/first-pipeline.conf

{
          "ident" => "-",
       "referrer" => "\"http://semicomplete.com/presentations/logstash-monitorama-2013/\"",
           "verb" => "GET",
           "auth" => "-",
      "timestamp" => "04/Jan/2015:05:13:42 +0000",
       "response" => "200",
          "agent" => "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.77 Safari/537.36\"",
           "host" => "logstash",
            "cip" => "83.149.9.216",
    "httpversion" => "1.1",
     "@timestamp" => 2021-06-23T15:46:09.624Z,
        "request" => "/presentations/logstash-monitorama-2013/imageskibana-search.png",
          "bytes" => "203023",
           "path" => "/var/log/httpd.log"
}
filebeat和logstash联动

filebeat采集日志输出到logstash

复制代码
vim /usr/local/logstash/config/first-pipeline.conf

# 监听 5044 端口,接收 filebeat 的输入
input {
    beats {
      port => 5044
   }
}

filter {
    grok {
         match => { "message" => "%{COMBINEDAPACHELOG }" }
    }
}

output {
    stdout {}
}

运行logstash

复制代码
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf

运行 logstash 之后修改 filebeat 的 yml 文件输出目标如下

注意 : output只能有一个配置,只能输出到一个地方

复制代码
vim /usr/local/filebeat/filebeat.yml

# output.console:  # 注释原来输出到终端的配置
#  pretty: true

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /tmp/*.log

# 改为输出到logstash
output.logstash:
  # The Logstash hosts
  hosts: ["192.168.3.61:5044"]

运行filebeat

复制代码
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml

logstash接收到的filebeat的消息如下:

复制代码
{
      "@version" => "1",
       "message" => "ABG",
           "log" => {
        "offset" => 4,
          "file" => {
            "path" => "/tmp/access.log"
        }
    },
         "agent" => {
                  "id" => "e1fd3d9a-bf15-4cd7-9afa-faa9e4037cb4",
            "hostname" => "localhost",
        "ephemeral_id" => "b5b0c305-c123-4d66-899b-05abcdaf131f",
                "type" => "filebeat",
                "name" => "localhost",
             "version" => "7.13.2"
    },
           "ecs" => {},
          "host" => {
                   "id" => "70b835b3e58a4ec294e3f2ca23d3fbc1",
             "hostname" => "localhost",
                   "os" => {
            "codename" => "Core",
            "platform" => "centos",
              "kernel" => "3.10.0-693.el7.x86_64",
                "name" => "CentOS Linux",
             "version" => "7 (Core)",
                "type" => "linux",
              "family" => "redhat"
        },
        "containerized" => false,
                 "name" => "localhost",
                   "ip" => [
            [0] "192.168.232.138",
            [1] "fe80::d166:4c0b:187c:9b3a",
            [2] "fe80::fa61:ef46:73d7:d050"
        ],
                  "mac" => [
            [0] "00:0c:29:4a:13:ae"
        ],
         "architecture" => "x86_64"
    },
       "project" => {
          "id" => "574734885120952459",
        "name" => "myproject"
    },
    "@timestamp" => 2021-07-07T01:43:24.041Z,
          "tags" => [
        [0] "beats_input_codec_plain_applied",
        [1] "_grokparsefailure"
    ]
}
安装ElasticSearch集群

修改内核参数

复制代码
# 添加以内核参数设置
cat >> /etc/sysctl.conf << EOF
fs.file-max=655360
vm.max_map_count = 262144
EOF

#执行命令使内核参数生效
sysctl -p

cat >> /etc/security/limits.conf << EOF
*        soft    nproc           20480
*        hard    nproc           20480
*        soft    nofile          65536
*        hard    nofile          65536
*        soft    memlock         unlimited
*        hard    memlock         unlimited
EOF

解压安装包

复制代码
tar -xf elasticsearch-7.13.2-linux-x86_64.tar.gz -C /usr/local/
mv /usr/local/elasticsearch-7.13.2 /usr/local/elasticsearch

在每个节点创建用户 ela

复制代码
useradd ela
echo "123456" | passwd --stdin ela

在每个节点上对 ela 用户授权

复制代码
chown -R ela:ela /usr/local/elasticsearch

ela1 节点 设置的内容如下:

复制代码
vim /usr/local/elasticsearch/config/elasticsearch.yml
yaml 复制代码
# 文件末尾加入
cluster.name: elk
node.name: ela1
node.data: true
network.host: 0.0.0.0
http.port: 9200

discovery.seed_hosts:  #官方指定写法如下,3台机器一样
   - 192.168.3.61      #节点1
   - 192.168.3.62      #节点2
   - 192.168.3.63      #节点3
cluster.initial_master_nodes: ["192.168.3.61", "192.168.3.62", "192.168.3.63"]

ela2 节点设置的内容如下:

复制代码
vim /usr/local/elasticsearch/config/elasticsearch.yml
yaml 复制代码
# 文件末尾加入
cluster.name: elk
node.name: ela2
node.data: true
network.host: 0.0.0.0
http.port: 9200

discovery.seed_hosts:  #官方指定写法如下,3台机器一样
   - 192.168.3.61      #节点1
   - 192.168.3.62      #节点2
   - 192.168.3.63      #节点3
cluster.initial_master_nodes: ["192.168.3.61", "192.168.3.62", "192.168.3.63"]

ela3 节点设置的内容如下:

复制代码
vim /usr/local/elasticsearch/config/elasticsearch.yml
yaml 复制代码
# 文件末尾加入
cluster.name: elk
node.name: ela3
node.data: true
network.host: 0.0.0.0
http.port: 9200

discovery.seed_hosts:  #官方指定写法如下,3台机器一样
   - 192.168.3.61      #节点1
   - 192.168.3.62      #节点2
   - 192.168.3.63      #节点3
cluster.initial_master_nodes: ["192.168.3.61", "192.168.3.62", "192.168.3.63"]

参数说明

  • cluster.name 集群名称,各节点配成相同的集群名称。
  • node.name 节点名称,各节点配置不同。
  • node.data 指示节点是否为数据节点。数据节点包含并管理索引的一部分。
  • network.host 绑定节点IP。
  • http.port 监听端口。
  • path.data 数据存储目录。
  • path.logs 日志存储目录。
  • discovery.seed_hosts 指定集群成员,用于主动发现他们,所有成员都要写进来,包括自己,每个节点中应该写一样的信息。
  • cluster.initial_master_nodes 指定有资格成为 master 的节点
  • http.cors.enabled 用于允许head插件访问ES。
  • http.cors.allow-origin 允许的源地址。

注意:

  • 当您为提供自定义设置时 network.host,Elasticsearch会假设您正在从开发模式过渡到生产模式,并将许多系统启动检查从警告升级到异常。
  • cluster.initial_master_nodes 中的节点名称需要和 node.name 的名称一致。
启动集群

切换到普通用户 ela , 启动elasticsearch

复制代码
su - ela
/usr/local/elasticsearch/bin/elasticsearch -d -p /tmp/elasticsearch.pid

启动脚本

复制代码
vi start.sh
shell 复制代码
#!/bin/bash
# Elasticsearch 启动脚本(以用户 ela 运行)

# ========== 配置区 ==========
ES_USER="ela"                         # 运行 ES 的系统用户
ES_HOME="/usr/local/elasticsearch"    # ES 安装目录
PID_FILE="/tmp/elasticsearch.pid"     # PID 文件路径
# ============================

# 检查 PID 文件是否存在且进程仍在运行
if [ -f "$PID_FILE" ]; then
    pid=$(cat "$PID_FILE")
    if kill -0 "$pid" 2>/dev/null; then
        echo "Elasticsearch 已在运行,PID: $pid"
        exit 1
    else
        echo "发现过期的 PID 文件,正在移除..."
        rm "$PID_FILE"
    fi
fi

# 切换到 ES 用户并启动(su - 会加载用户环境,-c 执行命令)
su - "$ES_USER" -c "$ES_HOME/bin/elasticsearch -d -p $PID_FILE"

# 等待 2 秒,检查 PID 文件是否生成,确认启动成功
sleep 2
if [ -f "$PID_FILE" ]; then
    pid=$(cat "$PID_FILE")
    echo "Elasticsearch 启动成功,PID: $pid"
else
    echo "启动失败,请检查日志(位于 $ES_HOME/logs/)"
    exit 1
fi
shell 复制代码
chmod +x start.sh
./start.sh

默认端口号是 :

  • 9200 用于外部访问的监听端口,比如查看集群状态,向其传输数据,查询数据等
  • 9300 用户集群中节点之间的互相通信,比如主节点的选举,集群节点信息的通告等。

注意:如果集群配置错误,想重新初始化集群,只需要删除数据目录,重启服务即可

日志消息可以在 $ES_HOME/logs/ 目录中找到

常用es命令

查看集群健康状态

复制代码
[ela@ela3 logs]$ curl -X GET "192.168.3.61:9200/_cat/health?v"
epoch      timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1783868461 15:01:01  elk     green           3         3      0   0    0    0        0             0                  -                100.0%

三种不同状态的含义

  • 黄色 如果您仅运行单个Elasticsearch实例,则集群状态将保持黄色。单节点群集具有完整的功能,但是无法将数据复制到另一个节点以提供弹性。
  • 绿色 副本分片必须可用,群集状态为绿色。
  • 红色 如果群集状态为红色,则某些数据不可用。

查看集群节点信息

复制代码
curl -X GET "http://192.168.3.61:9200/_cat/nodes?v"
ip           heap.percent ram.percent cpu load_1m load_5m load_15m node.role  master name
192.168.3.62           35          97   0    0.00    0.03     0.03 cdhilmrstw -      ela2
192.168.3.61           27          96   0    0.01    0.06     0.06 cdhilmrstw *      ela1
192.168.3.63           27          62   0    0.00    0.05     0.05 cdhilmrstw -      ela3

检查集群状态

复制代码
curl -XGET 'http://localhost:9200/_cluster/health/?pretty'
{
  "cluster_name" : "elk",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 0,
  "active_shards" : 0,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}

查看ES中所有的索引

复制代码
curl -X GET http://192.168.3.61:9200/_cat/indices?v
  • health: 索引的健康状态,Elasticsearch 索引的健康状态有三种:green(绿色,健康),yellow(黄色,部分健康),red(红色,不健康)。"yellow" 状态表示索引的某些分片处于未分配状态,但主分片是可用的。
  • status: 索引的状态,这里是 "open"。这表示索引处于打开状态,可以进行读取和写入操作。
  • index: 索引的名称,这里是 "nginx-access-log-2023.09.13"。
  • uuid: 索引的唯一标识符。
  • pri: 主分片(primary shard)的数量,这里是 1 个主分片。
  • rep: 副本分片(replica shard)的数量,这里也是 1 个副本分片。
  • docs.count: 索引中文档的总数,这里是 20。
  • docs.deleted: 索引中已删除的文档数量,这里是 0。
  • store.size: 索引的存储大小,这里是 34.1KB。
  • pri.store.size: 主分片的存储大小,这里也是 34.1KB。

新建索引

复制代码
curl -X PUT http://192.168.3.61:9200/testyf

删除索引

复制代码
curl -X DELETE http://192.168.3.61:9200/testyf

查看指定索引信息

复制代码
curl -X GET http://192.168.3.61:9200/testyf?pretty

查看别名

复制代码
curl -X GET http://192.168.3.61:9200/_cat/aliases
es集群测试

使用 Filebeat 搜集 Nginx 的日志,输出到 Logstash, 再由 Logstash 处理完数据后输出到 Elasticsearch。

启动es集群

复制代码
su - ela
cd /usr/local/elasticsearch
./bin/elasticsearch -d

查看集群状态 为 green

复制代码
curl -XGET 'http://192.168.3.61:9200/_cluster/health/?pretty'

配置logstash

复制代码
vi /usr/local/logstash/config/first-pipeline.conf

input {
   beats {
      port => 5044
   }
}

filter {
    grok {
        match => { "message" => "%{COMBINEDAPACHELOG}" }
        remove_field => [ "message" ]
    }
    geoip {
       source => "clientip"
    }
}

output {
  stdout {
     codec => rubydebug
  }

  elasticsearch {  #原来基础上添加此配置
    # 这里是输出到 elasticsearch 集群中
    hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
  }
}

启动 Logstash

复制代码
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf

启动 Filebeat

复制代码
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml

查看 Logstash 的终端 , 应有相应的输出

复制代码
......
	"@timestamp" => 2026-07-13T13:33:59.538Z,
          "input" => {
        "type" => "log"
    },
           "verb" => "GET",
           "auth" => "-",
            "log" => {
        "offset" => 234,
          "file" => {
            "path" => "/tmp/access.log"
        }
....

验证Elasticsearch是否创建了索引

复制代码
[root@ela2 ~]# curl -X GET "192.168.3.61:9200/_cat/indices"
green open logstash-2026.07.13-000001 T9eheSsfSFyUwVT_Ctns_A 1 1 2 0 65.4kb 32.7kb

可以看到索引以创建,但索引是 Elasticsearch 是自动创建的,不过这往往不是生产中想要的。

通常把访问日志 access.log 中的内容单独放到一个索引中

编辑配置文件

复制代码
vim /usr/local/logstash/config/first-pipeline.conf
yaml 复制代码
input {
   beats {
      port => 5044
   }
}

filter {
    grok {
        match => { "message" => "%{COMBINEDAPACHELOG}" }
        remove_field => [ "message" ]
    }
    geoip {
       source => "clientip"
    }
}
output {
  stdout {
     codec => rubydebug
  }

  if [log][file][path] == "/tmp/access.log" {
    elasticsearch {
      hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
      index => "%{[host][hostname]}-nginx-access-%{+YYYY.MM.dd}"
    }
  } else if [log][file][path] == "/var/log/nginx/error.log" {
    elasticsearch {
      hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
      index => "%{[host][hostname]}-nginx-error-%{+YYYY.MM.dd}"
    }
  }
}

重启logstash

复制代码
ps -ef | grep logstash | grep -v grep | awk '{print $2}' | xargs kill -9

/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf

想access.log中新写入一行

复制代码
vi /tmp/access.log
124.127.39.57 - - [04/Mar/2026:10:50:28 +0800] "GET /logo.jpg HTTP/1.1" 200 14137 "http://81.68.233.173/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36" "-"

验证 Elasticsearch 集群中的索引

复制代码
[root@ela3 ~]# curl -X GET "192.168.3.61:9200/_cat/indices"
green open logstash-2026.07.13-000001       T9eheSsfSFyUwVT_Ctns_A 1 1 2 0 65.6kb 32.8kb
green open ela1.com-nginx-access-2026.07.13 ILGlwQ3tRXS-51bavKALvw 1 1 1 0 65.2kb 32.5kb

logstash-2026.07.13-000001 是原来自动创建的

ela1.com-nginx-access-2026.07.13 是新建立的,手动定义的索引

安装kibana

注意: kibana版本必须和es版本完全一致,否则kibana无法启动

复制代码
tar -xf kibana-7.13.2-linux-x86_64.tar.gz -C /usr/local/
mv /usr/local/kibana-7.13.2-linux-x86_64 /usr/local/kibana

配置主配置文件

复制代码
vim /usr/local/kibana/config/kibana.yml

server.port: 5601 #改
server.host: "0.0.0.0"  #改

# 用于连接到 ES 集群的地址和端口
elasticsearch.hosts: ["http://192.168.3.61:9200"] #改

# 日志文件路径
# logging.dest: stdout 
logging.dest: /var/log/kibana/kibana.log #改

# 设置页面的字体为中文
i18n.locale: "zh-CN"  #改

创建用于运行 kibana 的普通用户

默认情况下,kibana 不允许使用 root 用户运行,所以这里创建一个普通用户

复制代码
useradd kib
echo "123456" | passwd --stdin kib

创建程序使用到的目录并赋予权限

复制代码
mkdir /var/log/kibana/ -p
mkdir /run/kibana -p
chown kib:kib /run/kibana /var/log/kibana/ /usr/local/kibana -R

运行于前台

复制代码
su - kib
/usr/local/kibana/bin/kibana

运行于后台

复制代码
su - kib
nohup /usr/local/kibana/bin/kibana &

使用浏览器访问 http://192.168.3.61:5601

登录kibana创建索引

kafaka集群
kafka简介

数据缓冲队列。同时提高了可扩展性。具有峰值处理能力,使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。

Kafka是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、web/nginx日志、访问日志,消息服务等等,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。

1.话题(Topic):是特定类型的消息流。(每条发布到 kafka 集群的消息属于的类别,即 kafka 是面向 topic 的。)

2.生产者(Producer):是能够发布消息到话题的任何对象(发布消息到 kafka 集群的终端或服务).

3.消费者(Consumer):可以订阅一个或多个话题,从而消费这些已发布的消息。

4.服务代理(Broker):已发布的消息保存在一组服务器中,它们被称为代理(Broker)或Kafka集群。

5.partition(区):每个 topic 包含一个或多个 partition。

6.replication:partition 的副本,保障 partition 的高可用。

7.leader:replica 中的一个角色, producer 和 consumer 只跟 leader 交互。

8.follower:replica 中的一个角色,从 leader 中复制数据。

9.zookeeper:kafka 通过 zookeeper 来存储集群的信息。

Zookeeper简介

ZooKeeper是一个分布式协调服务,它的主要作用是为分布式系统提供一致性服务,提供的功能包括:配置维护、分布式同步等。Kafka的运行依赖ZooKeeper。也是java微服务里面使用的一个注册中心服务

ZooKeeper主要用来协调Kafka的各个broker,不仅可以实现broker的负载均衡,而且当增加了broker或者某个broker故障了,ZooKeeper将会通知生产者和消费者,这样可以保证整个系统正常运转。

在Kafka中,一个topic会被分成多个区并被分到多个broker上,分区的信息以及broker的分布情况与消费者当前消费的状态信息都会保存在ZooKeeper中。

部署zk

zk需要依赖jdk,安装jdk

复制代码
rpm -ivh jdk-8u131-linux-x64.rpm

Kafka运行依赖ZK,Kafka官网提供的tar包中,已经包含了ZK,这里不再额外下载ZK程序。

解压至目录

shell 复制代码
tar xzf kafka_2.12-2.8.0.tgz -C /usr/local/
mv /usr/local/kafka_2.12-2.8.0/ /usr/local/kafka/

分别配置三台kafka中的zookeeper

第一台节点

注释所有配置

shell 复制代码
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/zookeeper.properties

文件后添加如下配置

shell 复制代码
vi /usr/local/kafka/config/zookeeper.properties
shell 复制代码
dataDir=/opt/data/zookeeper/data    # 需要创建,所有节点一致
dataLogDir=/opt/data/zookeeper/logs # 需要创建,所有节点一致
clientPort=2181
tickTime=2000
initLimit=20
syncLimit=10

# 以下 IP 信息根据自己服务器的 IP 进行修改  kafka集群IP:Port
server.1=192.168.3.61:2888:3888
server.2=192.168.3.62:2888:3888
server.3=192.168.3.63:2888:3888

创建 data、log 目录

shell 复制代码
mkdir -p /opt/data/zookeeper/{data,logs}

创建myid文件 ,myid号按顺序排

shell 复制代码
echo 1 > /opt/data/zookeeper/data/myid

第二台节点

注释所有配置

shell 复制代码
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/zookeeper.properties

文件后添加如下配置

shell 复制代码
vi /usr/local/kafka/config/zookeeper.properties
shell 复制代码
dataDir=/opt/data/zookeeper/data    # 需要创建,所有节点一致
dataLogDir=/opt/data/zookeeper/logs # 需要创建,所有节点一致
clientPort=2181
tickTime=2000
initLimit=20
syncLimit=10

# 以下 IP 信息根据自己服务器的 IP 进行修改  kafka集群IP:Port
server.1=192.168.3.61:2888:3888
server.2=192.168.3.62:2888:3888
server.3=192.168.3.63:2888:3888

创建 data、log 目录

shell 复制代码
mkdir -p /opt/data/zookeeper/{data,logs}

创建myid文件 ,myid号按顺序排

shell 复制代码
echo 2 > /opt/data/zookeeper/data/myid

第三台节点

注释所有配置

shell 复制代码
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/zookeeper.properties

文件后添加如下配置

shell 复制代码
vi /usr/local/kafka/config/zookeeper.properties
shell 复制代码
# 需要创建,所有节点一致
dataDir=/opt/data/zookeeper/data
dataLogDir=/opt/data/zookeeper/logs
clientPort=2181
tickTime=2000
initLimit=20
syncLimit=10

# 以下 IP 信息根据自己服务器的 IP 进行修改  kafka集群IP:Port
server.1=192.168.3.61:2888:3888
server.2=192.168.3.62:2888:3888
server.3=192.168.3.63:2888:3888

创建 data、log 目录

shell 复制代码
mkdir -p /opt/data/zookeeper/{data,logs}

创建myid文件 ,myid号按顺序排

shell 复制代码
echo 3 > /opt/data/zookeeper/data/myid

配置项含义:

复制代码
dataDir 	ZK数据存放目录。
dataLogDir  ZK日志存放目录。
clientPort  客户端连接ZK服务的端口。
tickTime    ZK服务器之间或客户端与服务器之间维持心跳的时间间隔。
initLimit   允许follower连接并同步到Leader的初始化连接时间,当初始化连接时间超过该值,则表示连接失败。
syncLimit   Leader与Follower之间发送消息时如果follower在设置时间内不能与leader通信,那么此follower将会被丢弃。
server.1=192.168.3.61:2888:3888    2888是follower与leader交换信息的端口,3888是当leader挂了时用来执行选举时服务器相互通信的端口。

启动zk

复制代码
cd /usr/local/kafka
nohup bin/zookeeper-server-start.sh config/zookeeper.properties &

查看端口

复制代码
netstat -lntp | grep 2181
tcp6       0      0 :::2181           :::*           LISTEN      1226/java
部署Kafka

第一台节点

注释所有配置

shell 复制代码
sed -i 's/^[^#]/#&/' /usr/local/kafka/config/server.properties

文件后添加如下配置

shell 复制代码
vim /usr/local/kafka/config/server.properties
shell 复制代码
# 注意对应id
broker.id=1
# 注意对应ip
listeners=PLAINTEXT://192.168.3.61:9092
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/opt/data/kafka/logs
num.partitions=6
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=2
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.retention.hours=168
log.segment.bytes=536870912
log.retention.check.interval.ms=300000
zookeeper.connect=192.168.3.61:2181,192.168.3.62:2181,192.168.3.63:2181
zookeeper.connection.timeout.ms=6000
group.initial.rebalance.delay.ms=0

创建目录

shell 复制代码
mkdir -p /opt/data/kafka/logs

配置项含义:

复制代码
broker.id 
	每一个broker在集群中的唯一标识,要求是正数。在改变IP地址,不改变broker.id的时不会影响consumers
listeners=PLAINTEXT://192.168.3.61:9092       
	监听地址
num.network.threads  
	broker 处理消息的最大线程数,一般情况下不需要去修改
num.io.threads
	broker处理磁盘IO 的线程数 ,数值应该大于你的硬盘数
socket.send.buffer.bytes  		
	socket的发送缓冲区
socket.receive.buffer.bytes		
	socket的接收缓冲区
socket.request.max.bytes
	socket请求的最大数值,防止serverOOM,message.max.bytes必然要小于socket.request.max.bytes,会被topic创建时的指定参数覆盖
log.dirs        日志文件目录
num.partitions
num.recovery.threads.per.data.dir   每个数据目录(数据目录即指的是上述log.dirs配置的目录路径)用于日志恢复启动和关闭时的线程数量。
offsets.topic.replication.factor

transaction state log replication factor  事务主题的复制因子(设置更高以确保可用性)。 内部主题创建将失败,直到群集大小满足此复制因素要求

log.cleanup.policy = delete
	日志清理策略 选择有:delete和compact 主要针对过期数据的处理,或是日志文件达到限制的额度,会被 topic创建时的指定参数覆盖
log.cleanup.interval.mins=1
	指定日志每隔多久检查看是否可以被删除,默认1分钟	
log.retention.hours
	数据存储的最大时间 超过这个时间 会根据log.cleanup.policy设置的策略处理数据,也就是消费端能够多久去消费数据。log.retention.bytes和log.retention.minutes或者log.retention.hours任意一个达到要求,都会执行删除,会被topic创建时的指定参数覆盖

log.segment.bytes
	topic的分区是以一堆segment文件存储的,这个控制每个segment的大小,会被topic创建时的指定参数覆盖
log.retention.check.interval.ms 
	文件大小检查的周期时间,是否触发 log.cleanup.policy中设置的策略
zookeeper.connect   
	ZK主机地址,如果zookeeper是集群则以逗号隔开。
zookeeper.connection.timeout.ms     
	连接到Zookeeper的超时时间。

第二台节点

shell 复制代码
scp 192.168.3.61:/usr/local/kafka/config/server.properties 192.168.3.62:/usr/local/kafka/config/server.properties

mkdir -p /opt/data/kafka/logs

# 修改对应id 和 ip
vim /usr/local/kafka/config/server.properties

broker.id=2  # 注意对应id
listeners=PLAINTEXT://192.168.3.62:9092   # 注意对应ip

第三台节点

bash 复制代码
scp 192.168.3.61:/usr/local/kafka/config/server.properties 192.168.3.63:/usr/local/kafka/config/server.properties

mkdir -p /opt/data/kafka/logs

# 修改对应id 和 ip
vim /usr/local/kafka/config/server.properties

broker.id=3  # 注意对应id
listeners=PLAINTEXT://192.168.3.63:9092   # 注意对应ip

启动Kafka

shell 复制代码
cd /usr/local/kafka
nohup bin/kafka-server-start.sh config/server.properties &
验证kafka

在192.168.3.61上创建topic

复制代码
/usr/local/kafka/bin/kafka-topics.sh --create --zookeeper 192.168.3.61:2181 --replication-factor 1 --partitions 1 --topic testtopic
# Created topic testtopic. 

参数解释:
--zookeeper指定zookeeper的地址和端口
--partitions指定partition的数量
--replication-factor指定数据副本的数量

在192.168.3.62上面查询192.168.3.61上的topic

复制代码
/usr/local/kafka/bin/kafka-topics.sh --zookeeper 192.168.3.61:2181 --list
# testtopic

模拟消息生产和消费

发送消息到192.168.19.20

复制代码
/usr/local/kafka/bin/kafka-console-producer.sh --broker-list 192.168.3.61:9092 --topic testtopic
>hello
>你好呀

从192.168.3.61接受消息

复制代码
/usr/local/kafka/bin/kafka-console-consumer.sh --bootstrap-server  192.168.3.61:9092 --topic testtopic --from-beginning
hello
你好呀
logstash服务器从kafka获取数据并输出到es集群
shell 复制代码
vim /usr/local/logstash/config/first-pipeline.conf
shell 复制代码
input {
    kafka {
      type => "apache_log"
      codec => "json"
      topics => ["apache"]
      decorate_events => true
      bootstrap_servers => "192.168.3.61:9092, 192.168.3.62:9092, 192.168.3.63:9092"
    }
}

filter {
    grok {
        match => { "message" => "%{COMBINEDAPACHELOG}" }
        remove_field => [ "message" ]
    }
}
output {
    stdout {}
    if [type] == "apache_log" {  #和上面的type一致
      elasticsearch {
         index => "apache-%{+YYYY.MM.dd}"
         codec => "json"
         hosts => ["192.168.3.61:9200","192.168.3.62:9200","192.168.3.63:9200"]
      }
   }
}

decorate_events => true 默认是 false 这将向logstash 事件添加一个名为kafka的字段 ,这包含以下属性。

  • topic 主题:与此消息相关联的主题

  • consumer_group 使用者群组:此事件中用来读取的使用者群组

  • partition 分区:与此消息关联的分区

  • offset 偏移量:与此消息关联的分区的偏移量

  • key:包含message key的ByteBuffer

重启动 logstash

复制代码
kill -9 进程id
/usr/local/logstash/bin/logstash -f /usr/local/logstash/config/first-pipeline.conf --config.reload.automatic

配置 Filebeat 输出到 kafka

shell 复制代码
vim /usr/local/filebeat/filebeat.yml
shell 复制代码
# 注释其他 output filebeat只能有一个output位置

# output.console:  
#   pretty: true
# output.logstash:
  # The Logstash hosts
#   hosts: ["192.168.3.61:5044"]

# 配置输入端
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /tmp/*.log


# 加入以下配置,设置输出目标为kafka集群
output.kafka:
  hosts: ["192.168.3.61:9092", "192.168.3.62:9092", "192.168.3.63:9092"]
  topic: 'apache'
  partition.round_robin:
    reachable_only: false
  required_acks: 1
  compression: gzip
  max_message_bytes: 1000000

重新启动filebeat

复制代码
kill -9 进程id
/usr/local/filebeat/filebeat -c /usr/local/filebeat/filebeat.yml

获取apache topic

复制代码
[root@ela3 kafka]# /usr/local/kafka/bin/kafka-console-consumer.sh --bootstrap-server  192.168.3.61:9092 --topic apache  --from-beginning
{"@timestamp":"2026-07-19T01:50:42.128Z","@metadata":{"beat":"filebeat","type":"_doc","version":"7.13.2"},"log":{"offset":1872,"file":{"path":"/tmp/access.log"}},"message":"124.127.39.61 - - [04/Mar/2021:10:50:28 +0800] \"GET /logo.jpg HTTP/1.1\" 200 14137 \"http://81.68.233.173/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.192 Safari/537.36\" \"-\"","input":{"type":"log"},"ecs":{"version":"1.8.0"},"host":

es获取索引

复制代码
[root@ela3 kafka]# curl -X GET "192.168.3.61:9200/_cat/indices"
green open .apm-custom-link                 1mqc4K6WRKmcLh8GddR37Q 1 1  0  0    416b    208b
green open logstash-2026.07.13-000001       T9eheSsfSFyUwVT_Ctns_A 1 1  2  0  65.6kb  32.8kb
green open .kibana_task_manager_1           0svl5hNdQzWU80BA3zqP2A 1 1  5 40 323.6kb 162.3kb
green open .apm-agent-configuration         JG_SJgheQxOptCCPXbE5zA 1 1  0  0    416b    208b
green open .kibana-event-log-7.10.0-000001  IQtSHKjqRH6tkacvzGr8hQ 1 1  3  0  32.8kb  16.4kb
green open ela1.com-nginx-access-2026.07.13 ILGlwQ3tRXS-51bavKALvw 1 1  2  0 130.1kb    65kb
green open ela1.com-nginx-access-2026.07.18 HtOKF29STsyaeZaCAqUuPQ 1 1  1  0  65.3kb  32.6kb
green open .kibana_1                        VjbUWUD1SS6-nCFJlZUW-Q 1 1 34 11  20.8mb  10.4mb
green open apache-2026.07.19                LYYrhiddQ26xsAGZC38rMQ 1 1  1  0  51.8kb  25.8kb

kibana 中创建索引后适用discover查看如下

OK完结

相关推荐
Zane19941 小时前
JMM 与 happens-before:一次搞懂 Java 内存模型
java·后端
An_s1 小时前
Java Spring Boot+vue3文件管理系统
java·开发语言
wuqingshun3141591 小时前
接口和抽象类有什么区别?
java
SimonKing2 小时前
别再写 setter 了!MapStruct Plus vs MapStruct,谁才是 Bean 转换的真神?
java·后端·程序员
倒流时光三十年2 小时前
第一阶段 05 · Java 客户端查询类详解(Query / SearchCriteria / Response 与复杂拼接)
java·开发语言·python
rannn_1112 小时前
【力扣hot100】哈希表专题——从两数之和到最长连续序列
java·算法·leetcode·哈希
观远数据2 小时前
云原生BI的战略价值:不是技术选择,而是业务弹性的决定因素
java·人工智能·云原生
Full Stack Developme2 小时前
Tomcat 设计原理
java·tomcat