一、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
topics.put(topic,partitionNum);
Map
KafkaStream
threadPool = Executors.newFixThreadPool(partitionNum);
for(KafkaStream
threadPool.execute(new MessageRunner(partition));
}
}
public void close(){
try{
threadpool.shutdown();
}catch(Exception e){
}finally{
connector.shutdown();
}
}
class MessageRunner implements Runnable(){
private KafkaStream
MessageRunner(KafkaStream
this.KafkaStream
}
public void run(){
ConsumerIterator
while(it.hasNext()){
MessageAndMetadata
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
public ProduceImp() throws Exception{
Properties properties = new Properties();
properties.load(ClassLoader.getSystemResourceAsStream("produce.properties"));
ProduceConfig config=new ProduceConfig(properties);
inner=new Producer
}
public void send(String topicName,String message){
if(topicName==null || message ==null){
return;
}
KeyedMessage
inner.send(km);
}
public void send(String topicName,Collection
if(topicName==null || messages ==null){
return;
}
if(messages.isEmpty()){
return;
}
List
for(String entry:messages){
KeyenMessage
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();
}
}
}
}