1.异步通信原理
1.1.观察者模式
发布订阅模式
1.2.生产者消费者模式
- 传统模式
生产者直接将消息传递给指定的消费者
耦合性特别高,当生产者或者消费者发生变化,都需要重写业务逻辑 - 生产者消费者模式
通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯
1.3.缓冲区
解耦,支持并发,支持忙闲不均
1.4.数据单元
关联到业务对象,完整性,独立性,颗粒度
2.消息系统原理
一个消息系统负责将数据从一个应用传递到另外一个应用,应用只需关注于数据,无需关注数据在两个或多个应用间是如何传递的。
2.1.点对点消息传递
2.2.发布订阅消息传递
用于分布式
3.Kafka简介
官网: http://kafka.apache.org
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。
概况说:
- 消息中间件
1.天生分布式
2.存储数据
3.流处理(聚合、统计)
3.1.设计目标
适时数据处理
3.2.Kafka的优点
解耦
冗余(安全)
扩展性
可恢复性
缓冲
异步通信
4.Kafka系统架构
4.1.Broker(服务器节点)
. Kafka集群包含一个或多个服务器,服务器节点称为broker。
4.2.Topic(主题表名)
每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。
- 类似于数据库的表名或者ES的Index
- 物理上不同Topic的消息分开存储。逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)
4.3.Partition (分区)
- topic中的数据分割为一个或多个partition。
- 每个topic至少有一个partition,当生产者产生数据的时候,根据分配策略,选择分区,然后将消息追加到指定的分区的末尾(队列)
- 每条消息都会有一个自增的编号
标识顺序
用于标识消息的偏移量 - 每个partition中的数据使用多个segment文件存储。
- partition中的数据是有序的,不同partition间的数据丢失了数据的顺序。
- 如果topic有多个partition,消费数据时就不能保证数据的顺序。严格保证消息的消费顺序的场景下,需要将partition数目设为1。
partition分为主leader,从Follower
弱一致性保证数据的一致性:同节点不参与用户请求
4.4.Leader(主节点)
每个partition有多个副本,其中有且仅有一个作为Leader,Leader是当前负责数据的读写的partition。
4.5.Follower(从节点)
- Follower跟随Leader,所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步。
- 如果Leader失效,则从Follower中选举出一个新的Leader。
- 当Follower挂掉、卡住或者同步太慢,leader会把这个follower从" in sync replicas”(ISR)列表中删除,重新创建一个Follower。
4.6. replication(备份)
- 数据会存放到topic的partation中,但是有可能分区会损坏
- 我们需要对分区的数据进行备份(备份多少取决于你对数据的重视程度)我们将分区的分为Leader(1)和Follower(N)
Leader负责写入和读取数据
Follower只负责备份
保证了数据的一致性
4.7.producer(生产者)
- 生产者即数据的发布者,该角色将消息发布到Kafka的topic中。
- broker接收到生产者发送的消息后,broker将该消息追加到当前用于追加数据的segment文件中。
- 生产者发送的消息,存储到一个partition中,生产者也可以指定数据存储的partition。
4.8.consumer(消费者)
消费者可以从broker中读取数据。消费者可以消费多个topic中的数据。kafka提供了两套consumer APl:
- The high-1eve1 consumer API
- The simpleconsumer API
4.9.Consumer Group (消费者组)
- 每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。
- 将多个消费者集中到一起去处理某一个Topic的数据,可以更快的提高数据的消费能力整个消费者组共享一组偏移量(防止数据被重复读取),因为一个Topic有多个分区
4.10. offset偏移量
- 可以唯一的标识—条消息
- 偏移量决定读取数据的位置,不会有线程安全的问题,消费者通过偏移量来决定下次读取的消息
- 消息被消费之后,并不被马上删除,这样多个业务就可以重复使用kafka的消息
- 我们某一个业务也可以通过修改偏移量达到重新读取消息的目的,偏移量由用户控制·消息最终还是会被删除的,默认生命周期为1周(7*24小时)
4.11.Zookeeper
学习笔记点这里
kafka通过 zookeeper来存储集群的 meta 信息。
5.Kafka环境搭建
windows(如下) / linux
- 启动kafka前先启动zookeeper
- 进入bin目录,双击zkServer.cmd运行Zookeeper
- kafka跟目录shift+右键打开Powershell
- 输入运行:
.\bin\windows\kafka-server-start.bat .\config\server.properties
6.Kafka数据检索机制
kafka相当于数据流
- topic在物理层面以partition为分组,一个topic可以分成若干个partition
- partition还可以细分为Segment,一个partition物理上由多个Segment组成
segment的参数有两个:
1. log.segment.bytes:单个segment可容纳的最大数据量,默认为1GB
2. log.segment.ms: Kafka在commit一个未写满的segment前,所等待的时间(默认为7天) - LogSegment文件由两部分组成,分别为".index"文件和".log"文件,分别表示为Segment索引文件和数据文件。
1.partition全局的第一个segment从O开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值。
2.数值大小为64位,20位数字字符长度,没有数字用0填充 - 消息都具有固定的物理结构
数据的安全性
7.1. producer delivery guarantee
生产者如何安全的把数据传到kafka上
0. At least one 消息绝不会丢,但可能会重复传输 (消息传,日志没写)
- At most once消息可能会丢,但绝不会重复传输
- Exactly once每条消息肯定会被传输一次且仅传输一次
- Producers可以选择是否为数据的写入接收ack,有以下几种ack的选项: request.required.acks
acks=0:
Producer在ISR 中的Leader已成功收到的数据并得到确认后发送下一条 Message。
acks=1:
·这意味着Producer无需等待来自Broker的确认而继续发送下一批消息。
acks=all :
Producer需要等待ISR中的所有Follower都确认接收到数据后才算一次发送完成,可靠性最高。
7.2.ISR机制
kafka数据如何同步
- 关键词
AR : Assigned Replicas 用来标识副本的全集
OSR : out -sync Replicas离开同步队列的副本
ISR : in -sync Replicas 加入同步队列的副本
ISR = Leader+没有落后太多的副本;AR = OSR+ ISR。 - 我们备份数据就是防止数据丢失,当主节点挂掉时,可以启用备份节点o
- producer–push–>leader
leader<–pull–follower
Follower每间隔一定时间去Leader拉取数据,来保证数据的同步 - lSR(in-syncReplica)
当主节点挂掉,并不是去Follower选择主,而是从ISR中选择主。判断标准
超讨10秒钟没有同步数据,主副节点差4000条数据 - 脏节点选举
kafka采用一种降级措施来处理:
选举第一个恢复的node作为leader提供服务,以它的数据为基准,这个措施被称为脏leader选举
7.3.Broker数据存储机制
kafka存储时长
无论消息是否被消费,kafka都会保留所有消息。有两种策略可以删除旧数据:
1.基于时间:1og.retention. hours=168
2.基于大小:1og.retention . bytes=1073741824
7.4.consumer delivery guarantee
消费者如何消费数据
- 如果将consumer设置为autocommit,consumer一旦读到数据立即自动commit。如果只讨论这一读取消息的过程,那Kafka确保了Exactly once。
- 读完消息先commit再处理消息。
如果consumer在commit 后还没来得及处理消息就crash了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息。这就对应于At most once - 读完消息先处理再commit。
如果在处理完消息之后commit之前consumer crash了,下次重新开始工作时还会处理刚刚未commit的消息,实际上该消息已经被处理过了。
这就对应于At least once。 - 如果一定要做到Exactly once,就需要协调offset和实际操作的输出。
经典的做法是引入两阶段提交。 - Kafka默认保证At least once,并且允许通过设置producer异步提交来实现At most once
7.5.数据的消费
partiton_num=2,启动一个consumer进程订阅这个topic,对应的,stream_num设为2,也就是说启两个线程并行处理message。
如果auto.commit.enable=true,
。当consumer fetch了一些数据但还没有完全处理掉的时候,
。刚好到commit interval出发了提交offset操作,接着consumer crash掉了。
。这时已经fetch的数据还没有处理完成但已经被commit掉,因此没有机会再次被处理,数据丢失。
如果auto.commit.enable=false,
。假设consumer的两个fetcher各自拿了—条数据,并且由两个线程同时处理,
。这时线程t1处理完partition1的数据,手动提交offset,这里需要着重说明的是,当手动执行commit的时候,
。实际上是对这个consumer进程所占有的所有partition进行commit,kafka暂时还没有提供更细粒度的commit方式,
。也就是说,即使t2没有处理完partition2的数据,offsett也被t1提交掉了。如果这时consumer crash掉,t2正在处理的这条数据就丢失了。
- 方法1:(将多线程问题转成单线程)
手动commit offset,并针对partition_num启同样数目的consumer进程,这样就能保证一个consumer进程占有一个partition,commit offset的时候不会影响别的partition的offset。但这个方法比较局限,因为partition和consumer进程的数目必须严格对应 - 方法2:(参考HDFS数据写入流程)
手动commit offset,另外在consumer端再将所有fetch到的数据缓存到queue里,当把queue里所有的数据处理完之后,再批量提交offset,这样就能保证只有处理完的数据才被commit。
8.JavaAPI
8.1.生产者
8.2.消费者
8.1.重复消费和数据的丢失
9.Kafka优化
9.1.Partition数目
一般来说,每个partition能处理的吞吐为几MB/s(仍需要基于根据本地环境测试后获取准确指标),增加更多的partitions意味着;
- 更高的并行度与吞吐
- 可以扩展更多的(同一个consumer group中的)consumers
- 若是集群中有较多的brokers,则可更大程度上利用闲置的brokers
- 但是会造成Zookeeper的更多选举
- 也会在Kafka中打开更多的文件
9.2.Replication factor
此参数决定的是records复制的数目,建议至少设置为2,一般是3,最高设置为4。·更高的replication factor(假设数目为N)意味着:
- 系统更稳定(允许N-1个broker宕机)
- 更多的副本(如果acks=all,则会造成较高的延时)
- 系统磁盘的使用率会更高(一般若是RF为3,则相对于RF为2时,会占据更多50%的磁盘空间)
9.3.批量写入
为了大幅度提高producer写入吞吐量,需要定期批量写文件
- 每当producer写入10000条消息时,刷数据到磁盘
log.flush.interva7.messages=100ool - 每间隔1秒钟时间,刷数据到磁盘
log.flush.interva7.ms=1000
10.Flume+Kafka集成
参考尚学堂-林老师