日志收集系统系列(一)之系统背景及架构
项目地址:https://gitee.com/zhangyafeii/go-log-collect
一、日志收集系统背景
1 项目背景
-
a. 每个系统都有日志,当系统出现问题时,需要通过日志解决问题
-
b. 当系统机器比较少时,登陆到服务器上查看即可满足
-
c. 当系统机器规模巨大,登陆到机器上查看几乎不现实
2 解决方案
-
a. 把机器上的日志实时收集,统一的存储到中心系统
-
b. 然后再对这些日志建立索引,通过搜索即可以找到对应日志
-
c. 通过提供界面友好的web界面,通过web即可以完成日志搜索
3 遇到的问题
-
a. 实时日志量非常大,每天几十亿条
-
b. 日志准实时收集,延迟控制在分钟级别
-
c. 能够水平可扩展
4 业界方案ELK
5 ELK方案问题
-
a. 运维成本高,每增加一个日志收集,都需要手动修改配置
-
b. 监控缺失,无法准确获取logstash的状态
-
c. 无法做定制化开发以及维护
二、日志收集系统架构
6 日志收集系统设计
7 各组件介绍
-
-
Kafka,高吞吐量的分布式队列,linkin开发,apache顶级开源项目
-
ES,elasticsearch,开源的搜索引擎,提供基于http restful的web接口
-
Kibaa:开源的ES数据分析和可视化工具
-
Hadoop,分布式计算框架,能够对大量数据进行分布式处理的平台
-
-
-
后端服务组件开发
-
etcd的使用
-
Kafka和zookeeper的使用
-
9 消息队列的通信模型
9.1 点对点模式(queue)
消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。一条消息被消费以后,queue中就没有了,不存在重复消费。
9.2 发布/订阅(topic)
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点不同,发布到topic的消息会被所有订阅者消费(类似于关注了微信公众号的人都能收到推送的文章)。
补充:发布订阅模式下,当发布者消息量很大时,显然单个订阅者的处理能力是不足的。实际上现实场景中是多个订阅者节点组成一个订阅组负载均衡消费topic消息即分组订阅,这样订阅者很容易实现消费能力线性扩展。可以看成是一个topic下有多个Queue,每个Queue是点对点的方式,Queue之间是发布订阅方式。
10 Kafka
10.1 介绍
Apache Kafka由著名职业社交公司LinkedLn开发,最初是被设计用来解决Linkedln公司内部海量日志传输问题。kafka使用Scala语言编写,于2011年开源并进入Apache孵化器,2012年10月正式毕业,现在为Apache顶级项目。
Kafka是一个分布式数据流平台,可以运行在单台服务器上,也可以在多台服务器上部署形成集群。它提供了发布和订阅功能,使用者可以发送数据到Kafka中,也可以从Kafka中读取数据(以便进行后续的处理)。Kafka具有高吞吐、低延迟、高容错等特点。设计内在就是分布式的,分区的和可复制的提交日志服务。
10.2 架构组件
-
Producer: Producer即生产者,消息的产生着,是消息的入口,用来向Kafka中发送数据(record)。
-
kafka cluster: kafka集群,一台或多台服务器组成
-
Broker:Broker是指部署了kafka实例的服务器节点,每个服务器上有一个或多个kafka的实例,我们姑且恩威每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等。
-
Topic:消息的主题,可以理解为消息的分类,用来区分不同类型信息的主题。kafka的数据就保存在topi。在每个broker上都可以创建多个topic。实际应用中通常是一个业务线建一个topic。比如应用程序A订阅了主题t1,应用程序B订阅了主题t2而没有订阅t1,那么发送到主题t1中的数据将只能被应用程序A读到,而不会被应用程序B读到。
-
Partition:Topic的分区,每个topic可以有一个或多个partition(分区),分区的作用是负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹。Kafka使用分区支持物理上的并发写入和读取,从而大大提高了吞吐量。
-
Replication: 每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一分区也只能存放一个副本(包括自己)
-
-
Record 消息 实际写入Kafka中并可以被读取的消息记录。每个record包含了key、value和timestamp。
-
Consumer:消费者,即消息的消费方,是消息的出口,用来读取Kafka中的数据(record)。
-
Consumer Group:消费组,一个消费者组可以包含一个或多个消费者。在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,使用多分区+多消费者方式可以极大提高数据下载的处理速度。
-
-
Segment:消息的聚合单位,包括一定的消息数量。
10.3 工作流程
我们看上面的架构图中,producer就是生产者,是数据的入口。Producer在写入数据的时候永远的找leader,不会直接将数据写入follower!那leader怎么找呢?写入的流程又是什么样的呢?看下图。
-
生产者从kafka集群中获取分区Leader信息
-
生产者将消息发送给leader
-
leader将消息写入本地磁盘
-
follower从leader拉取消息数据
-
follower将消息写入本地磁盘后向leader发送ACK
-
leader收到所有的follower的ACK后向生产者发送ACK
10.4 选择partition的原则
在kafka中,如果某个topic有多个partion,producer又怎么知道该将数据发往哪个partition呢?kafka中与几个原则:
-
partition在写入的时候可以指定需要写入的partition,如果有指定,则写入对应的partition。
-
如果没有指定partition,但是设置了数据的key,则会根据key的值hash出一个partition。
-
如果既没指定partition,有没有设置key,则会采用轮询方式,即每次取一小段时间的数据写入某个partiton,下一小段的时间写入下一个partition。
10.5 ACK应答机制
producer在想kafka写入消息的时候,可以设置参数来确定是否确认kafka接收到数据,这个参数可设置为0、1、all。
-
0代表producer往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。
-
1代表producer往集群发送数据只要leader应答就可以发送下一条,只确保leader发送成功。
-
all代表producer往集群发送数据需要所有的follower都完成从leader的同步才会发送下一条,确保leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。
最后要注意的是,如果往不存在的topic写数据,能不能写入成功呢?kafka会自动创建topic,分区和副本的数量根据默认配置都是1。
10.6 Topic和数据日志
topic是同一类别的消息记录(record)的集合。在Kafka中,一个主题通常有多个订阅者。对于每个主题,Kafka集群维护了一个分区数据日志文件结构如下:
每个partition都是一个有序并且不可变的消息记录集合。当新的数据写入时,就被追加到partition的末尾。在每个partition中,每条消息都会被分配一个顺序的唯一标识,这个标识被称为offset,即偏移量。注意,Kafka只保证在同一个partition内部消息是有序的,在不同partition之间,并不能保证消息有序。
Kafka可以配置一个保留期限,用来标识日志会在Kafka集群内保留多长时间。Kafka集群会保留在保留期限内所有被发布的消息,不管这些消息是否被消费过。比如保留期限设置为两天,那么数据被发布到Kafka集群的两天以内,所有的这些数据都可以被消费。当超过两天,这些数据将会被清空,以便为后续的数据腾出空间。由于Kafka会将数据进行持久化存储(即写入到硬盘上),所以保留的数据大小可以设置为一个比较大的值。
10.7 Partition结构
Partition在服务器上的表现形式就是一个一个的文件夹,每个partition的文件夹下面会有多组segment文件,魅族segment文件又包含.index文件、.log文件、.timeindex文件三个文件,其中.log文件就是实际存储message的地方,而.index和.timeindex文件为索引文件,用于检索消息。
10.8 消费数据
多个消费者实例可以组成一个消费者组,并用一个标签来标识这个消费者组。一个消费者组中的不同消费者实例可以运行在不同的进程甚至不同的服务器上。
如果所有的消费者实例都在同一个消费者组中,那么消息记录会被很好的均衡的发送到每个消费者实例。
如果所有的消费者实例都在不同的消费者组,那么每一条消息记录会被广播到每一个消费者实例。
举个例子。如上图所示,一个两个节点的Kafka集群上拥有一个四个partition(P0-P3)的topic。有两个消费者组都在消费这个topic中的数据,消费者组A有两个消费者实例,消费者组B有四个消费者实例。从图中我们可以看到,在同一个消费者组中,每个消费者实例可以消费多个分区,但是每个分区最多只能被消费者组中的一个实例消费。也就是说,如果有一个4个分区的主题,那么消费者组中最多只能有4个消费者实例去消费,多出来的都不会被分配到分区。其实这也很好理解,如果允许两个消费者实例同时消费同一个分区,那么就无法记录这个分区被这个消费者组消费的offset了。如果在消费者组中动态的上线或下线消费者,那么Kafka集群会自动调整分区与消费者实例间的对应关系。
10.9 使用场景
消息队列(MQ)
在系统架构设计中,经常会使用消息队列(Message Queue)——MQ。MQ是一种跨进程的通信机制,用于上下游的消息传递,使用MQ可以使上下游解耦,消息发送上游只需要依赖MQ,逻辑上和物理上都不需要依赖其他下游服务。MQ的常见使用场景如流量削峰、数据驱动的任务依赖等等。在MQ领域,除了Kafka外还有传统的消息队列如ActiveMQ和RabbitMQ等。
- 异步处理, 把非关键流程异步化,提高系统的响应时间和健壮性
- 应用解耦,通过消息队列,
- 流量削峰
追踪网站活动
Kafka最出就是被设计用来进行网站活动(比如PV、UV、搜索记录等)的追踪。可以将不同的活动放入不同的主题,供后续的实时计算、实时监控等程序使用,也可以将数据导入到数据仓库中进行后续的离线处理和生成报表等。
Metrics
Kafka经常被用来传输监控数据。主要用来聚合分布式应用程序的统计数据,将数据集中后进行统一的分析和展示等。
日志聚合
很多人使用Kafka作为日志聚合的解决方案。日志聚合通常指将不同服务器上的日志收集起来并放入一个日志中心,比如一台文件服务器或者HDFS中的一个目录,供后续进行分析处理。相比于Flume和Scribe等日志聚合工具,Kafka具有更出色的性能。
10.10 优点
-
可靠性 - Kafka是分布式,分区,复制和容错的。
-
可扩展性 - Kafka消息传递系统轻松缩放,无需停机。
-
耐用性 - Kafka使用分布式提交日志,这意味着消息会尽可能快地保留在磁盘上,因此它是持久的。
-
性能 - Kafka对于发布和订阅消息都具有高吞吐量。 即使存储了许多TB的消息,它也保持稳定的性能。
-
Kafka非常快,并保证零停机和零数据丢失。
10.11 kafka为什么快?
Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间,但是实际上,Kafka的特性之一就是高吞吐率。
即使是普通的服务器,Kafka也可以轻松支持每秒百万级的写入请求,超过了大部分的消息中间件,这种特性也使得Kafka在日志处理等海量数据场景广泛应用。
Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。
详细介绍参考:https://www.cnblogs.com/binyue/p/10308754.html
11 Zookeeper
ZooKeeper主要包含几下几个组件:
-
Client(客户端):我们的分布式应用集群中的一个节点,从服务器访问信息。对于特定的时间间隔,每个客户端向服务器发送消息以使服务器知道客户端是活跃的。类似地,当客户端连接时,服务器发送确认码。如果连接的服务器没有响应,客户端会自动将消息重定向到另一个服务器。
-
Server(服务器):服务器,我们的ZooKeeper总体中的一个节点,为客户端提供所有的服务。向客户端发送确认码以告知服务器是活跃的。
-
Ensemble:ZooKeeper服务器组。形成ensemble所需的最小节点数为3。
-
Leader: 服务器节点,如果任何连接的节点失败,则执行自动恢复。Leader在服务启动时被选举。
-
Follower:跟随leader指令的服务器节点。
ZooKeeper的应用场景:
- 服务注册&服务发现
配置中心
-
分布式锁
Zookeeper是强一致的多个客户端同时在Zookeeper上创建相同znode,只有一个创建成功