logstash定时同步elasticsearch数据

1.logstash简介

Logstash 是 Elastic Stack 的数据处理管道,负责采集、转换和输出 数据。

2.使用场景

由于业务需要,我需要将elastic集群中的数据定时同步到另一个独立的elastic单节点中,对比了一些工具,最后还是选择了logstash。

3.elastic环境准备

  • es集群和单节点部署这里就不作介绍了,我使用的是docker部署的
环境 IP地址 端口 elastic版本
elastic集群一主两从环境(生产环境) 192.168.1.2、192.168.1.3、192.168.1.4 使用nginx代理9201 7.1.1
elastic单节点(数据统计环境) 172.16.4.53 9200 7.1.1

4.logstash部署

4.1 创建容器映射目录

bash 复制代码
mkdir -p /data/logstash/{config,conf.d,logs,data}

4.2 创建logstash主配置文件(/data/logstash/config)

bash 复制代码
[root@localhost config]# cat /data/logstash/config/logstash.yml
http.host: "0.0.0.0"
path.config: /usr/share/logstash/conf.d/*.conf
path.logs: /var/log/logstash
path.data: /usr/share/logstash/data

4.3 创建logstash日志文件(/data/logstash/config)

bash 复制代码
[root@localhost config]# cat /data/logstash/config/log4j2.properties
# 日志级别:你可以根据需要调整,例如改成 DEBUG 可以看到更详细的同步过程
logger.elasticsearchoutput.name = logstash.outputs.elasticsearch
logger.elasticsearchoutput.level = DEBUG

logger.elasticsearchinput.name = logstash.inputs.elasticsearch
logger.elasticsearchinput.level = DEBUG

appender.console.type = Console
appender.console.name = plain_console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n

appender.rolling.type = RollingFile
appender.rolling.name = plain_rolling
appender.rolling.fileName = /var/log/logstash/logstash.log
appender.rolling.filePattern = /var/log/logstash/logstash-%d{yyyy-MM-dd}.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 30

rootLogger.level = DEBUG
rootLogger.appenderRef.console.ref = plain_console
rootLogger.appenderRef.rolling.ref = plain_rolling

4.4 创建数据同步配置(/data/logstash/conf.d)

input 导出数据绝不会影响源集群的原始数据。

Logstash 使用 Elasticsearch 的 只读 Scroll API 拉取数据,整个过程仅执行搜索请求,不会对源索引的文档、设置或映射做任何修改、删除或写入操作。你可以把它理解为在 Kibana 里执行了一次查询,只是结果被转发到了别处。

bash 复制代码
[root@localhost conf.d]# cat /data/logstash/conf.d/sync_to_single.conf
input {
  elasticsearch {
    hosts => ["http://192.168.1.2:9201"]   # 替换为源集群IP
    user => "elastic"
    password => "123456"
    index => "lipc_test88,cm_aidata2"           # 替换为实际索引名
    size => 1000
    scroll => "5m"
    docinfo => true
    #schedule => "55 17 * * *"                # 需要定时同步时放开
  }
}

filter {
  mutate {
    remove_field => ["@version", "@timestamp"]
  }
}

output {
  elasticsearch {
    hosts => ["http://172.16.4.53:9200"]  #替换为目标地址
    user => "elastic"
    password => "123456"
    index => "%{[@metadata][_index]}"
    document_id => "%{[@metadata][_id]}"
    action => "index"
  }
  stdout { codec => rubydebug }
}

4.5 设置容器映射目录权限

bash 复制代码
chown -R 1000:1000 /data/logstash

4.6 启动logstash容器

  • logstash版本需要与elastic版本一致,否则同步数据可能会有问题
bash 复制代码
[root@localhost logstash ]# cat /data/logstash/docker-compose.yaml
version: '3.8'

services:
  logstash:
    image: docker.elastic.co/logstash/logstash:7.1.1
    container_name: logstash-sync
    restart: unless-stopped                # 容器退出后自动重启,除非手动停止
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - /data/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
      - /data/logstash/conf.d/:/usr/share/logstash/conf.d/
      - /data/logstash/logs:/var/log/logstash
      - /data/logstash/data:/usr/share/logstash/data
      - /data/logstash/config/log4j2.properties:/usr/share/logstash/config/log4j2.properties
    network_mode: "host"

5.定时同步测试

5.1 创建测试数据并插入elastic

  • 创建测试数据文件
bash 复制代码
[root@localhost elastic]# cat test_data_multiday.ndjson
{"index":{"_index":"cm_aidata2_new","_id":"1"}}
{"id":"1","name":"张三","age":30,"position":"工程师","event_date":"2026-03-04T09:00:00+08:00"}
{"index":{"_index":"cm_aidata2_new","_id":"2"}}
{"id":"2","name":"李四","age":25,"position":"设计师","event_date":"2026-03-04T14:30:00+08:00"}
{"index":{"_index":"cm_aidata2_new","_id":"3"}}
{"id":"3","name":"王五","age":35,"position":"经理","event_date":"2026-03-04T20:15:00+08:00"}
{"index":{"_index":"cm_aidata2_new","_id":"4"}}
{"id":"4","name":"赵六","age":28,"position":"开发","event_date":"2026-03-06T10:00:00+08:00"}
{"index":{"_index":"cm_aidata2_new","_id":"5"}}
{"id":"5","name":"孙七","age":32,"position":"测试","event_date":"2026-03-06T15:45:00+08:00"}
  • 测试数据导入elastic
bash 复制代码
[root@localhost elastic]# cat load_es_data.sh
#!/bin/bash
curl -u elastic:123456 -H "Content-Type: application/x-ndjson" \
  -XPOST "http://127.0.0.1:9200/_bulk?pretty" \
  --data-binary "@test_data_multiday.ndjson"
  • 查询数据归档数量
bash 复制代码
# 查询文档总数
[root@localhost elastic]# curl -u elastic:123456 "http://127.0.0.1:9201/cm_aidata2_new/_count?pretty"
{
  "count" : 5,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  }
}

5.2 定时全量同步

  • 取消sync_to_single.conf中配置文件定时同步的注释,设定时间按照"分 时 日 月 周" 配置,如下就是每天的17:55执行定时同步,定时同步会重新覆盖之前的数据,请注意!!!
bash 复制代码
[root@localhost conf.d]# cat /data/logstash/conf.d/sync_to_single.conf
schedule => "55 17 * * *"                # 需要定时同步时放开

5.3 定时增量同步

  • sync_to_single.conf配置文件增加如下内容,每天晚上22:50听不一天之前的数据
bash 复制代码
    schedule => "50 22 * * *"                # 需要定时同步时放开
    query => '{
      "query": {
        "range": {
          "event_date": {
            "gte": "now-1d/d",
             "lt": "now/d",
             "time_zone": "+08:00"
          }
        }
      }
    }'
  • 实时同步10分钟内的数据
bash 复制代码
    schedule => "* * * * *"                # 需要定时同步时放开
    query => '{
      "query": {
        "range": {
          "event_date": {
             "gte": "now-10m",
             "lte": "now/m",
             "time_zone": "+08:00"
          }
        }
      }
    }'
  • 完整配置文件如下
bash 复制代码
[root@localhost conf.d]# cat sync_to_single.conf
input {
  elasticsearch {
    hosts => ["http://192.168.1.2:9201"]   # 替换为源集群IP
    user => "elastic"
    password => "ytx@1234"
    index => "cm_aidata2_new"           # 替换为实际索引名
    size => 1000
    scroll => "5m"
    docinfo => true
    schedule => "51 14 * * *"                # 需要定时同步时放开
    query => '{
      "query": {
        "range": {
          "event_date": {
            "gte": "now-1d/d",
             "lt": "now/d",
             "time_zone": "+08:00"
          }
        }
      }
    }'
  }
}

filter {
  mutate {
    remove_field => ["@version", "@timestamp"]
  }
}

output {
  elasticsearch {
    hosts => ["http://172.16.4.53:9200"]
    user => "elastic"
    password => "ytx@1234"
    index => "%{[@metadata][_index]}"
    document_id => "%{[@metadata][_id]}"
    action => "index"
  }
  stdout { codec => rubydebug }
}

5.4 重启logstash

bash 复制代码
docker restart logstash-sync

5.5 在源elastic节点查看符合增量同步的的数据,可以看到有两条,在cm_aidata2_new索引中

bash 复制代码
# 查询测试范围查询(仅返回 3 月 6 日数据)
[root@localhost elastic]# curl -u elastic:123456 -X GET "http://127.0.0.1:9200/cm_aidata2_new/_search?pretty" -H 'Content-Type: application/json' -d'
> {
>   "query": {
>     "range": {
>       "event_date": {
>         "gte": "2026-03-06T00:00:00+08:00",
>         "lt": "2026-03-07T00:00:00+08:00"
>       }
>     }
>   }
> }'
{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "cm_aidata2_new",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "id" : "4",
          "name" : "赵六",
          "age" : 28,
          "position" : "开发",
          "event_date" : "2026-03-06T10:00:00+08:00"
        }
      },
      {
        "_index" : "cm_aidata2_new",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "id" : "5",
          "name" : "孙七",
          "age" : 32,
          "position" : "测试",
          "event_date" : "2026-03-06T15:45:00+08:00"
        }
      }
    ]
  }
}

5.6 在目标节点(172.16.4.53)查看是否同步到源节点(192.168.1.2)的增量数据

bash 复制代码
[root@localhost conf.d]# curl -u elastic:123456 -X GET "http://172.16.4.53:9200/cm_aidata2_new/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "range": {
      "event_date": {
        "gte": "2026-03-06T00:00:00+08:00",
        "lt": "2026-03-07T00:00:00+08:00"
      }
    }
  }
}'
{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "cm_aidata2_new",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "age" : 28,
          "event_date" : "2026-03-06T10:00:00+08:00",
          "position" : "开发",
          "id" : "4",
          "name" : "赵六"
        }
      },
      {
        "_index" : "cm_aidata2_new",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "age" : 32,
          "event_date" : "2026-03-06T15:45:00+08:00",
          "position" : "测试",
          "id" : "5",
          "name" : "孙七"
        }
      }
    ]
  }
}

6.编写elastic命令执行小工具

  • 可以使用小工具执行es常用命令
bash 复制代码
[root@localhost elastic]# cat es_command.sh
#!/bin/bash
# ES 快捷命令工具 - 支持数字/中文/英文
# 使用方法: ./es_quick.sh [命令] 或直接运行交互式

ES_HOST="127.0.0.1:9200"
USER="elastic"
PASS="123456"

# 基础curl命令
curl_es() {
    curl -s -u "$USER:$PASS" "$@"
}

# 显示帮助
show_help() {
    echo "========================================"
    echo "ES 快捷命令工具"
    echo "========================================"
    echo "数字 | 中文   | 英文       | 功能"
    echo "----------------------------------------"
    echo "1    | 索引   | index      | 查看所有索引"
    echo "2    | 容量   | disk       | 查看磁盘使用"
    echo "3    | 健康   | health     | 查看集群健康"
    echo "4    | 节点   | node       | 查看节点信息"
    echo "5    | 分片   | shard      | 查看分片分配"
    echo "6    | 文档   | count      | 查看文档数量"
    echo "7    | 搜索   | search     | 搜索索引数据"
    echo "8    | 映射   | mapping    | 查看索引映射"
    echo "9    | 设置   | setting    | 查看索引设置"
    echo "10   | 统计   | stats      | 查看集群统计"
    echo "11   | 任务   | task       | 查看任务列表"
    echo "12   | 模板   | template   | 查看索引模板"
    echo "13   | 删除   | delete     | 删除索引"
    echo "14   | 创建   | create     | 创建索引"
    echo "15   | 别名   | alias      | 查看别名"
    echo "16   | 快照   | snapshot   | 查看快照仓库"
    echo "17   | ILM    | ilm        | 查看ILM策略"
    echo "18   | SQL    | sql        | 查看SQL状态"
    echo "19   | 状态   | status     | 查看集群状态"
    echo "20   | 帮助   | help       | 显示此帮助"
    echo "0    | 退出   | exit       | 退出程序"
    echo "========================================"
}

# 执行命令
execute_command() {
    case $1 in
        # 数字命令
        1|索引|index)
            curl_es "http://$ES_HOST/_cat/indices?v"
            ;;
        2|容量|disk)
            curl_es "http://$ES_HOST/_cat/allocation?v"
            ;;
        3|健康|health)
            curl_es "http://$ES_HOST/_cluster/health?pretty"
            ;;
        4|节点|node)
            curl_es "http://$ES_HOST/_cat/nodes?v"
            ;;
        5|分片|shard)
            curl_es "http://$ES_HOST/_cat/shards?v"
            ;;
        6|文档|count)
            echo -n "索引名(回车查看所有): "
            read idx
            if [ -z "$idx" ]; then
                curl_es "http://$ES_HOST/_cat/count?v"
            else
                curl_es "http://$ES_HOST/$idx/_count"
            fi
            ;;
        7|搜索|search)
            echo -n "索引名: "
            read idx
            echo -n "搜索关键字: "
            read keyword
            if [ -n "$keyword" ]; then
                curl_es "http://$ES_HOST/$idx/_search?q=$keyword&size=5&pretty"
            else
                curl_es "http://$ES_HOST/$idx/_search?size=5&pretty"
            fi
            ;;
        8|映射|mapping)
            echo -n "索引名(回车查看所有): "
            read idx
            if [ -z "$idx" ]; then
                curl_es "http://$ES_HOST/_all/_mapping?pretty"
            else
                curl_es "http://$ES_HOST/$idx/_mapping?pretty"
            fi
            ;;
        9|设置|setting)
            echo -n "索引名(回车查看所有): "
            read idx
            if [ -z "$idx" ]; then
                curl_es "http://$ES_HOST/_all/_settings?pretty"
            else
                curl_es "http://$ES_HOST/$idx/_settings?pretty"
            fi
            ;;
        10|统计|stats)
            curl_es "http://$ES_HOST/_cluster/stats?human&pretty"
            ;;
        11|任务|task)
            curl_es "http://$ES_HOST/_tasks?detailed&pretty"
            ;;
        12|模板|template)
            curl_es "http://$ES_HOST/_cat/templates?v"
            ;;
        13|删除|delete)
            echo -n "要删除的索引名: "
            read idx
            curl_es -X DELETE "http://$ES_HOST/$idx?pretty"
            ;;
        14|创建|create)
            echo -n "要创建的索引名: "
            read idx
            curl_es -X PUT "http://$ES_HOST/$idx"
            ;;
        15|别名|alias)
            curl_es "http://$ES_HOST/_cat/aliases?v"
            ;;
        16|快照|snapshot)
            curl_es "http://$ES_HOST/_snapshot?pretty"
            ;;
        17|ILM|ilm)
            curl_es "http://$ES_HOST/_ilm/policy?pretty"
            ;;
        18|SQL|sql)
            curl_es -X POST "http://$ES_HOST/_sql?format=txt" \
                -H "Content-Type: application/json" \
                -d '{"query": "SHOW TABLES"}'
            ;;
        19|状态|status)
            curl_es "http://$ES_HOST/"
            ;;
        20|帮助|help)
            show_help
            ;;
        0|退出|exit|quit)
            echo "再见!"
            exit 0
            ;;
        *)
            echo "未知命令: $1"
            echo "输入 'help' 查看可用命令"
            ;;
    esac
}

# 主程序
main() {
    # 如果有参数,直接执行命令
    if [ $# -gt 0 ]; then
        execute_command "$1"
        exit 0
    fi

    # 交互式模式
    while true; do
        echo -e "\n========================================"
        echo -e "输入命令: \033[1;33m[数字/中文/英文]\033[0m"
        echo -e "示例: 1 或 索引 或 index"
        echo -e "输入 help 查看所有命令"
        echo -e "========================================"
        echo -n "命令: "
        read cmd
        execute_command "$cmd"
    done
}

# 检查连接
check_connection() {
    echo "测试ES连接..."
    if curl_es "http://$ES_HOST" > /dev/null 2>&1; then
        echo -e "\033[32m✓ 连接成功\033[0m"
    else
        echo -e "\033[31m✗ 连接失败\033[0m"
        exit 1
    fi
}

# 启动
check_connection
main "$@"
相关推荐
Elastic 中国社区官方博客4 小时前
如何使用 OpenTelemetry 对你的搜索 API 进行埋点,并使用 ES|QL 对其进行查询
大数据·功能测试·elasticsearch·搜索引擎·全文检索·可用性测试
BerryS3N1 天前
Code Git 工作树:多分支开发的痛点与工作树的曙光
大数据·git·elasticsearch
Elasticsearch1 天前
Elastic 与 Deductive AI 携手合作,加速工程团队的 agent 式事件调查
elasticsearch
Elasticsearch1 天前
将你的 Grafana Kubernetes 仪表板迁移到 Elastic Observability:相同的 PromQL,30 倍更快的查询
elasticsearch
爱莉希雅&&&1 天前
elasticsearch+kibana+logstash+filebeat链路部署流程
大数据·elasticsearch·搜索引擎·kibana·logstash·filebeat
前端 贾公子1 天前
Git Worktree 使用指南
大数据·elasticsearch·搜索引擎
Elasticsearch1 天前
如何使用 OpenTelemetry 对你的搜索 API 进行埋点,并使用 ES|QL 对其进行查询
elasticsearch
阿里云大数据AI技术2 天前
更快、更稳、更省:揭秘阿里云 Elasticsearch 存算分离与弹性扩缩
elasticsearch
阿里云大数据AI技术2 天前
Search Lake:ES x Paimon 让湖上多模态数据可搜可用
人工智能·elasticsearch·搜索引擎