一、JMS 消息队列
1、JMS是Java Message Service的缩写,即Java消息服务,如Hornetq、ActiveMQ、kafka。在大型互联网中,JMS可以帮助我们应用之间的解耦以及操作的异步。
2、JMS两种消息模型:点对点模型,发布/订阅模型。在此基础上,我们着重思考的是消息的顺序保证、扩展性、可靠性、业务操作与消息发送一致性,以及多集群订阅者等方面的问题。
点对点模型:一条消息只被一个消费者消费,只被消费一次。
发布/订阅模型:生产者通过一个特定的topic发送消息到中间件,中间件根据消费者注册的topic,将消息传递给消费者。允许多个消费者接收同一条消息,消费者必须先运行订阅topic。
点对点模型生产者代码:
//1)创建一个connection
InitialContext ctx=new InitialContext();
QueueConnectionFactory f=(QueueConnectionFactory)ctx.lookup("myQueueConnectionFactory");
QueueConnection con=f.createQueueConnection();
con.start();
//2) 创建一个会话接口
QueueSession ses=con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
//3) 获取会话接口对象
Queue t=(Queue)ctx.lookup("myQueue");
//4)创建一个发送者对象
QueueSender sender=ses.createSender(t);
//5) 创建一个消息对象
TextMessage msg=ses.createTextMessage();
String s="aaaa";
msg.setText(s);
//7) 发送消息
sender.send(msg);
System.out.println("Message successfully sent.");
//8) 关闭连接
con.close();
二、kafka
Kafka是一个分布式的、可分区的、多模式的消息系统。
分布式的:Kafka以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个broker。每个分区都由一个服务器作为“leader”,零或若干服务器作为“followers”,leader负责处理消息的读和写,followers则去复制leader。如果leader 挂了,followers中的一台则会自动成为leader。集群中的每个服务都会同时扮演两个角色:作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。
可分区的:Kafka提供的一个逻辑概念:topic,Kafka 对每个topic的日志进行了分区,每个分区都由一系列有序的、不可变的消息组成,这些消息被连续的追加到分区中。分区中的每个消息都有一个连续的序列号叫做offset,用来在分区中唯一的标识这个消息。在一个可配置的时间段内,Kafka集群保留所有发布的消息,不管这些消息有没有被消费。
多模式的:Kafka消费者提供了一个用户组的概念。不同用户组可以消费同一个消息(发布/订阅模型),同一个用户组的不同用户不能消费同一个消息(点对点模型)。,通过分区的概念,Kafka可以在多个consumer组并发的情况下提供较好的有序性和负载均衡。将每个分区分只分发给一个consumer组,这样一个分区就只被这个组的一个consumer消费,就可以顺序的消费这个分区的消息。就是有多少分区就允许多少并发消费。注意consumer组的数量不能多于分区的数量。
三、Kafka安装配置
1、下载安装包
2、Kafka自带zookeeper,只需要配置zookeeper.properties中的server.1、server.2、server.3,然后再在zookeeper文件夹中添加myid文件,内容分别为1、2、3。执行./bin/zookeeper-server-start.sh config/zookeeper.properties &启动zookeeper集群
3、配置Kafka,修改server.properties文件,broker.id、log.dirs、xookeeper.connect。
4、启动kafka集群,执行命令:./bin/kafka-server-start.sh –daemon config/server.properties &
四、java整合Kafka
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.9.2</artifactId>
<version>0.8.2.2</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
生产者
- public KafkaProducer(String topic)
- {
- props.put("serializer.class", "kafka.serializer.StringEncoder");
- props.put("metadata.broker.list", "10.22.10.139:9092");//端口号为server.properties配置的port
- producer = new kafka.javaapi.producer.Producer<Integer, String>(new ProducerConfig(props));
- this.topic = topic;
- }
消费者
- private static ConsumerConfig createConsumerConfig()
- {
- Properties props = new Properties();
- props.put("zookeeper.connect","10.22.10.139:2181");
- props.put("group.id", "group1");
- props.put("zookeeper.session.timeout.ms", "40000");
- props.put("zookeeper.sync.time.ms", "200");
- props.put("auto.commit.interval.ms", "1000");
- return new ConsumerConfig(props);
- }
生产
- producer.send(new KeyedMessage<Integer, String>(topic, messageStr));
消费
- Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
- topicCountMap.put(topic, new Integer(1));
- Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);
- KafkaStream<byte[], byte[]> stream = consumerMap.get(topic).get(0);
- ConsumerIterator<byte[], byte[]> it = stream.iterator();
- while (it.hasNext()) {
- System.out.println("receive:" + new String(it.next().message()));
- }