ELK 维护的一些点
去年入职新公司之后, 负责维护平台的elk
这套东西是2013年搭建的, 年久失修, 所以做了个方案, 开始了批量升级
将logstash从1.3升级到2.1, 将elasticsearch从1.4.1升级到2.0
期间踩了很多坑, 搞了一个多月, 总算搞完
从纯手工落后隔三差五有人找查问题的自行车, 改成自动化最新版本新架构运维便捷上了两个月无人反馈的, 额, 小汽车:) - 集成安装包/shell脚本/fabric实现部署/升级/增删/加黑名单等等功能
每天日志量大概10G上下, 几十个采集端, 两个redis, 两个indexer, 两台es机器扛起
以下, 不那么严谨地, 记录一些遇到的问题
1. logstash升级策略
logstash1.3到2.x, 变化点还是很多的
所以, 首先第一步要去阅读官方文档, 将所有change log过一遍, 对一些关键性的东西进行了解, 比如, 干掉了哪些语法(旧的功能需要如何实现), 哪些语法有变更, 新增了哪些特性等.
然后, 将线上不同类型agent的配置文件拉下来, 先, 归类, 然后, 开始改-测-改-测-直到测试通过
bin/logstash agent -t -f test.conf
直到, 语法验证通过
现在要做的是, 验证数据正确性
从线上拉取对应日志, 启动, 查看输出
output {
stdout{
debug => true
}
}
这里需要验证的是, 1. 过滤, 该过滤的过滤了 2. 转换, 该转换的转换了 3.新增, 新增字段
注意, 测试时, 使用逻辑分支覆盖到所有配置文件中的分支即可.
然后, 可以挑一台机器, 停老的服务, 部署新的服务进行测试
建议, 部署agent的时候, 如果读的是文件, 建议配置sincedb_path
这样假设下次升级, 就可以从老的服务最后读取的位置开始了
input {
file {
path => ["/data/logs/*.log"]
sincedb_path => "/data/LogNew/logstash/sincedb/celery.sincedb"
}
}
2. elasticsearch升级的策略
elasticsearch从1.4到2.0, 部署上变化不大, 变化最大的是存储doc的schema变了……
使用原来的语法查询, 发现查不到, 因为字段名以及嵌套层级完全不一样了, 这里, 要修改查询端, 兼容新老版本的格式
{'from': 0,
'query': {'filtered': {'filter': {'bool': {'must': [{'bool': {'should': [{'term': {'type': 'app'}},
{'term': {'@type': 'app'}}]}},
{'bool': {'should': [{'term': {'log_level': u'error'}},
{'term': {'@fields.log_level': u'error'}}]}},
{'range': {'@timestamp': {'gt': 'now-5h'}}},
{'bool': {'should': [{'term': {'log_type': u'celery'}},
{'term': {'@fields.log_type': u'celery'}}]}}]}}}},
'size': 100,
'sort': [{'@timestamp': 'desc'}]}
另一个是, 取到数据进行解析的时候, 发现解析逻辑跪了, 没办法, 返回的json也完全变了, 这里, 要修改解析逻辑, 兼容新老版本格式
for hit in log_hits:
try:
source = hit.get('_source')
if '@fields' in source:
log = source.get('@fields', {})
else:
log = source
为了让用户感觉不到集群升级, 首先要做的就是上面两个变更
然后, 搭建新的集群, 最好找新的机器搭建(我在新的机器搭完才发现妈蛋硬盘才100G, 坑死, 无奈在老集群上搭新的集群, 硬盘1t)
ready, 所有节点起好维护好, 然后, 改indexer, 将同一份日志灌到两个集群
output {
elasticsearch {
hosts => ["10.1.1.1:9100", "10.1.1.2:9100"]
}
elasticsearch {
hosts => ["10.1.1.1:9110", "10.1.1.2:9110"]
}
}
简单测试下, 没问题就放着甭管了, 等数据攒齐了….
数据够了, 就, 停indexer, 停老集群, 停新集群, 改新集群端口, 起来….同时去掉indexer只输出到新的集群, 起来……测试, 切换完毕, 收工吧.
优化点: 集成安装包和supervisord
额, logstash和es, 如果要配置节点, 其实还是挺蛋疼的
要做的, 就是, logstash+不同类型配置文件+运维脚本, 达成一个包
然后, 如果要部署一台机器, 扔上去一键执行安装, 测试, 启动即可
例如, 运维脚本 logstashd.sh
#!/bin/bash
BASEDIR=$(dirname $0)
cd $BASEDIR
CURRENT_DIR=`pwd`
function help_msg() {
echo "===================== usage ====================="
echo "./logstashd.sh - enter command line"
echo "./logstashd.sh status - show all configured process"
echo "./logstashd.sh start ${name} - start program"
echo "./logstashd.sh stop ${name} - stop program"
echo "./logstashd.sh restart ${name} - restart program"
echo "./logstashd.sh reread && ./logstashd.sh update - update config and just update the modified programs"
echo "./logstashd.sh reload - reload config files and restart all programs(stopeed not included)"
echo "================================================="
echo ""
}
if [ "${1}" = "-h" -o "${1}" = "--help" ]
then
help_msg
exit 0
fi
SUPERVISORCTL='/data/LogNew/python27/bin/supervisorctl'
CONFIG_FILE_PATH="${CURRENT_DIR}/conf/supervisord.conf"
$SUPERVISORCTL -c $CONFIG_FILE_PATH $@
使用
./logstashd.sh
===================== usage =====================
./logstashd.sh - enter command line
./logstashd.sh status - show all configured process
./logstashd.sh start - start program
./logstashd.sh stop - stop program
./logstashd.sh restart - restart program
./logstashd.sh reread && ./logstashd.sh update - update config and just update the modified programs
./logstashd.sh reload - reload config files and restart all programs(stopeed not included)
=================================================
111_indexer RUNNING pid 27058, uptime 1:25:10
indexer RUNNING pid 24731, uptime 1:31:29
supervisor> restart indexer
这里, 我引入了stackless python (独立), 然后装pip/supervisord, 使用supervisord对logstash/es进程进行管理
使用supervisord管理进程, 有个注意点
默认supervisord相关的文件在
/tmp/supervisor*
而线上, 存在tmp被删/清理了情况, 导致要进行进程启停操作才发现,妈蛋找不到
处理方式 => 放到集成安装包的run目录下
注意点: logstash存在两个output时, 必须要保证二者的可用性
logstash indexer, 分别转发数据到两个不同的output
output {
elasticsearch {
hosts => ["10.1.1.1:8080", "10.1.1.2:8080"]
}
redis {
host => "10.1.1.3"
port => 6379
password => "7oEsjqUNoTdgE4"
data_type => "list"
key => "log_queue"
db => 0
batch => true
}
}
此时, 若是redis挂了, 则日志也不会刷到es中, 所以, 需要同时保证所有output的可用性
对于redis, 可以进行进程监控, 发现挂了的话, 告警并同时重启(可以crontab一分钟检查一次)
优化点: ELK增加agent_ip字段
需求: 在实际使用中, 有时候需要反向根据查询结果, 获知日志的来源机器
处理:
1.先获取ip
GetLanIp () {
## get associated LAN ip address
## usage: GetLanIp
/sbin/ifconfig | awk '
/eth/{
getline;
if (/inet addr:(172|10|192)\./) {
gsub(".*addr:| *Bcast.*","");
print $0;
exit;
}
}'
return 0
}
2.放入环境变量
ETH1_IP=10.1.1.1
3.修改logstash配置
注意, 这里是logstash2.x的语法
environment {
add_metadata_from_env => ["agent_ip", "ETH1_IP"]
add_field => {"agent_ip" => "%{[@metadata][agent_ip]}" }
}
问题: elk的utc问题
elasticsearch内部使用的是utc, 存储为long (milliseconds since the epoch) e.g. timestamp=1420070400000
可以看下 es 时间处理
logstash 接受了这种设定, 往es传数据的时候, 根据UTC, 每天00:00新建一个index
kibana也接受这种设定, 在查询和展示时根据用户的时区进行处理
问题描述
这导致了, 对于东八区, 2015-11-6日, 8点之前, 只有logstash-2015.11.05
这个index, 到8点的时候, 创建新的index logstash-2015.11.06
, 即, 对于我们这个时区的人来说, 一天的数据存在了两个index里面
同类问题 Elasticsearch doesn’t care about timezone and creates indexes with UTC
修正方案1: 修改logstash的数据时间
logstash团队对于支持localtime的问题, 不予修复 讨论, 但是可以自行去修改logstash的代码
当然, 可以修改每个logstash indexer的时间, 但是会带来问题 问题: 1. logstash都要修改getLocalTime
2.相对时间搜索 3. kibana等相关插件/组件要修正
运维/升级和后续使用上会有很多地雷
修正方案2: 不修正
接受这种设定, 学习kibana, 类似自行确定要搜索的index
对于00:00-08:00
的, 程序处理使用昨天的indexer
所以, 更好的方式是, 不修正……原来不变的才是最好的
rolling restart
当存在配置变更时, 需要重启es集群, 不可能全部重启的, 这样会导致服务不可用….
所以, 要一个个重启
先执行
curl -XPUT 'http://localhost:9200/_cluster/settings' -d '
{
"transient" : {
"cluster.routing.allocation.enable" : "none"
}
}'
然后, shutdown, 改配置, start
then : 一定要记得执行, 否则不会执行recovery…..会一直等着
curl -XPUT 'http://localhost:9200/_cluster/settings' -d '
{
"transient" : {
"cluster.routing.allocation.enable" : "all"
}
}'
logstash文本解析配置grok语法
一个线上的工具, https://grokdebug.herokuapp.com/
挺好用的, 但是有时候变更频繁相应有些缓慢
暂时没有找到命令行工具
坑: GROK语法
上线后发现, 尼玛, 部分应用日志没有被采集
定位发现, 原来在grok
的解析中使用了WORD
而 WORD
: 不支持连字符和下划线
跪了, 需要自定义LOGFILENAME [a-z\-A-Z0-9_\.]+
放到pattern中
然后, 搜索的时候, 尼玛, 也搜不到….语法要做处理, 使用raw
, es建索引的时候自动拆掉了导致搜索不到
{'term': {'app_name.raw': 'nms-t'}}
做一些exclude
有时候需要做一些exclude, 去除比必要采集和监控的日志(进入采集逻辑纯粹是浪费cpu和内存)
例如, 目录树, 不要监控celery.log
logs
├── a
│ ├── a.log
│ ├── b.log
│ └── celery.log
└── b
├── c.log
└── d.log
排除部分文件
file {
path => ["/data/logs/*/*.log"]
exclude => ["celery.log", ]
sincedb_path => "/data/LogNew/logstash/sincedb/django.sincedb"
}
一些相关用到的命令
- 查看plugin版本
https://www.elastic.co/guide/en/logstash/current/working-with-plugins.html
bin/plugin list --verbose
- create empty index
curl -XPUT 'http://localhost:9100/logstash-2015.12.15/'
- 查看健康度
curl 'http://localhost:9100/_cluster/health?pretty=true'
- 查看indices
#!/bin/bash
curl 'http://localhost:9100/_cat/indices?v' | sort -k 3
删除30天前crontab脚本
#!/bin/bash
now=`date +%Y%m%d`
echo $now
days_30_before=`date -d "$now 31 days ago" +%Y.%m.%d`
echo $days_30_before
echo "http://10.1.1.1:9100/logstash-$days_30_before"
curl -XDELETE "http://10.1.1.1:9100/logstash-$days_30_before" > /dev/null 2>&1
尚未处理
logstash2.1 muline codec, 配置多个数据来源, 存在串的情况, 生产中大数据量有, 小规模没有复现….
好了, 先这些, 还有一些窝在某些目录下, 后续整理好了发
wklken
2016-02-16