官方es搭建步骤写的很简略, 但是实际搭建过程中, 会涉及一系列环境配置. 以下的流程, 是在搭建过程中梳理出来的详细步骤(实践过3遍以上)

其实, 这些流程在具体应用的时候, 都可以变成自动化脚本, 或者直接用docker好了, 以便扩容足够快(目前我们用的打包成集成安装包, 实现脚本自动部署)

只是简单集群的基本设置, 不涉及调优的参数配置, 不涉及client/master/data节点区分等等. 可以参照搭建的主体流程.


版本及连接

elasticseearch版本: 2.3.3

相关链接: - 官网 - 文档

系统要求

如果仅作测试用, 不需要两天机器, 可以将两个节点部署在同一台机器上, 对磁盘/cpu要求不高, 内存大于2g基本足够了

如果是正式环境, 需要根据日志量进行评估, 例如, 每天日志量占硬盘约约10G, 且保留30天日志, 则磁盘会占用约300g, es设定的阈值是磁盘空间占满85%则日志开始告警. 所以, 需要至少 300/0.85=354g.

准备两台机器, 在同一个局域网内(可ping通), 分别在每台机器上部署相应es节点, 搭建一套日志集群.

两台机器, 最少的资源了, 但是没法做到高可用, 所以, 还需要再加一台机器, 防止脑裂, 具体见最后(两台主力机器+一台稳定的机器就行)

  • 集群节点: 最少两台机器
  • 内存: 16G及以上
  • cpu: 4核及以上
  • 硬盘: 800G及以上, 建议1T, 集群容量约10亿级(取决于对应日志大小)
  • 操作系统: centos

这里假设, 两台机器ip分别为

第一台机器: 10.0.0.1
第二台机器: 10.0.0.2

机器系统为centos6.5

部署

1. 确认JDK版本及安装

es依赖java的版本最小为1.7

java -version
  • 如果系统中未安装JDK

则命令返回bash: java: command not found, 需要安装JDK

  • 如果系统中安装了JDK, 需确认版本是否大于java 1.7, 否则需要升级 java version "1.7.0_51" Java(TM) SE Runtime Environment (build 1.7.0_51-b13) Java HotSpot(TM) Server VM (build 24.51-b03, mixed mode)

安装及升级java(注意根据系统不同运行对应安装命令)

# Redhat/Centos/Fedora
sudo yum install java-1.7.0-openjdk

或者到官网, 下载最新的jdk的rpm包, 然后安装

wget http://download.oracle.com/otn-pub/java/jdk/8u91-b14/jdk-8u91-linux-x64.rpm
rpm -Uvh jdk-8u91-linux-x64.rpm

再次确认安装成功

java -version

2. 下载es

版本: 2.3.3

下载地址: - elasticsearch-2.3.3.tar.gz (tar.gz格式)

命令行中的下载命令:

curl -L -O https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.3.3/elasticsearch-2.3.3.tar.gz

解压:

tar -xzf elasticsearch-2.3.3.tar.gz

3. 用户/目录/权限设置

新建用户, 假设为es

sudo useradd es

新建目录, 假设/data/目录挂载的硬盘最大(500G以上)

mkdir -p /data/LogTool
mkdir -p /data/LogData

将解压后的目录移动至新建的目录/data/LogTool下, 并改名为elasticsearch

mv elasticsearch-2.3.3 /data/LogTool/elasticsearch

将目录所有者修改为test

chown -R es:es /data/LogTool
chown -R es:es /data/LogData

5. 切换用户

切换到es用户, 并进入elasticsearch目录

su es
cd /data/LogTool/elasticsearch/

以用户es的身份进行后续操作

6. 修改配置文件

以用户es的身份进行操作

文件路径: config/elasticsearch.yml

修改该文件中配置项: (注意, 原始文件中都是被#号注释掉了, 需要去掉对应注释并修改配置值)

  • 集群名: cluster.name, 注意: 两台机器配置一致
cluster.name: inner_es_cluster
  • 节点名: node.name, 注意: 两台机器配置不同, 一台为01, 另一台为02
# 第一台机器
node.name: inner_es_node_01

# 第二台机器
node.name: inner_es_node_02
  • 数据路径: path.data, 为新建立的目录
path.data: /data/LogData/
  • 日志路径: path.logs
path.logs: /data/LogData/logs
  • LockMemory:
bootstrap.mlockall: true
  • 本机ip: network.host, 注意两台机器配置不同, 分贝配置为对应机器的内网ip
# 第一台机器
network.host: 10.0.0.1

# 第二台机器
network.host: 10.0.0.2
  • Discovery配置: 注意这里是两台机器内网ip+9300端口, 注意这里minimum_master_nodes=2, 见最后一点防脑裂说明
discovery.zen.ping.unicast.hosts: ["10.0.0.1:9300", "10.0.0.2:9300"]
discovery.zen.minimum_master_nodes: 2
  • gatewary配置:
gateway.recover_after_nodes: 2
gateway.recover_after_time: 5m
gateway.expected_nodes: 1
  • 新增其他配置到文件末尾, 根据需求加, 这里用到了script, 同时增大了recovery的配置(要大些保证recovery速度, 但是又不能太大, 会将带宽占满)
script.engine.groovy.inline.search: on
script.engine.groovy.inline.aggs: on
indices.recovery.max_bytes_per_sec: 100mb
indices.recovery.concurrent_streams: 10

7. 设置es占用内存

修改文件bin/elasticsearch.in.sh, 将文件如下变量变更为4g(根据自身机器配置, 配置的内存最大不超过机器物理内存的75%. 两个变量值相等, 以获取最大的性能). 当然, 实际使用中4g可能远远不够, 这个值仅是个示例

ES_MIN_MEM=4g
ES_MAX_MEM=4g

修改centos配置: /etc/security/limits.conf, 以便启用memlock, 提升性能

加入, 注意, 示例中用户为es

es soft memlock unlimited
es hard memlock unlimited

确认max descriptiors

查看系统数量

  • 如果结果是unlimited, 则无需任何处理, 直接进入下一步
ulimit -n
unlimited
  • 如果结果是一个整数, 且小于204800
ulimit -n
4096

此时, 需要编辑/etc/security/limits.conf, 加入

es soft nofile 204800
es hard nofile 204800

另一种方法, 修改bin/elasticsearch, 在文件的前半部分加入下面这行代码, 保证在启动前执行即可.

ulimit -n 204800

8. 启动测试

以用户es的身份进行操作

在命令行中执行启动命令

cd /data/elasticsearch/
./bin/elasticsearch

可以看到程序启动日志

[2016-06-30 17:20:26,677][WARN ][bootstrap                ] unable to install syscall filter: seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in
[2016-06-30 17:20:27,390][INFO ][node                     ] [inner_es_node_01] version[2.3.3], pid[6415], build[218bdf1/2016-05-17T15:40:04Z]
[2016-06-30 17:20:27,390][INFO ][node                     ] [inner_es_node_01] initializing ...
[2016-06-30 17:20:27,948][INFO ][plugins                  ] [inner_es_node_01] modules [lang-groovy, reindex, lang-expression], plugins [], sites []
[2016-06-30 17:20:27,974][INFO ][env                      ] [inner_es_node_01] using [1] data paths, mounts [[/data (/dev/xvdb1)]], net usable_space [67.4gb], net total_space [98.4gb], spins? [no], types [ext3]
[2016-06-30 17:20:27,974][INFO ][env                      ] [inner_es_node_01] heap size [990.7mb], compressed ordinary object pointers [true]
[2016-06-30 17:20:29,926][INFO ][node                     ] [inner_es_node_01] initialized
[2016-06-30 17:20:29,926][INFO ][node                     ] [inner_es_node_01] starting ...
[2016-06-30 17:20:30,083][INFO ][transport                ] [inner_es_node_01] publish_address {10.0.0.1:9300}, bound_addresses {10.0.0.1:9300}
[2016-06-30 17:20:30,088][INFO ][discovery                ] [inner_es_node_01] inner_es_cluster/odmTjZRHRVaa8Zn4vTPcxA
[2016-06-30 17:21:00,091][WARN ][discovery                ] [inner_es_node_01] waited for 30s and no initial state was set by the discovery
[2016-06-30 17:21:00,099][INFO ][http                     ] [inner_es_node_01] publish_address {10.0.0.1:9200}, bound_addresses {10.0.0.1:9200}
[2016-06-30 17:21:00,099][INFO ][node                     ] [inner_es_node_01] started

等待约一分钟后, 看到如下日志代表启动成功

[2016-06-30 17:21:00,099][INFO ][node                     ] [inner_es_node_01] started

确认集群是否启动成功

curl http://10.0.0.1:9200/

{
  "name" : "inner_es_node_01",
  "cluster_name" : "inner_es_cluster",
  "version" : {
    "number" : "2.3.3",
    "build_hash" : "218bdf10790eef486ff2c41a3df5cfa32dadcfde",
    "build_timestamp" : "2016-05-17T15:40:04Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.0"
  },
  "tagline" : "You Know, for Search"
}

启动第二个节点时日志

[2016-06-30 17:32:42,494][WARN ][bootstrap                ] unable to install syscall filter: seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in
[2016-06-30 17:32:43,295][INFO ][node                     ] [inner_es_node_02] version[2.3.3], pid[10240], build[218bdf1/2016-05-17T15:40:04Z]
[2016-06-30 17:32:43,295][INFO ][node                     ] [inner_es_node_02] initializing ...
[2016-06-30 17:32:43,879][INFO ][plugins                  ] [inner_es_node_02] modules [lang-groovy, reindex, lang-expression], plugins [], sites []
[2016-06-30 17:32:43,905][INFO ][env                      ] [inner_es_node_02] using [1] data paths, mounts [[/data (/dev/xvdb1)]], net usable_space [67.4gb], net total_space [98.4gb], spins? [no], types [ext3]
[2016-06-30 17:32:43,905][INFO ][env                      ] [inner_es_node_02] heap size [990.7mb], compressed ordinary object pointers [true]
[2016-06-30 17:32:45,876][INFO ][node                     ] [inner_es_node_02] initialized
[2016-06-30 17:32:45,876][INFO ][node                     ] [inner_es_node_02] starting ...
[2016-06-30 17:32:45,978][INFO ][transport                ] [inner_es_node_02] publish_address {10.0.0.2:9300}, bound_addresses {10.0.0.2:9300}
[2016-06-30 17:32:45,983][INFO ][discovery                ] [inner_es_node_02] inner_es_cluster/VBsHeFjXQXau59hkjTuhTA
[2016-06-30 17:32:49,067][INFO ][cluster.service          ] [inner_es_node_02] detected_master {inner_es_node_01}{1BktktzhQ_y6BN-lNIKhHg}{10.0.0.1}{10.0.0.1:9300}, added {{inner_es_node_01}{1BktktzhQ_y6BN-lNIKhHg}{10.0.0.1}{10.0.0.1:9300},}, reason: zen-disco-receive(from master [{inner_es_node_01}{1BktktzhQ_y6BN-lNIKhHg}{10.0.0.1}{10.0.0.1:9300}])
[2016-06-30 17:32:49,077][INFO ][http                     ] [inner_es_node_02] publish_address {10.0.0.2:9200}, bound_addresses {10.213.136.23:9201}
[2016-06-30 17:32:49,077][INFO ][node                     ] [inner_es_node_02] started

注意, 日志中cluster.service部分, 表示发现了第一台机器的节点

[2016-06-30 17:32:49,067][INFO ][cluster.service          ] [inner_es_node_02] detected_master {inner_es_node_01}{1BktktzhQ_y6BN-lNIKhHg}{10.0.0.1}{10.0.0.1:9300}, added {{inner_es_node_01}{1BktktzhQ_y6BN-lNIKhHg}{10.0.0.1}{10.0.0.1:9300},}, reason: zen-disco-receive(from master [{inner_es_node_01}{1BktktzhQ_y6BN-lNIKhHg}{10.0.0.1}{10.0.0.1:9300}])

启动第二个节点后, 同样确认是否启动成功

curl http://10.0.0.1:9200/

{
  "name" : "inner_es_node_02",
  "cluster_name" : "inner_es_cluster",
  "version" : {
    "number" : "2.3.3",
    "build_hash" : "218bdf10790eef486ff2c41a3df5cfa32dadcfde",
    "build_timestamp" : "2016-05-17T15:40:04Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.0"
  },
  "tagline" : "You Know, for Search"
}

9. 正式启动

ctrl+c 关掉原先的进程

使用命令, 以daemon形式启动, 进程pid写入es.pid, 可以用于重启等

bin/elasticsearch -d -p es.pid
echo $?
0

查看对应进程是否启动

ps aux | grep elasticsearch

使用curl请求服务确定是否正常

curl http://10.0.0.1:9200/

或者, 更好的方式, 使用supervisord管理进程, 以下为supervisord.conf示例

[program:es]
directory=/data/LogTool/elasticsearch
command=/data/LogTool/elasticsearch/bin/elasticsearch
autostart=true
autorestart=true
stdout_logfile=/data/LogTool/elasticsearch/log/supervisord_es_out.log
stderr_logfile=/data/LogTool/elasticsearch/log/supervisord_es_err.log

10. 脑裂

单机测试开发的时候, 其实一个节点就够了. 上线, 使用两个节点, 目的是利用es本身的特性做到高可用.

但是两个节点是远远不够的. 启动后, 集群会选举一个master, 一切ok. 但是如果存在网络问题或者某个节点无响应(负载过高), 就会认为对方dead了, 然后两个节点自动选举为master, 在后续建索引的时候造成数据不一致.

两个节点防脑裂的配置, minimum_master_nodes决定了选主需要的最少节点数, N/2+1, 两个节点即2

discovery.zen.minimum_master_nodes: 2 

但是, 此时一个节点挂了, 则整个集群挂了(无法选举主节点了)

所以, 要再加一个节点, 这个节点只要保证稳定即可, 对cpu和磁盘要求不高. 这个es节点的配置同其他节点的区别node.data: false, 不存储索引数据.

# split brain prevent
node.data: false