基于ELK系统,搭建支持TB级别日志平台
一. 背景
日志作为服务的重要数据,可以更好的帮助业务查看服务状态,查找问题和数据恢复,随着业务服务的逐渐增加,业务机器在不断增加,业务间调用关系也随之更加复杂,所以如何能将各机器的日志完全、快速的收集,更友好的聚合可视化展示则成为了服务化框架的重要环节。
旧有的方案是定时将该机器的日志进行转发到几台日志平台中,在业务方查找日志时,登陆机器进行查看,这样成本很低,但并不高效和友好。业界比较流行的方式是通过几个组件(ELK)来搭建日志平台。
E:ElasticSearch 一个分布式实时文档存储,搜索引擎
L:Logstash 一个开源数据收集引擎,能够动态地采集、转换和传输数据,不受格式或复杂度的影响
K:Kibana 是一种开源数据可视化和挖掘工具。
filebeat: 轻量级的数据收集程序
kafka: 一种开源的消息系统
二.数据与机器配置
数据:保存5天数据,一共大约50T+ 的数据量 千级别的索引和分片
机器配置
冷热数据分离架构
冷 20 * 8c * 16g * 3T
热:本地SSD 20 * 16c * 64g * 1.7 T
(可以根据自己需要进行调整)
三. 设计方案
1.设计思路
1.1 利用filebeat 的轻量性,将filebeat部署在业务机器上,这样最小化日志采集对业务机器资源的占用
1.2 由于filebeat是实时采集,需要通过一个组件来接收这部分数据,这个组件要有高吞吐,高可用,而且这部分日志数据要做到可复用(复用的好处多多,后续会说这里的好处),这里自然想到业界比较成熟的消息引擎系统kafka,引入这个中间层除了上面的好处优势之外,还能对系统起到缓冲(“削峰填谷”)的作用,防止突然大数据量压垮后续集群
1.3 Logstash :从kafka 中读的组件,也是elastic 公司的产品,可以很好做到从kafka 到 ElasticSearch 转换。
1.4 ElasticSearch,整个日志搜索的核心部分。数据实体保存的组件。
1.5 保存在ElasticSearch 中的数据通过kibana进行查看,当然kibana 比较完善,可以做一些监控,索引管理,聚合分析,图表展示等很多功能。
1.6 为了方便业务部门使用,减少接入成本,所以接入公司的发布平台管理以及利用Jenkins 做到自动部署。(这里不做重点说明)
2.系统结构图
各个组件的部署过程网上成熟方案很多,这里不在赘述
3.实践及优化
按照上面的结构图,搭建好一套日志平台之后,恭喜你完成了基础设施的搭建,接下来开始一些细节配置
3.1.索引名设计
索引是针对ElasticSearch 中存储的概念,区别于Mongo等组件中索引的概念,可以把这个索引看作mongo中的一个表。针对索引名的设计是 项目名+标示信息+日期(YY.MM.DD)
标示信息是给业务创建索引留下定制空间,比较建议根据filebeat 采集的文件类型不同,填写这个字段,例如 业务将trace日志进行单独打印一个文件中,并且想单独查看,可以配置标示信息为“trace”或者“info”来将数据存在不同的ES索引中。
这时两个索引名:
xxx-trace-2020.03.27
xxx-info-2020.03.27
在根源filebeat 采集时需要将这些跟项目有关信息带上
3.2.filebeat 配置
filebeat.yml 文件
filebeat.inputs:
- type: log
paths:
- /data/server/xngo/xxx/log/info.log
fields:
project: xxx
type: info
tail_files: true
output.kafka:
hosts: ["xxx-kafka-1:9092","xxx-kafka-2:9092","xxx-kafka-3:9092"]
topic: "search-log-4"
max_message_bytes: 10000000
这里常规设置不做解释,只针对日志中心定制配置进行解释
paths 采集日志文件的路径
fields.project 项目名称
fields.type 上面提到的标示信息
tail_files 只采集新日志,这里是为了防止刚接入过程中突然向日志中心写入大量留存日志
输出设置:output.kafka
hosts: kafka 的地址
topic: 索引写入到kafka 的主题名
max_message_bytes:kafka 默认单条消息为10M,当单条日志大于10M时会报错,需要设置kafka信息,并且在filebeat 中也进行设置(单条日志10M?这信息量,有意义吗?)
3.3.kafka 配置
kafka 没有过多定制化配置,多个topic而不是单topic 接收全部日志有几个好处,1 可以提高集群的吞吐量,2 减少服务之间日志的相互影响。
将max_message_bytes 设置超过10M。
由于是日志流 近实时处理,可以将持久化时间设置3天左右少一点,节省kafka 资源
3.4.logstash 配置
logstash.conf
logstash 是pipeline式处理方式,从数据源(input)-->过滤器(filter)-->数据终点(output)
input {
kafka {
bootstrap_servers=> "xxx-kafka-1:9092,xxx-kafka-2:9092,xxx-kafka-3:9092"
topics => ["search-log-0","search-log-1","search-log-2","search-log-3","search-log-4","search-log-5"]
group_id => "logstash-es"
codec => "json"
consumer_threads => 5
}
}
filter {
ruby {
code => "event.set('index_day', event.timestamp.time.localtime.strftime('%Y.%m.%d'))"
}
}
output {
elasticsearch {
hosts => ["http://xx.xx.xx.xx:9200", "http://xx.xx.xx.xx:9200","http://xx.xx.xx.xx:9200"]
index => "%{[fields][project]}-%{[fields][type]}-%{index_day}"
user => "***"
password => "***"
}
}
还记得在filebeat 中设置的kafka地址吗?这里同样input配置,只不过作为消费者,需要一个group_id消费组ID
filter.ruby.code 是获得当前时间
output.elasticsearch.hosts 设置ElasticSearch 集群master 节点
index 拼接索引名,字段名就是filebeat 中的配置名
user和password 针对带有安全验证🔐的ES集群的账号和密码(暂时可以不需要关心)
另外:logstash.yml
pipeline.batch.size: 6000
设置单个工作线程在执行过滤器和输出之前收集的最大事件数
通俗讲就是我攒够一定的数据之后在进行输出,这里是可以减少ES的网络开销进行的优化。
3.5.ElasticSearch 配置
elasticsearch.yml
cluster.name: es-log-center
node.name: log-center-master-1
node.master: true
node.data: false
node.attr.node_type: hot
path.data: /data/elastic_data
path.logs: /data/logs/elastic
thread_pool.write.queue_size: 3000
thread_pool.search.queue_size: 3000
thread_pool.write.size: 9
network.host: xxx.xxx.xxx.xxx
http.port: 9200
discovery.seed_hosts: ["log-center-master-1","log-center-master-2","log-center-master-3"]
cluster.initial_master_nodes: ["log-center-master-1","log-center-master-2","log-center-master-3"]
首先科普一下ES的集群基础知识
cluster.name设置集群的名字,一个集群中有很多的节点组成,而每种节点都可以扮演单一或多种角色
master 节点角色可以创建索引,保存每个索引的数据分片路由信息,每个索引的配置信息,集群的配置信息等,而master 不参与实际的磁盘IO工作,所以相应master节点机器并不要求高配置,但要求冗余,一般设置三台master节点机器保证高可用。(两台会出现集群选举的脑裂问题)
data 节点角色用来保存数据,实际进行磁盘IO的节点,所以其要求更高CPU,高内存,高IO磁盘。进行集群横向扩容时一般扩的就是数据节点。还有其他角色比如Client、Ingest这里不在赘述,感兴趣可以自行查看。
node.name 节点在集群中的名字
node.master、node.data 设置节点是否是 master 节点,和数据节点,一个节点即可以是master也可以是data节点,使用实际建议角色单独部署,区分开。只有是node.master 节点才能被选举成master 节点。
node.attr.node_type 可以制定节点的类型,在数据写入时,可以制定将索引分配在特定类型的节点中,这是hot-warm 架构的关键,后续优化介绍。
path.data、path.logs数据保存位置和 日志打印位置。
对于thread_pool 的设置都是优化点,在数据写入或者搜索的过程可以理解成一个个写入任务和搜索任务,线程去执行这些任务,所以需要thread_pool去保存这些任务,ES中将各种任务放在不同的thread_pool 去处理,当请求或写入的任务过多会进行丢弃,这就会造成丢数据的现象。
write.queue_size、search.queue_size设置线程池的最大任务数。
thread_pool.write.size: 执行线程的数量,并且它最大只能设置成(CPU核数+1)
当logstash 或者写入ES的程序报错:
retrying failed action with response code: 429
说明已经开始丢数据,需要横向、纵向扩容,或者调高这个设置的值。
network.host 一般填写本机IP
http.port 对外提供服务的端口,一般都填写9200
另一个默认端口很重要是9300,这个端口用于集群内部的数据传输,比如数据迁移,数据恢复等等
discovery.seed_hosts、cluster.initial_master_nodes 一般填写几个master节点信息,用来初始化master节点,和选举master时用
3.6.ElasticSearch 更多实践细节
ES知识扩展:存储方式
每一个索引的数据是以分片的方式进行存储,每一个分片是数据的最小运行单元,它不仅仅是一块物理地址,实际每一个分片单独就是一个搜索引擎。索引通过主分片和副本分片来提高吞吐量和保证高可用性。例如 某个索引有50G数据,保存是每个分片5G数据,需要一个副本。实际这个索引就需要10个主分片+10个副本分片来保存数据,占用100G磁盘
ES知识扩展:数据字段
索引的每个字段根据类型不同,存储方式不同,当类型为text类型时,ES会对这个字段进行分词,创建倒排索引等耗性能操作,所以如果不需要可以将这些字段变成keyword字段,可以整体检索,避免进行分词处理,提高性能。
(1).利用索引模版,做定制化处理
设置索引模版,在索引模版中规定好各个字段的含义,每个索引的分片数,副本数,这样大数据索引不会因为分片数少而查询效率低下,小数据索引不会因为分片数过多导致性能浪费现象。
ES知识扩展:存储流程
过程解释:
首先写入Index Buffer, 同时写入Transaction log
Transaction log 会进行落盘,保证断电等数据不丢失
当Index Buffer空间满或者超过设定时间时,进行Refresh 写入Segment,清空Index Buffer,写入Segment就可以被检索到
默认30 min或者Transaction log 满时进行flush 操作 :调用refresh ->将Segment写入磁盘-> 清空Transaction log
merge: 写入磁盘上Segment较多时,需要定期进行合并,目的是减少Segment和删除已删除的文档
(2).增大Index Buffer 进行Refresh时间间隔
这个的优化是相对的,当增大Refresh时间的时候,相对牺牲的是数据检索的实时性(所以这个设置要考虑清楚)
"refresh_interval": "60s" 默认1s
(3).hot-warm 架构
由于分片的维护都是消耗性能的,而日志场景中,当天的日志索引都是高IO操作,而隔天的索引IO相对较低,所以可以考虑在高IO场景应用更好的机器,低IO时用一般的机器来处理,这样降低机器成本,这就是hot-warm 的场景。通过给节点标记,实现数据定向写入。
在ES启动时使用node.attr.node_type: hot 或者node.attr.node_type: warm 标示节点(👆上面配置文件时提到过)
当新创建的索引时设置 "index.routing.allocation.require.node_type":"hot",等过一天或者两天后,将索引的这个值设置成“warm”,ES就会自动将其进行数据迁移,而不影响检索的使用。
四.总结
本文从日志平台的各个组件角度出发,讲述各个组件的作用,为什么选用这些组件,并且渗透了一些ES的知识。一些配置是在实践过程中解决过具体问题,提高集群性能的配置。各个公司或者场景不完全相同,并不能一概而论。
搭建日志平台更像是基础设施的搭建,规则的设置,后续会针对日志进行复用,链路监控,链路查看等。
后续的日志中心会从性能,数据量做持续优化,会对日志进行精简处理,满足更复杂的查询场景,剥离无用的日志数据