elk+redis已是目前很多中小型公司比较青睐的开源日志搜集组合之一,主要是因为安装配置简单,社区活跃、开源免费等等.

随着公司业务的变多,日志量追渐增大,单节点的elk+redis已经满足不了业务的需求,这时候扩容或许是一件非常普遍的行为,那么如何做到自动扩容和"缩容"呢?


先来看一张简化版的扩谱图

Deploying and Scaling Logstash_第1张图片


在看完这张简化版的扩谱图之后,我们首先要明白elasticsearch cluster是如何做到Discovery的?

Deploying and Scaling Logstash_第2张图片

Elasticsearch是一个点对点的系统,节点之间直接通信并且节点之间的关系都是对等的;

2.0版本之后,为了安全考虑,默认禁用了multicast(组播)功能;但是Es还支持单播(unicast)方式

如果不涉及到Es性能优化,其实配置集群相当简单,只需要配置以下核心参数即可:

discovery.zen.ping.unicast.hosts: ["10.100.100.81", "10.100.100.82"]
# 指定Es集群中每个节点的host地址,集群中所有的配置保持一致.

discovery.zen.minimum_master_nodes: 2
# 指定master节点的个数(hosts / 2)+ 1
# 这里的hosts是指集群节点数之和.


(1) Logstash插件介绍

# logstash-shipping
logstash-input-file     # 数据源.
logstash-output-redis   # 输出到消息队列.
    
# logstash-indexing
logstash-input-redis    # 从消息队列中取数据.
logstash-output-elasticsearch   # 输入到elasticsearch 持久化存储.


(2) 为什么会有这个架构呢?

2015.10 elk+redis(v1) 上线
2016.5  elk+redis(v2) 方案已定(扩谱图)

elk_v1 上线之后 研发使用后的反应很好.
在elk_v1使用的过程中国区测试环境没有出过问题,但是美国正式环境就经常性问题不断?比如
1> redis堵了;
2> kibana界面打不开或者打开之后之后一直处于Searching状态,无法正常打开日志.
3> kibana界面崩溃了
4> es所在的机器cpu非常吃紧
主要原因是因为美国正式环境日志量比中国测试环境日志量大的多,经过heap插件查看日志量在20~40G/天

个人临时性的解决办法就是 elasticsearch集群;
于是乎就"悄悄"的在美国正式环境上部署了一套3个节点的es集群,完成后告诉大领导,大领导回复
"3台实例比较贵,日志只是偶尔看.",大领导想实现一种如果哪天日志量比较大的话我们就扩容,如果日志量小的我们就缩容
但是要保证日志尽可能不能丢失,因为我们使用的亚马逊的AWS费用比较昂贵.


(3) 如何实现动态扩容和缩容呢?


首先要明白elasticsearch集群的原理?

Deploying and Scaling Logstash_第3张图片

logstash-output-elasticsearch
    hosts 类型为 数组
    默认是本地的['127.0.0.1']
    
假如你搭建了三个节点的elasticsearch集群,并指定master和node节点,这个时候我们只需要在
output-elasticsearch插件做以下更改就可以了
hosts => ["cluster-node1", "cluster-node2", "cluster-node3"],
之后kibana连接任何一台elasticsearch就可以完整的查看所有数据.


(3.1) 基于以上原则 我们做了改变,也就是上面的扩谱图.

1. 每台要搜集日志的机器上都运行一个logstash-shipping服务
并指定input插件为日志文件或日志文件目录
而output插件就是消息队列redis、kafka、mq等

2. 集群的任何一个节点上都运行logstash-indexing、redis、elasticsearch、kibana、haproxy服务.
redis就是消息队列服务;
logstash-indexing从消息队列中取数据并写入到elasticsearch;
kibana从elasticserach查询数据;

这里有两个问题要特别说明:
1> elasticsearch如何自动建立集群的
# Pass an initial list of hosts to perform discovery when new node is started:
discovery.zen.ping.unicast.hosts:  ["127.0.0.1", "[::1]"]

# Prevent the "split brain" by configuring the majority of nodes (total number of nodes / 2 + 1):
discovery.zen.minimum_master_nodes: 2

因为以上参数的都是动态可变的,因此选择用consul-template来自动更改,然后reload服务。
关于consul-template的一些高级用法可以参考官方文档,挺详细的
 也可以私下交流 

2> haproxy是代理什么服务?
haproxy是对redis服务的代理;
看以下几个参数
logstash-output-redis host array # 解决队列的单点故障,可以同时指定多个redis实例.
logstash-input-redis host string # 只能指定一个redis实例.
如果output-redis指定的是多个redis实例,不能解决多个redis的请求、压力负载是均衡的,
如果这里指定haproxy的代理redis实例的地址,用haproxy的负载均衡策略就可以解决
redis负载不均衡的问题?


扩展总结:

核心在于集群的每个节点上都要启动logstash-indexing、redis、elasticsearch、kibana、haproxy以上四个服务,elasticsearch和haproxy代理redis等这些动态的都是通过service discovery(consul)以及consul-template刷新完成的


单节点elk+redis性能架构瓶颈及解决办法?

(1) Redis队列堵了?
logstash-output-redis   
data_type => list
logstash的output插件到Redis,通常情况下我们指定的数据类型为list;
如果你的App日志产生量在某一段时间内特别大,这个时候Redis有可能出现队列的长度几百万,这个
时候你应该从哪里入手以及解决呢?从以下两点入手:
1> 日志量不大,日志只写到Redis,但是不从Redis取,导致了只写不出.
2> 日志量很大,日志量写的很快,但是从Redis取的很慢,导致了Redis每秒钟都在不停的增加.


(2) 如何解决Redis队列堵了问题?
增加线程数、增加往Es写入的频率和一次从Redis消费的数目
flush_size 批量写入ES数量
idle_flush_time 批量写入ES频率 

(3) 如何动态监控redis队列?
要注意监控redis队列长度,如果长时间堆集说明elk出问题了,要尽快解决否则Redis服务有可能会挂; 
每2S检查一下redis中数据列表长度,100次 
# redis-cli -r 100 -i 1 llen logstash:redis

(4) 什么情况下要扩展到Es集群?
观察过很长时间Es对cpu的影响比较大,内存往往都挺正常的;
硬件配置4核cpu、8G内存;
如果你登录kibana去查看日志,然后在登录到对应es的服务器上用top看服务器的性能,如果cpu
在300%左右或更高并且kibana界面一直处于Searching状态,那么建议你换Es集群吧!
观察io也正常、内存也正常、就是cpu偶尔会很高.