消息分发中间件:Kafka

一、Kafka的作用

数据的前端采集和后端处理之间需要一个消息中间件负责消息转发,以保障消息的可靠性以及匹配前后端的速度差。是java开发的,不支持事务、支持集群、动态扩容以及负载均衡

二、Kafka架构

1、生产者(Producer):消息和数据的生产者

2、代理(Broker):缓存代理,Kafka的核心功能

3、消费者(Consumer):消息和数据的消费者

kafa给Producer和Consumer提供注册的接口,数据从Producer发送到Broker,Broker承担一个中间缓存和分发的作用,负责发送到注册到系统中的Consumer。

三、设计要点

1、Kafka是以Topic进行消息管理的,每个Topic包含多个Partition,每个分区物理上对应一个文件夹,该文件夹以topicName_partitionIndex方式命名,该文件夹存储这个分区的所有消息(.log)和索引文件(.index)。每个分区是一个有序队列,分区中的每条消息都会被分配一个有序id(offset),kafka只能保证按一个分区的顺序将消息发给consumer,不能保证整个topic(多个分区)消息是有序的。每个分区由多个Segment组成,发布者发布到Topic的消息会被均匀的分不到多个分区上,Broker收到消息后往对应分区的最后一个Segment上添加该消息,当某个Segment上的消息条数达到配置值或者消息发布时间超过阀值时,Segment上的消息便会被flush到磁盘上,只有flush到磁盘上的消息订阅者才能订阅到,Segment达到一定大小后将不会再往该Segment写数据,Broker会创建新的Segment。

2、Producer和Broker之间没有负载均衡机制,Broker和Consumer之间利用ZooKeeper进行负载均衡。所以所有的Broker和Consumer都要在ZooKeeper中进行注册。

3、消费组:多个消费者可以被加到一个组中,所有组员共同消费一个topic,但组员之间不能重复消费。这样不仅可以提高kafka并发消费的能力,还可以增强容错机制。

4、kafka之所以快,不仅因为是顺序读写I/O和多个分区概念,还因为大多数情况是在内存中寻找数据。

四、Kafka消息存储方式

每个分区都是一个顺序的、不可变的消息队列,并且可以持续添加。分区中的消息被分配一个序列号,成为偏移量(offset)。Kafka中保存所有的消息,直到它们过期,无论消息是否被消费。

五、代码样例

1、Consumer

public class ConsumerImp{

    private ConsumerConfig config;

    private String topic;'

    private  int partitionNum;

    private MessageExecutor executor;

    private  ConsumerConnector connector;

    private  ExecutorService threadPool;

    public ConsumerImp(String topic, int partitionNum,MessageExecutor executor) throws Excepti;on{

         Properties properties = new Properties();

         properties.load(ClassLoader.getSystemResourceAsStream("consumer.properties"));

         config = new ConsumerConfig(properties);

         this.topic = topic;

        this.partitionNum=partitionNum;

       this.executor=executor;

}

public void start() throws Exception{

      connector=Consumer.createJavaConsumerConnector(config);

      Map<String,Integer> topics = new HashMap<>();

     topics.put(topic,partitionNum);

    Map<String,List<KafkaStream<byte[],byte[]>>> streams = connector.createMessageStreams(topics);

    KafkaStream<byte[],byte[]> partitions=streams.get(topic);

   threadPool = Executors.newFixThreadPool(partitionNum);

  for(KafkaStream<byte[],byte[]> partition:partitions){

       threadPool.execute(new MessageRunner(partition));

}   

}

public void close(){

try{

threadpool.shutdown();

}catch(Exception e){

}finally{

connector.shutdown();

}

}

class MessageRunner implements Runnable(){

 private  KafkaStream<byte[],byte[]> partition;

MessageRunner(KafkaStream<byte[],byte[]> partition){

 this.KafkaStream<byte[],byte[]> partition=KafkaStream<byte[],byte[]> partition;

}

public void run(){

ConsumerIterator<byte[],byte[]> it = partition.iterator();

while(it.hasNext()){

MessageAndMetadata<byte[],byte[]> item=it.next();

System.out.println(item.partition());

System.out.println(item.offset());

executor.execute(new String(item.message()));

}

 

}

}

interface MessageExecutor{

public void execute(String message);

}

public static void main(String[] args){

ConsumerImp consumer=null;

try{

MessageExecutor executor = new MessageExecutor(){

public void execute(String message){

System.out.println(message);

}

};

consumer=new ConsumerImp("test-topic",2,executor);

consumer.start();

}catch(Exception e){

e.printStackTrace();

}finally{

if(consumer!=null){

consumer.close();

}

}

}

}

2、Producer

public class ProducerImp{

private Producer<String,String> inner;

public ProduceImp() throws Exception{

Properties properties = new Properties();

properties.load(ClassLoader.getSystemResourceAsStream("produce.properties"));

ProduceConfig config=new ProduceConfig(properties);

inner=new Producer<String,String>(config);

}

public void send(String topicName,String message){

if(topicName==null || message ==null){

return;

}

KeyedMessage<String,String> km=new KeyedMessage<String,String>(topicName,message);

inner.send(km);

}

public void send(String topicName,Collection<String> messages){

if(topicName==null || messages ==null){

return;

}

if(messages.isEmpty()){

return;

}

List<KeyedMessage<String,String>> kms=new ArrayList<>();

for(String entry:messages){

KeyenMessage<String,String> km=new KeyendMessage<>(topicName,entry);

kms.add(km);

}

inner.send(kms);

}

public void close(){

inner.close();

}

public void main(String[] args){

ProducerImp producer =null;

try{

producer=new ProducerImp();

int i=0;

while(true){

producer.send("test-topic","this is a sample" + i);

i++;

Thread.sleep(2000);

}

}catch(Exception e){

e.printStackTrace();

}finally{

if(producer!=null){

producer.close();

}

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值