因项目部署在多台服务器上,如果出现Bug需要查询日志的时候,日志非常难查询。所以采用Logstash来收集日志,通过Kibana页面将日志展示出来。一开始偷懒,使用Docker安装了个单机版的ELK,后面日志体量上来后,发现只要增加条件查询,ELK就贼容易崩溃!
后面通过排查发现,增加条件检索后ElasticSearch性能降的很快,内存消耗大大增加。之前通过Docker安装ELK只是简单玩玩,索引也只根据日期创建了个索引,加上一开始CPU、内存分配都很小,搜索量上来后,ES崩溃也就很正常了! 回归正题,此次更新ELK环境,准备了三台服务器,准备将ES部署为集群模式,一台Mester,两台Node Data,然后将Kibana、Logstash安装在Mester机器上。部署方式采用二进制部署方式,版本为8.2.3,官网也支持K8s和Docker部署。创建文件夹(在home下面创建elk文件夹,方便查找安装包及解压文件)
# 创建目录
mkdir elk
# 这里本该为新用户赋予目录权限,我为了省事,直接把该目录下权限放开给所有用户这个可以自行考虑
chmod -R 777 elk
创建用户,并设置初始密码(基于安全考虑,es默认不让root用户启动)
# 创建用户,将你自己的用户名替换’用户名‘,用户名是不需要引号包裹的
useradd ’用户名‘
# 设置密码,执行后会让输入密码,并二次确认,确认成功后即设置成功,可以用新用户登陆服务器
passwd '用户名'
调整进程最大打开文件数量
vim /etc/security/limits.conf
# 直接末尾添加限制
es soft nofile 65536
es hard nofile 65536
调整进程最大虚拟内存区域数量及关闭防火墙
echo vm.max_map_count=262144>> /etc/sysctl.conf
sysctl -p
# 关闭防火墙
systemctl stop firewalld
# 设置重启后防火墙布重启
systemctl disable firewalld
添加服务器名解析,此处将你自己ip替换成【’服务器1ip‘】即可
cat > /etc/hosts << EOF
'服务器1ip' es-node-01
'服务器2ip' es-node-02
'服务器3ip' es-node-03
EOF
安装配置ES
在配置ES前,得先切换前面创建好的用户进去/home/elk目录下,创建es/data,es/logs目录,用于保存数据及保存日志。ES的集群名称配置一样es-cluster,三台ES节点的node.name分别为 es-node-01、es-node-02、es-node-03,network.host配置为各自本机的IP地址。
cd /home/elk
# 下载Es压缩包
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.2.3-linux-x86_64.tar.gz
# 三台服务器都准备好安装包,进行解压
tar -xvf elasticsearch-8.2.3-linux-x86_64.tar.gz
cd elasticsearch-8.2.3
# 编写配置文件
vi config/elasticsearch.yml
# 以下为配置信息,按照各自的数据替换
cluster.name: es-cluster
node.name: es-node-01
node.attr.rack: r1
path.data: /home/elk/es/data
path.logs: /home/elk/es/logs
network.host: ‘服务器ip’
discovery.seed_hosts: ["ip1", "ip2", "ip3"]
cluster.initial_master_nodes: ["ip1", "ip2", "ip3"]
xpack.security.enabled: false
xpack.security.transport.ssl.enabled: false
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,X-Requested-With,Content-Type,Content-Length
启动ES服务
# 依次启动三台服务器的ES服务
./bin/elasticsearch -d
访问3台服务器9200端口,如果都看到如下信息则代表ES启动成功
再次查看集群的健康状态, http://10.17.16.30:9200/_cat/health
上图具体含义可点击跳转其他文章查看
到这,可以说已经是已经成功安装好了ES,但是安装过程中还是遇到了一些问题,在此简单说下问题和解决方法
main ERROR RollingFileManager,具体报错信息如下
2022-07-05 10:22:07,358 main ERROR RollingFileManager (/home/elk/elasticsearch-8.2.3/logs/elasticsearch_server.json) java.io.FileNotFoundException: /home/elk/elasticsearch-8.2.3/logs/elasticsearch_server.json (Permission denied) java.io.FileNotFoundException: /home/elk/elasticsearch-8.2.3/logs/elasticsearch_server.json (Permission denied)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.(FileOutputStream.java:213)
at java.io.FileOutputStream.(FileOutputStream.java:133)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:746)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:716)
at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:114)
at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:100)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.getFileManager(RollingFileManager.java:217)
at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:146)
at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:62)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:122)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1120)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1045)
at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1037)
at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:651)
at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:247)
at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:293)
at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:626)
at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:302)
at org.elasticsearch.common.logging.LogConfigurator.configure(LogConfigurator.java:222)
at org.elasticsearch.common.logging.LogConfigurator.configure(LogConfigurator.java:118)
at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:369)
at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:166)
at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:157)
at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:77)
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:112)
at org.elasticsearch.cli.Command.main(Command.java:77)
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsear:ch.java:122)
at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:80)
这些错误都是因为之前的Permission denied引起的。
这是因为当前启用用户没有权限写入这些文件。切换到root用户重新赋权限就OK了。但是按照我前面将整个elk目录都放开的话,这个问题应该不会出现了
Exception in thread “main“ org.elasticsearch.bootstrap.BootstrapException:… 具体错误信息如下
Exception in thread “main“ org.elasticsearch.bootstrap.BootstrapException:java.nio.file.AccessDeniedException:/home/elk/elasticsearch-8.2.3/config/elasticsearch.keystore Likely root casue:java.nio.file.AccessDeniedException:/home/elk/elasticsearch-8.2.3/config/elasticsearch.keystore
at sun.nio.fs.UnixExcption.translateToIOException(UnixException.java:84)
at sun.nio.fs.UnixExcption.rethrowAsIOException(UnixException.java:102)
at sun.nio.fs.UnixExcption.rethrowAsIOException(UnixException.java:107)
at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
at java.nio.file.Files.newByteChannel(Files.java:361)
at java.nio.file.Files.newByteChannel(Files.java:407)
根据报错信息提示,是elasticsearch.keystore文件的权限问题,我们进入该文件所属目录查看文件权限,果不其然,这个文件权限属于root,不是新建用户的权限,解决方法是直接删除elasticsearch.keystore,切换回新用户启动es后该文件会自动创建。这个问题是使用root用户启动的延续问题。
目前我遇到的,大多是没切换用户导致的一系列权限问题,运气比较好,其他问题倒是也出现。
kibana的版本要与ES的版本保持一致,如果没保持一致会出现kibana连接不上ES等问题,使用新用户登陆服务器并进入/home/elk目录下
# kibana下载
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.2.3-linux-x86_64.tar.gz
# 解压文件
tar -xvf kibana-8.2.3-linux-x86_64.tar.gz
# 进入解压目录
cd kibana-8.2.3
# 修改配置
vim config/kibana.yml
# 配置信息
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://‘ES服务器ip’:9200/"]
i18n.locale: "zh-CN"
# 启动kibana服务,如需后台启动,前面加nuhup,尾部加&
nohup ./bin/kibana > logs/kibana.log 2>&1 &
启动后访问5601端口,如出现下图页面则启动成功
日志收集除了Logstash之外,还可以选择Filebeat,区别在于Logstash是通过jvm写的,功能比较多,具有filter功能,能过滤日志,资源消耗比较大;Filebeat是golang写的,比较轻量级,占用资源更少;Logstash是同步收集日志上报,Filebeat是收集日志后通过消息队列再通过logstash去获取。这里是直接使用Logstash
# 下载压缩包
wget https://artifacts.elastic.co/downloads/logstash/logstash-8.2.0-linux-x86_64.tar.gz
# 解压
tar -xvf logstash-8.2.0-linux-x86_64.tar.gz
# 修改配置文件
cd logstash-8.2.0
vim config/logstash.conf
# 配置信息
input {
tcp {
port => 5044
}
}
output {
elasticsearch {
hosts => ["http://ip1:9200","http://ip2:9200","http://ip3:9200"]
index => "%{app_id}"
}
}
# 检查配置文件语法是否正确
bin/logstash -f config/logstash.conf --config.test_and_exit
# 启动服务,如需后台启动,前面加nohup,尾部加&
nohup bin/logstash -f config/logstash.conf --config.reload.automatic &
到这,ELK环境配置基本就结束了,剩下来就是将ELK集成进项目中,实现日志收集上报,然后通过页面可以查看到上报的日志。
项目中引入依赖
net.logstash.logback
logstash-logback-encoder
5.2
日志配置文件
‘上报地址’
{‘额外参数,用于区分服务器或端’}
UTC
{
"severity": "%level",
"service": "${springAppName:-}",
"trace": "%X{X-B3-TraceId:-}",
"span": "%X{X-B3-SpanId:-}",
"exportable": "%X{X-Span-Export:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"rest": "%message"
}
在我将ELK配置完成并集成进项目中后,我发现日志无法收集,一开始认为是kibana没有连接上ES,但是我打开页面一切显示正常,后面发现是在Logstash配置文件中,imput下使用的beats而不是tcp,beats我猜可能是给Filebeat模式使用,具体未继续深究。
如上述日志配置文件中,在customFields标签中定了appName的自定义字段,然后到kibana页面中,无论重新自定义字段或者读取日志都没办法获取到该属性,更别说通过该数据检索数据了,如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLmJrVaj-1668839752713)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c4ab7b8eb16b46f5901c74878218afe2~tplv-k3u1fbpfcp-watermark.image?)]
后通过查看资料和对比之前通过docker中logstash的配置文件发现在input中可以指定输出类型,不指定的话默认是字符串,所以才没办法读取到自定义字段,json-lines是根据每行的日志输入为json;还有一个属性是json,应该是整个输出为json,这个没去使用,具体就不太清楚了。
input {
tcp {
port => 5044
codec => json_lines
}
}
发现不管是ES也好还是Kibana、Logtash也好,通过bin目录下启动还算可以,但是要停止服务,就得自己通过ps -ef去查询进程了,然后杀死进程,难道就没有一个简单点的方式吗?别说,还真有,如下,在bin的上层目录建立两个sh脚本文件,一个里面存放启动命令;一个存放服务停止命令。以Logstash的停止命令为例,如下:
pid=`ps -ef | grep logstash | grep -v grep | awk '{print $2}'`
if [ -n "${pid}" ];then
echo "Will shutdown logstash: ${pid}"
kill -9 ${pid}
fi
这样就可以通过执行sh文件来停止服务了,是不是简单多了!
初始服务器的内存分配是4G,启动ES后发现内存消耗达到了50%,峰值甚至到了70%多,在FinalShell(Mac远程连接服务器工具,好用,推介)中发现后猜测是不是内存分配的太小了,于是乎将内存加大至8G,心想这问题应该是解决了吧。哦吼,就算内存加大了一倍,ES启动后内存消耗的比例丝毫没降,一个java的进程(ES的进程)消耗了4.4G的内存,算了先用着,有问题或者有时间再去研究研究
参考文章:https://blog.csdn.net/www_xuhss_com/article/details/125494770