中间件学习-kafka架构简述及搭建

Kafka

Kafka是Apache下的分布式消息中间件,需要zookeeper的分布式管理才能使用
架构如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vH8QTuO-1626158135606)(en-resource://database/519:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zBcXi3iM-1626158135609)(en-resource://database/517:1)]

Partition

kafka的存储,就不得不提到分区,即partitions,创建一个topic时,同时可以指定分区数目,分区数越多,其吞吐量也越大,但是需要的资源也越多,同时也会导致更高的不可用性,kafka在接收到生产者发送的消息之后,会根据均衡策略将消息存储到不同的分区中

每个partition可以被认为是一个无限长度的数组,新数据 顺序追加进这个数组。物理上,每个partition对应于一个文件夹。一个broker上可以存放多个 partition。这样,producer可以将数据发送给多个broker上的多个partition,consumer也可以并 行从多个broker上的不同paritition上读数据,实现了水平扩展

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zk0Py6Xq-1626158135612)(en-resource://database/515:1)]

offset

同一个partition上顺序存储顺序读写

offset是kafka消费者在对应分区上已经消费的消息数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AggPd5m3-1626158135614)(en-resource://database/535:1)]

Kafka环境搭建

在台式机上做了三个虚拟机,组成一个虚拟机集群,安装zookeeper后,完成分布式结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWXyB8V6-1626158135615)(en-resource://database/523:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6qk4M6f6-1626158135616)(en-resource://database/521:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-stAVnOyj-1626158135617)(en-resource://database/525:1)]

安装kafka,运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28UjQoby-1626158135617)(en-resource://database/529:1)]

运行生产者和消费者

java代码进行生产与消费

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOewkIxg-1626158135618)(en-resource://database/531:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ta3rSVYx-1626158135619)(en-resource://database/533:1)]

package com.kafka.sample;

import kafka.producer.KeyedMessage;

import kafka.javaapi.producer.Producer;
import kafka.serializer.StringEncoder;


import java.util.Properties;

public class Hello01Producer extends Thread{
    private Producer<String,String> producer;

    public Hello01Producer(String pName){
        super.setName(pName);

        Properties properties=new Properties();
        properties.put("metadata.broker.list","192.168.76.200:9092,192.168.76.201:9092,192.168.76.202:9092");
        //设定写出数据的格式
        properties.put("serializer.class", StringEncoder.class.getName());
        //设定应答方式
        properties.put("ack",1);
        //批量
        properties.put("batch.size",16384);
        //通过api创建生产者对象
        producer= new Producer<String,String>(new kafka.producer.ProducerConfig(properties));
    }
    public void run(){
        //初始化计数器
        int count=0;
        System.out.println("Hello01Producer开始发送数据");

        while(count<10000){
            String key =String.valueOf(++count);
            String value=Thread.currentThread().getName()+"----"+count;

            KeyedMessage<String,String> message=new KeyedMessage<>("bdplog",key,value);
            producer.send(message);
            
            System.out.println("生产者Producer生产----"+key+"----"+value);
            try{
                //生产速度
                Thread.sleep(1);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args){
        Hello01Producer producer1=new Hello01Producer("Robert");
        producer1.start();
    }
}

package com.kafka.sample;

import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import kafka.message.MessageAndMetadata;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class Hello01Consumer extends Thread {
    private ConsumerConnector consumer;

    public Hello01Consumer(String cName) {
        super.setName(cName);
        //配置文件
        Properties properties = new Properties();
        //zk地址
        properties.put("zookeeper.connect", "192.168.76.200:2181,192.168.76.201:2181,192.168.76.202:2181");
        //消费者所在组名
        properties.put("group.id", "SHSXT-BigData");
        //zk超时时间
        properties.put("zookeeper.session.timeout.ms", "400");
        //第一次消费时,从最低偏移量开始
        properties.put("auto.offset.reset", "smallest");
        //自动提交偏移量
        properties.put("auto.commit.enable", "true");
        //提交偏移量时间间隔
        properties.put("auto.commit.interval.ms", "1000");
        //通过api创建对象
        consumer = Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));

    }
    @Override
    public  void run() {
        //描述读取哪个topic,需要几个线程
        Map<String,Integer> topicCountMap=new HashMap<>();
        topicCountMap.put("bdplog",1);
        //消费者根据配置信息开始读取
        Map<String, List<KafkaStream<byte[],byte[]>>> consumeMap=consumer.createMessageStreams(topicCountMap);
        //每个线程对应一个KafkaStream
        List<KafkaStream<byte[],byte[]>> list=consumeMap.get("bdplog");
        //获取KafkaStream
        KafkaStream stream0=list.get(0);
        ConsumerIterator<byte[],byte[]> iterator=stream0.iterator();
        //开始迭代并获取数据
        while(iterator.hasNext()){
            //获取一条消息
            MessageAndMetadata<byte[],byte[]> value=iterator.next();
            int partition=value.partition();
            long offset=value.offset();
            String data=new String(value.message());
            System.out.println("----消费者Consumer消费----"+data+"----partition:"+partition+"----offset:"+offset);
        }
    }
    public static void main(String[] args){
        Hello01Consumer consumer1=new Hello01Consumer("ConsumerName");
        consumer1.start();
    }
}

ack

kafka提供了三种消息确认策略方式

ack=0,1,-1

0

意味着producer不等待broker同步完成的确认,继续发送下一条(批)信息

提供了最低的延迟。但是最弱的持久性,当服务器发生故障时,就很可能发生数据丢失。例如leader已经死亡,producer不知情,还会继续发送消息broker接收不到数据就会数据丢失

1

意味着producer要等待leader成功收到数据并得到确认,才发送下一条message。此选项提供了较好的持久性较低的延迟性。

Partition的Leader死亡,follwer尚未复制,数据就会丢失

-1

意味着producer得到follwer确认,才发送下一条数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oCaRsGv3-1626158135619)(en-resource://database/537:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GsQPOUSc-1626158135620)(en-resource://database/539:1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-unwvAE3K-1626158135620)(en-resource://database/541:1)]

每个partition不只有一个,而是有一个leader(红色)和多个replica(蓝色),生产者根据消息的topic和key值,确定了消息要发往哪个partition之后(假设是p1),会找到partition对应的leader(也就是broker2里的p1),然后将消息发给leader,leader负责消息的写入,并与其余的replica进行同步

参考:

linux构建集群
zookeeper搭建
kafka搭建

常见问题

Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么

分区中的所有副本统称为AR(Assigned Repllicas)。所有与leader副本保持一定程度同步的副本(包括Leader)组成ISR(In-Sync Replicas),ISR集合是AR集合中的一个子集。消息会先发送到leader副本,然后follower副本才能从leader副本中拉取消息进行同步,同步期间内follower副本相对于leader副本而言会有一定程度的滞后。前面所说的“一定程度”是指可以忍受的滞后范围,这个范围可以通过参数进行配置。与leader副本同步滞后过多的副本(不包括leader)副本,组成OSR(Out-Sync Relipcas),由此可见:AR=ISR+OSR。在正常情况下,所有的follower副本都应该与leader副本保持一定程度的同步,即AR=ISR,OSR集合为空
任意一个超过阈值都会把follower剔除出ISR, 存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中(策略剔除、策略加入)

Kafka中的broker 是干什么的

broker 是消息的代理,Producers往Brokers里面的指定Topic中写消息,Consumers从Brokers里面拉取指定Topic的消息,然后进行业务处理,broker在中间起到一个代理保存消息的中转站

Kafka follower如何与leader同步数据

Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制

日志复制算法(log replication algorithm)必须提供的基本保证是,如果它告诉客户端消息已被提交,而当前 leader 出现故障,新选出的 leader 也必须具有该消息。在出现故障时,Kafka 会从挂掉 leader 的 ISR 里面选择一个 follower 作为这个分区新的 leader ;换句话说,是因为这个 follower 是跟上 leader 写进度的。

每个分区的 leader 会维护一个 in-sync replica(同步副本列表,又称 ISR)。当 producer 往 broker 发送消息,消息先写入到对应 leader 分区上,然后复制到这个分区的所有副本中。只有将消息成功复制到所有同步副本(ISR)后,这条消息才算被提交。由于消息复制延迟受到最慢同步副本的限制,因此快速检测慢副本并将其从 ISR 中删除非常重要

Kafka中是怎么体现消息顺序性的?

kafka每个partition中的消息在写入时都是有序的,消费时,每个partition只能被每一个group中的一个消费者消费,保证了消费时也是有序的。
整个topic不保证有序。如果为了保证topic整个有序,那么将partition调整为1.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值