MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

ElasticSearch集群启动日志的分析与应用

2021-06-193.5k 阅读

ElasticSearch集群启动日志概述

ElasticSearch是一个分布式、RESTful 风格的搜索和数据分析引擎,广泛应用于各种规模的企业级搜索和大数据分析场景。在搭建和维护 ElasticSearch 集群时,启动日志是了解集群状态、排查潜在问题的重要依据。

ElasticSearch 的启动日志通常记录在 logs 目录下,文件名类似于 elasticsearch.log。日志文件记录了从 ElasticSearch 进程启动到初始化完成的一系列事件,包括节点发现、集群状态更新、插件加载等关键信息。

启动日志的基本结构

  1. 时间戳:日志的每一行都以时间戳开头,精确到毫秒,例如 2023-11-15T10:15:30.123+08:00,这有助于确定事件发生的具体时间。
  2. 日志级别:常见的日志级别有 DEBUGINFOWARNERRORFATALDEBUG 级别提供最详细的信息,常用于开发和调试;INFO 级别记录正常的运行信息;WARN 级别表示可能存在潜在问题,但不影响系统正常运行;ERROR 级别表示出现错误,需要关注;FATAL 级别则表示严重错误,可能导致系统无法正常运行。
  3. 线程名称:标识产生日志的线程,对于多线程的 ElasticSearch 来说,通过线程名称可以追踪特定操作的执行路径。
  4. 日志内容:具体的日志信息,描述了发生的事件、操作结果或错误详情。

关键启动日志分析

  1. 节点启动信息
[2023-11-15T10:15:30.123+08:00][INFO ][o.e.n.Node               ] [node-1] version[8.7.0], pid[12345], build[default/tar/abcdef1234567890], OS[Linux/5.15.0-1033-azure/x86_64], JVM[Oracle Corporation/OpenJDK 11.0.17/11.0.17+8-LTS]

这行日志表明节点 node - 1 正在启动,使用的 ElasticSearch 版本为 8.7.0,进程 ID 为 12345,运行在 Linux 系统上,JVM 版本为 OpenJDK 11.0.17。通过这些信息,可以确认节点的基本环境配置是否符合预期。

  1. 集群发现与加入
[2023-11-15T10:15:35.456+08:00][INFO ][o.e.d.z.ZenDiscovery     ] [node-1] failed to send join request to master {node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20} (reason: master not discovered yet)

这表明 node - 1 在尝试加入集群时,无法连接到主节点 node - 2,原因是主节点尚未被发现。这可能是网络问题、配置错误(如 cluster.initial_master_nodes 配置不当)或主节点本身尚未完全启动。

  1. 主节点选举
[2023-11-15T10:16:00.789+08:00][INFO ][o.e.c.m.MasterService    ] [node-2] elected-as-master ([1] nodes joined), reason: new_master {node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}, term: 1, version: 1, delta: master node changed {previous [], current [{node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}]}

此日志说明 node - 2 被选举为主节点,term 表示选举轮次,version 表示集群状态版本。主节点选举成功意味着集群开始稳定运行,其他节点将尝试连接主节点以同步状态。

  1. 索引与分片分配
[2023-11-15T10:16:10.012+08:00][INFO ][o.e.c.r.a.AllocationService] [node-2] updating number of replicas of [my_index] from [1] to [2] (reason: index has successfully assigned primary shard to [node-1] so can increase number of replicas)

这行日志显示集群正在调整 my_index 索引的副本数,从 1 增加到 2。原因是主分片已成功分配到 node - 1,因此可以增加副本数以提高数据可用性和查询性能。通过观察这类日志,可以了解集群的数据分布和负载均衡情况。

常见启动问题及日志分析

  1. 端口冲突
[2023-11-15T10:14:20.234+08:00][ERROR][o.e.b.Bootstrap          ] [node-1] Exception
java.net.BindException: Address already in use: bind
        at sun.nio.ch.Net.bind0(Native Method)
        at sun.nio.ch.Net.bind(Net.java:461)
        at sun.nio.ch.Net.bind(Net.java:453)
        at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:222)
        at io.netty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:134)
        at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:565)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1334)
        at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:501)
        at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:486)
        at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:989)
        at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:254)
        at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:356)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at java.lang.Thread.run(Thread.java:834)

此错误日志表明 node - 1 在启动时无法绑定到指定端口,因为该端口已被其他进程占用。解决方法是找出占用端口的进程并终止它,或者修改 ElasticSearch 的配置文件,使用其他可用端口。

  1. JVM 内存配置问题
[2023-11-15T10:14:40.567+08:00][FATAL][o.e.b.Bootstrap          ] [node-1] node validation exception
[1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

这表明 node - 1vm.max_map_count 参数设置过低,ElasticSearch 需要至少 262144。这是因为 ElasticSearch 使用内存映射文件来存储数据,过低的 vm.max_map_count 可能导致内存分配失败。解决方法是通过 sysctl -w vm.max_map_count=262144 命令临时修改,或在 /etc/sysctl.conf 文件中添加 vm.max_map_count=262144 并重启系统使其永久生效。

  1. 插件加载失败
[2023-11-15T10:15:20.890+08:00][ERROR][o.e.p.PluginsService     ] [node-1] failed to load plugin [x-pack]
org.elasticsearch.plugins.PluginValidationException: Plugin [x-pack] is not compatible with Elasticsearch version [8.7.0]

这行日志说明 node - 1 在加载 x - pack 插件时失败,原因是该插件与当前 ElasticSearch 版本不兼容。需要检查插件版本,并下载与 ElasticSearch 版本匹配的插件重新安装。

利用启动日志进行性能优化

  1. 监控节点初始化时间 通过分析启动日志中的时间戳,可以计算出每个节点从启动到完全初始化所需的时间。如果某个节点初始化时间过长,可能是由于硬件性能不足、配置复杂或加载大量数据导致。例如,在启动日志中找到节点启动和初始化完成的时间记录:
[2023-11-15T10:15:30.123+08:00][INFO ][o.e.n.Node               ] [node-1] version[8.7.0], pid[12345], build[default/tar/abcdef1234567890], OS[Linux/5.15.0-1033-azure/x86_64], JVM[Oracle Corporation/OpenJDK 11.0.17/11.0.17+8-LTS]
[2023-11-15T10:16:30.789+08:00][INFO ][o.e.c.s.ClusterService   ] [node-1] added {{node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20},}, term: 1, version: 1, reason: join from node [{node-1}{efgh5678}{192.168.1.101}{192.168.1.101:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}]

从以上日志可知,node - 1 从启动到加入集群花费了约 60 秒。如果这个时间超出预期,可以进一步分析日志中加载插件、初始化索引等步骤的时间,找出性能瓶颈。

  1. 优化主节点选举过程 主节点选举对集群的稳定性和性能至关重要。通过分析主节点选举的日志,可以了解选举的延迟和频率。如果选举频繁发生,可能是由于网络不稳定、节点故障或配置不当导致。例如:
[2023-11-15T10:16:00.789+08:00][INFO ][o.e.c.m.MasterService    ] [node-2] elected-as-master ([1] nodes joined), reason: new_master {node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}, term: 1, version: 1, delta: master node changed {previous [], current [{node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}]}
[2023-11-15T10:17:00.123+08:00][INFO ][o.e.c.m.MasterService    ] [node-3] elected-as-master ([2] nodes joined), reason: new_master {node-3}{ijkl7890}{192.168.1.102}{192.168.1.102:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}, term: 2, version: 2, delta: master node changed {previous [{node-2}{abcd1234}{192.168.1.100}{192.168.1.100:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}], current [{node-3}{ijkl7890}{192.168.1.102}{192.168.1.102:9300}{dimmed}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20}]}

在短时间内主节点从 node - 2 切换到 node - 3,这可能需要检查网络连接、节点健康状态以及 discovery.zen.minimum_master_nodes 等配置参数是否合理。

  1. 调整索引和分片分配策略 启动日志中关于索引和分片分配的信息,可以帮助优化数据分布和查询性能。例如,如果发现某个节点上的分片数量过多,导致负载过高,可以通过调整 index.routing.allocation.total_shards_per_node 等参数来平衡分片分配。假设日志中有如下记录:
[2023-11-15T10:16:10.012+08:00][INFO ][o.e.c.r.a.AllocationService] [node-2] updating number of replicas of [my_index] from [1] to [2] (reason: index has successfully assigned primary shard to [node-1] so can increase number of replicas)
[2023-11-15T10:16:15.345+08:00][WARN ][o.e.c.r.a.AllocationService] [node-2] some shards of [my_index] are not allocated yet, nodes with unassigned shards: [[node-3][ijkl7890][192.168.1.102][192.168.1.102:9300][dimmed][ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20]]

这表明 my_index 索引的一些分片在 node - 3 上未分配成功。可以进一步分析日志中的原因,如磁盘空间不足、节点负载过高等,并相应地调整分配策略。

自动化分析启动日志的脚本示例

为了更高效地分析 ElasticSearch 启动日志,可以编写自动化脚本。以下是一个使用 Python 和正则表达式分析日志文件的示例:

import re

log_file_path = 'elasticsearch.log'

# 定义正则表达式模式
timestamp_pattern = re.compile(r'\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}\+\d{2}:\d{2})\]')
log_level_pattern = re.compile(r'\[(\w+)\]')
node_name_pattern = re.compile(r'\[(\w+-\d+)\]')
error_pattern = re.compile(r'\[ERROR\].*Exception')

with open(log_file_path, 'r', encoding='utf-8') as f:
    for line in f:
        timestamp_match = timestamp_pattern.search(line)
        log_level_match = log_level_pattern.search(line)
        node_name_match = node_name_pattern.search(line)
        error_match = error_pattern.search(line)

        if timestamp_match and log_level_match and node_name_match:
            timestamp = timestamp_match.group(1)
            log_level = log_level_match.group(1)
            node_name = node_name_match.group(1)

            if error_match:
                print(f'[{timestamp}] [{log_level}] [{node_name}] Error detected: {line.strip()}')
            else:
                print(f'[{timestamp}] [{log_level}] [{node_name}] {line.strip()}')

这个脚本可以读取 ElasticSearch 日志文件,提取时间戳、日志级别和节点名称,并标记出包含错误信息的日志行。通过扩展正则表达式和逻辑,可以实现更复杂的分析功能,如统计不同类型错误的数量、分析特定操作的执行时间等。

与其他工具结合分析启动日志

  1. Kibana Kibana 是 ElasticSearch 的官方可视化工具,它可以与 ElasticSearch 集成,将日志数据可视化展示。通过在 Kibana 中创建索引模式,并导入 ElasticSearch 启动日志数据,可以使用 Kibana 的可视化界面进行深入分析。例如,可以创建柱状图展示不同节点的启动时间分布,或者使用折线图跟踪主节点选举的频率变化。

  2. Logstash Logstash 是一个数据收集、处理和转发的工具。可以配置 Logstash 从 ElasticSearch 启动日志文件中读取数据,进行清洗、转换和过滤,然后将处理后的数据发送回 ElasticSearch 或其他存储系统。例如,可以使用 Logstash 提取日志中的关键信息,如错误类型、节点名称等,并将其存储在 ElasticSearch 的特定索引中,以便于后续查询和分析。

结论

ElasticSearch 集群启动日志是了解集群运行状态、排查问题和优化性能的重要资源。通过深入分析启动日志中的关键信息,如节点启动、集群发现、主节点选举、索引分片分配等,可以及时发现并解决潜在问题,确保集群的稳定运行。结合自动化脚本和可视化工具,可以更高效地处理和分析大量的日志数据,为 ElasticSearch 集群的运维和优化提供有力支持。在实际应用中,应养成定期查看和分析启动日志的习惯,不断积累经验,提高 ElasticSearch 集群的管理水平。