RabbitMQ
- RabbitMQ
- 1.MQ introduction
- 2. Use scenario
- 3. Introduction to rabbitmq
- 4. AMQP agreement
- 5. Single node installation in Windows Environment
- 6. Use of rabbitmq management interface
- 7.RabbitMQ message type
- 7.1 simple queue
- 7.1.1 get ConnectionUtil:
- 7.1.2 message producer: Send
- 7.1.3 consumer: Recv
- 7.1.4 disadvantages of simple queues:
- 7.2 work queues, fair distribution polling distribution
- 7.3 publish/subscribe
- 7.4. Routing wildcard mode
- 7.5.Topics
- 7.6 RPC manual and automatic message acknowledgment (message acknowledgment mechanism transaction - confirm)
- Confirm mode
- Message response and message persistence
- Exchange (switch forwarder)
1.MQ introduction
MQ is called Message Queue. Message Queue (MQ) is an application to application communication method.
2. Use scenario
2.1. Peak shaving
The origin of flow peak shavingIt mainly comes from the business scenarios of the Internet, for example, the Spring Festival train ticket rush to start soon, a large number of users need to rush to buy at the same time; and the well-known Alibaba double 11 seconds kill, In a short time, hundreds of millions of users swarmed in, and the instantaneous flow was huge (high concurrency). For example, 2 million people were ready to rush to buy a product at 12:00 in the morning, but the number of products was limited to about 100-500.
In this way, there are only a few hundred users who can actually buy this product. But in terms of business, seckill hopes more people to participate in it, that is to say, more and more people are expected to come to see and buy the product before rush buying.
However, when the time of rush to buy is up and the user starts to place an order, the lack of back-end server of seckill doesn't want millions of people to launch rush to buy at the same time.
We all know that the processing resources of the server are limited, so when there is a peak, it is easy to cause server downtime and users can not access the situation.
2.2 log processing
2.3 Application decoupling
2.4 asynchronous processing
3. Introduction to rabbitmq
Introduction
RabbitMQ, developed in Erlang, is an open-source message middleware that implements AMQP advanced message queuing protocol.
Advantages:
- Very good performance, low latency
- Throughput to 10000
- Good management interface management tools
- The community is relatively active
Disadvantages:
- Relatively low throughput
4. AMQP agreement
Advanced Message Queuing Protocol
5. Single node installation in Windows Environment
Download the installation package
Click to jump to download RabbitMQ page
View the Erlang version required for this RabbitMQ
To install erlang:
Double click the default installation and select the installation directory. The directory cannot have Chinese characters, and the computer name cannot have Chinese characters
Configure erlang environment variables
Open cmd input erl
Install rabbitmq
Activate the rabbitMQ UI management interface:
Run in the sbin directory of rabbit
D:\work\java\rabbitMQ\rabbitmq_server-3.8.3\sbin> rabbitmq-plugins.bat enable rabbitmq_management
Restart service:
Browser access: http://localhost:15672/
Enter username: guest
input password:guest
6. Use of rabbitmq management interface
Browser address bar input: localhost:15672
User name: guest password: Guest
Add user
Tags
Admin: Super Administrator
Monitoring: monitor, which can view node information
Policymaker: policy maker (mirror)
Management:
Impersonator:
None
Added an admin password 123456, Tags: Administrator
Add Virtual Host
Virtual Host is equivalent to mysql db
Add: usually starts with "/"
After adding:
to grant authorization:
Set admin to access vhost01
Click user name
Select Virtual Host and Set permission
7.RabbitMQ message type
7.1 simple queue
P: Message producer
Red: queue
C: Consumers
Three objects: producer queue consumer
7.1.1 get ConnectionUtil:import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; public class ConnectionUtil { /** * Get MQ connection * @return */ public static Connection getConnection() throws IOException, TimeoutException { // Define a connection factory ConnectionFactory factory = new ConnectionFactory(); // Set service address factory.setHost("localhost"); // AMQP 5672 factory.setPort(5672); // vhost factory.setVirtualHost("/vhost01"); // user name factory.setUsername("admin"); // password factory.setPassword("123456"); return factory.newConnection(); } }7.1.2 message producer: Send
public class Send { private static final String QUERE_NAME="test_simple_queue"; public static void main(String[] args) throws IOException, TimeoutException { // Get a connection Connection connection = ConnectionUtil.getConnection(); // Get a channel from the connection Channel channel = connection.createChannel(); // Declare a queue channel.queueDeclare(QUERE_NAME, false, false, false, null); String message = "hello simple !"; channel.basicPublish("", QUERE_NAME, null, message.getBytes()); System.out.println("send message"); channel.close(); connection.close(); } }7.1.3 consumer: Recv
public class Recv { private static final String QUERE_NAME="test_simple_queue"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Create channel Channel channel = connection.createChannel(); // Queue declaration channel.queueDeclare(QUERE_NAME, false, false,false, null); // Define consumers for the queue DefaultConsumer defaultConsumer = new DefaultConsumer(channel){ // Get arrival message @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { super.handleDelivery(consumerTag, envelope, properties, body); String msgString = new String(body,"utf-8"); System.out.println("new api recv: " + msgString); } }; // listen queue channel.basicConsume(QUERE_NAME, true, defaultConsumer); } }7.1.4 disadvantages of simple queues:
The coupling is high. The producer corresponds to the consumer one by one (if I want to have multiple messages in the consumer consumption queue, this is not the case). When the queue name is changed, it must be changed at the same time
7.2 work queues, fair distribution polling distribution
7.2.1 why the work queue appears:simple queues are one-to-one correspondence, and in our actual development, it is effortless for producers to send messages, while consumers generally need to integrate with business. Consumers need to process after receiving messages, which may take time. At this time, there will be a lot of messages in the queues
7.2.2 distribute polling 7.2.2.1 message producer: Sendpublic class Send { public static final String QUEUE_NAME = "test_work_queue"; /** * |--> C2 * P ---> Queue ----| * |--> C1 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); // send message for (int i = 0; i < 50; i++) { String msg= "send hello " + i; channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("[WQ] send msg = " + msg); Thread.sleep(i*20); } // close resource channel.close(); connection.close(); } }7.2.2.2 consumer: Recv1:
public class Recv1 { public static final String QUEUE_NAME = "test_work_queue"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // Define a consumer Consumer consumer = new DefaultConsumer(channel) { // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //super.handleDelivery(consumerTag, envelope, properties, body); String msg = new String(body, "utf-8"); System.out.println("Recv [1] msg = " + msg); try{ Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); }finally{ System.out.println("Recv [1] done!"); } } }; // listen queue boolean autoAck = true; channel.basicConsume(QUEUE_NAME, autoAck, consumer); } }7.2.2.3 consumer: Recv2
public class Recv2 { public static final String QUEUE_NAME = "test_work_queue"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // Define a consumer DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { super.handleDelivery(consumerTag, envelope, properties, body); String msg = new String(body, "utf-8"); System.out.println("Recv [2] msg = " + msg); try{ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally{ System.out.println("Recv [2] done!"); } } }; // listen queue boolean autoAck = true; channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer); } }7.2.2.4 phenomenon:
Consumer 1 and consumer 2 handle the same number of messages
Consumer 1: even
Consumer 2: odd
This method is called round robin, and the result is that no matter who is busy or who is idle, no more messages will be sent. The task is always one for you and one for me
Manual receipt required
// MQ sends only one request to the consumer at a time. When the consumer finishes processing the message, it will manually receive the receipt, and then MQ sends another message to the consumer channel.basicQos(1); boolean autoAck = false; //false manual receipt, after processing the message, tell MQ channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);7.2.3.1 producers
public class Send { public static final String QUEUE_NAME = "test_work_queue"; /** * |--> C2 * P ---> Queue ----| * |--> C1 * @param args * @throws IOException * @throws TimeoutException */ public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); /** * Before each consumer sends a confirmation message, the message queue does not send the next message to the consumer, and only processes one message at a time * Limit sending more than one message to the same consumer */ channel.basicQos(1); // send message for (int i = 0; i < 50; i++) { String msg= "send hello " + i; channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("[WQ] send msg = " + msg); Thread.sleep(i*5); } // close resource channel.close(); connection.close(); } }7.2.3.2 consumer 1
public class Recv1 { public static final String QUEUE_NAME = "test_work_queue"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // MQ sends only one request to the consumer at a time. When the consumer finishes processing the message, it will manually receive the receipt, and then MQ sends another message to the consumer channel.basicQos(1); // Define a consumer Consumer consumer = new DefaultConsumer(channel) { // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //super.handleDelivery(consumerTag, envelope, properties, body); String msg = new String(body, "utf-8"); System.out.println("Recv [1] msg = " + msg); try{ Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); }finally{ System.out.println("Recv [1] done!"); // Manual receipt channel.basicAck(envelope.getDeliveryTag(), false); } } }; // listen queue // boolean autoAck = true; / / auto answer boolean autoAck = false; //Manual response channel.basicConsume(QUEUE_NAME, autoAck, consumer); } }7.2.3.3 consumers 2
public class Recv2 { public static final String QUEUE_NAME = "test_work_queue"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // MQ sends only one request to the consumer at a time. When the consumer finishes processing the message, it will manually receive the receipt, and then MQ sends another message to the consumer channel.basicQos(1); // Define a consumer DefaultConsumer defaultConsumer = new DefaultConsumer(channel) { // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { super.handleDelivery(consumerTag, envelope, properties, body); String msg = new String(body, "utf-8"); System.out.println("Recv [2] msg = " + msg); try{ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally{ System.out.println("Recv [2] done!"); // Manual receipt channel.basicAck(envelope.getDeliveryTag(), false); } } }; // listen queue boolean autoAck = false; //false manual receipt channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer); } }7.2.3.4 phenomenon:
Consumer 2 processes more messages than consumer 1, and has more to offer
7.3 publish/subscribe
1. One producer, multiple consumers
2. Each consumer has its own queue
3. The producer does not send the message directly to the queue, but to the exchange converter exchange
4. Each queue must be bound to the switch
5. The message sent by the producer passes through the switch and reaches the queue. Can realize a message to be consumed by multiple consumers
public class Send { public static final String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // Claim switch channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); //distribute // send message String msg = "hello ps"; channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes()); System.out.println("Send msg = " + msg); channel.close(); connection.close(); } }
Where's the news?? Lost, because the switch does not have the storage capacity, in rabbitmq only the queue has the storage capacity.
Because there is no queue bound to the switch after declaring the switch, the data is lost
Registration - "email -" SMS "
Consumer 1: Recv1public class Recv1 { public static final String QUEUE_NAME = "test_queue_fanout_email"; public static final String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // Ensure that only one is distributed at a time channel.basicQos(1); // Bind to switch forwarder channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); // Define a consumer Consumer consumer = new DefaultConsumer(channel) { // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //super.handleDelivery(consumerTag, envelope, properties, body); String msg = new String(body, "utf-8"); System.out.println("Recv [1] msg = " + msg); try{ Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); }finally{ System.out.println("Recv [1] done!"); // Manual receipt channel.basicAck(envelope.getDeliveryTag(), false); } } }; // listen queue boolean autoAck = false; channel.basicConsume(QUEUE_NAME, autoAck, consumer); } }Consumer 2: Recv2
public class Recv2 { public static final String QUEUE_NAME = "test_queue_fanout_sms"; public static final String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] args) throws IOException, TimeoutException { // Get connection Connection connection = ConnectionUtil.getConnection(); // Get channel Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // Bind to switch forwarder channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); // Ensure that only one is distributed at a time channel.basicQos(1); // Define a consumer Consumer consumer = new DefaultConsumer(channel) { // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { //super.handleDelivery(consumerTag, envelope, properties, body); String msg = new String(body, "utf-8"); System.out.println("Recv [2] msg = " + msg); try{ Thread.sleep(2000); }catch (InterruptedException e) { e.printStackTrace(); }finally{ System.out.println("Recv [2] done!"); // Manual receipt channel.basicAck(envelope.getDeliveryTag(), false); } } }; // listen queue boolean autoAck = false; channel.basicConsume(QUEUE_NAME, autoAck, consumer); } }
7.4. Routing wildcard mode
producerpublic class Send { public static final String EXCHANGE_NAME = "test_exchange_direct"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // exchange channel.exchangeDeclare(EXCHANGE_NAME, "direct"); String msg = "hello direct !"; // routing key String routingKey = "info"; channel.basicPublish(EXCHANGE_NAME, routingKey, null, msg.getBytes()); System.out.println("send :" + msg); channel.close(); connection.close(); } }Consumer 1: Recv1
public class Recv1 { public static final String EXCHANGE_NAME = "test_exchange_direct"; public static final String QUEUE_NAME = "test_queue_direct_1"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false,null); // Bind queue to switch and routingKey channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error"); // Ensure that only one is distributed at a time channel.basicQos(1); // Define a consumer Consumer consumer = new DefaultConsumer(channel){ // Message arrival, trigger this method @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "utf-8"); System.out.println("Recv [1] msg = " + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally{ // Message receipt channel.basicAck(envelope.getDeliveryTag(), false); System.out.println("Recv [1] done!"); } } }; // Listen to queue autoack: false manual receipt (message receipt channel.basicAck(envelope.getDeliveryTag(), false);) channel.basicConsume(QUEUE_NAME, false, consumer); } }Consumer 2: Recv2
public class Recv2 { public static final String EXCHANGE_NAME = "test_exchange_direct"; public static final String QUEUE_NAME = "test_queue_direct_2"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false,null); channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error"); channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "info"); channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "waring"); channel.basicQos(1); Consumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "utf-8"); System.out.println("Recv [2] msg = " + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally{ channel.basicAck(envelope.getDeliveryTag(), false); System.out.println("Recv [2] done!"); } } }; channel.basicConsume(QUEUE_NAME, false, consumer); } }
7.5.Topics
Topic exchange
Match route to a pattern
To match one or more characters
* match one character
For example: Goods#
Products: publish, delete, modify, query
producer
public class Send { public static final String EXCHANGE_NAME = "test_exchange_topic"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); // Claim switch channel.exchangeDeclare(EXCHANGE_NAME, "topic"); String message = "commodity..."; channel.basicPublish(EXCHANGE_NAME, "goods.delete", null, message.getBytes()); System.out.println("send message = " + message); channel.close(); connection.close(); } }
consumer:
public class Recv1 { public static final String EXCHANGE_NAME = "test_exchange_topic"; public static final String QUEUE_NAME = "test_queue_topic_1"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false,false,false,null); //Binding: channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.add"); channel.basicQos(1); //Defining consumers Consumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "utf-8"); System.out.println("[1] recv msg: " + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally{ System.out.println("[1] recv done!"); // Manual receipt channel.basicAck(envelope.getDeliveryTag(), false); } } }; // listen queue channel.basicConsume(QUEUE_NAME, false, consumer); } }
Consumer 2
public class Recv2 { public static final String EXCHANGE_NAME = "test_exchange_topic"; public static final String QUEUE_NAME = "test_queue_topic_2"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false,false,false,null); //Binding: channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.#"); channel.basicQos(1); //Defining consumers Consumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "utf-8"); System.out.println("[2] recv msg: " + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally{ System.out.println("[2] recv done!"); // Manual receipt channel.basicAck(envelope.getDeliveryTag(), false); } } }; // listen queue channel.basicConsume(QUEUE_NAME, false, consumer); } }
7.6 RPC manual and automatic message acknowledgment (message acknowledgment mechanism transaction - confirm)
In rabbitmq, we can solve the problem of abnormal data loss of rabbitmq server by persisting data
Question: after the producer sends the message, whether the message has arrived at the rabbitmq server or not is unknown by default
There are two ways:
AMQP implements transaction mechanism
confirm mode
Transaction mechanism:txSelect txCommit txRollback
txSelect: the user sets the current channel to transaction mode
txCommit: used to commit transactions
txRollback: rollback transaction
public class TxSend { public static final String QUEUE_NAME = "test_queue_tx"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); String msg = "hello tx message"; try{ // Open transaction channel.txSelect(); channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println(1/0); //Commit transaction channel.txCommit(); } catch(Exception e){ // Rollback transaction channel.txRollback(); System.out.println("send message txRollback"); } finally{ channel.close(); connection.close(); } }
consumer:
public class TxRecv { public static final String QUEUE_NAME="test_queue_tx"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); channel.basicConsume(QUEUE_NAME, true, new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "utf-8"); System.out.println("recv[tx] msg:" + msg); } }); } }
This mode is still time-consuming, which reduces the message throughput of Rabbitmq
Confirm mode
Implementation principle of producer mode
The producer sets the channel to confirm mode. Once the channel enters confirm mode, all messages published on the channel will be assigned a unique ID (starting from 1). Once the message is delivered to all matching queues, the broker sends an acknowledgement to the producer (containing the unique ID of the message). This enables the producer to know that the message has arrived at the destination queue correctly. If the message and queue are persistent, the acknowledgement message will be sent after the message is written to the disk. The delivery tag field of the acknowledgement message returned by the broker to the producer contains the serial number of the acknowledgement message. In addition, the broker can also set the basic.ack The multiple domain of. Indicates that all messages before this serial number have been processed.
The biggest advantage of Confirm mode is that it is asynchronous
Nack
Turn on confirm mode
channel.confirmSelect();
Programming mode:
1. General waitForCOnfirms()
- Send a batch of waitForConfirms in batch
- Asynchronous confirm mode: provides a callback
General confirm single general
send
/** * Normal mode */ public class Send1 { public static final String QUEUE_NAME = "test_queue_confirm1"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); // The producer calls confirm select to set chancel to confirm mode. Note (an exception will occur if the transaction mechanism is changed to this) channel.confirmSelect(); String msg = "hello confirm message"; channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("send message txRollback"); // Judge whether the transmission is successful if(!channel.waitForConfirms()){ System.out.println("message send failed"); } else { System.out.println("message send ok"); } channel.close(); connection.close(); } }
Send a batch of waitForConfirms in batch
/** * Batch mode */ public class Send2 { public static final String QUEUE_NAME = "test_queue_confirm2"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); // The producer calls confirm select to set chancel to confirm mode. Note (an exception will occur if the transaction mechanism is changed to this) channel.confirmSelect(); // Bulk send for (int i = 0; i < 10; i++) { String msg = "hello confirm message"; channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); } System.out.println("send message txRollback"); // Confirm whether it is sent successfully if(!channel.waitForConfirms()){ System.out.println("message send failed"); } else { System.out.println("message send ok"); } channel.close(); connection.close(); } }
Asynchronous mode
The ConfirmListener() callback method provided by the Channel object contains only deliveryTag (the sequence number of the message issued by the current Channel). We need to maintain an unconfirm message sequence number set for each Channel by ourselves. For each data publish ed, add 1 to the element in the set. Each time the handleAck method is called back, the unconfirm set deletes a corresponding (multiple=false) or multiple (multiple=true) record. From the perspective of program running efficiency, this unconfirm set is better to adopt the ordered set SortedSet storage structure.
producer:
/** * asynchronous */ public class Send3 { public static final String QUEUE_NAME = "test_queue_confirm3"; public static void main(String[] args) throws IOException, TimeoutException { Connection connection = ConnectionUtil.getConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false,false,false, null); // The producer calls confirm select to set the channel to confirm mode channel.confirmSelect(); // Store unconfirmed message ID final SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>()); // Monitor channel channel.addConfirmListener(new ConfirmListener(){ // No problem handleAck @Override public void handleAck(long deliveryTag, boolean multiple) throws IOException { if(multiple){ System.out.println("[handleAck]-----multiple true"); confirmSet.headSet(deliveryTag+1).clear(); } else { System.out.println("[handleAck]-----multiple false"); confirmSet.remove(deliveryTag); } } // handleNack has a problem @Override public void handleNack(long deliveryTag, boolean multiple) throws IOException { if(multiple){ System.out.println("[N]handleNack-----multiple"); confirmSet.headSet(deliveryTag + 1).clear(); } else { System.out.println("[N]handleNack-----multiple false"); confirmSet.remove(deliveryTag); } } }); String msgStr = "ssss"; while(true){ long seqNo = channel.getNextPublishSeqNo(); channel.basicPublish("", QUEUE_NAME, null, msgStr.getBytes()); confirmSet.add(seqNo); } } }
Message response and message persistence
Message responseboolean autoAck = false; //false manual receipt
channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);
boolean autoAck =true; (auto ack mode) once rabbitmq distributes the message to the consumer, it will be removed from memory
In this case: if the executing consumer is killed, the processing message will be lost.
boolean autoAck =false; (manual mode). If one consumer hangs up, it will be delivered to other consumers. Rabbitmq supports message response. The consumer sends a message response to tell rabbitmq that I have finished processing this message. You can delete it, and then rabbitmq will delete the message in memory.
Message response is on by default and false by default
Message acknowledgment:
If rabbitmq hangs, the message will still be lost
Message persistenceQueue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) throws IOException;
boolean durable = false;
channel.queueDeclare(QUEUE_NAME, false, false, false,null);
We can't change the boolean durable = false to true in the program. Even if the code is correct, it won't run successfully! Because we have defined a test_work_queue. This queue is persistent. rabbitmq does not allow redefining (different parameters) an existing queue
Exchange (switch forwarder)
On the one hand, it receives messages from producers, and on the other hand, it pushes messages to queues
open relay
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
String exchange: switch name
channel.basicPublish("", QUERE_NAME, null, message.getBytes());
Type:
fanout (do not process route key) Direct (process route key)Routing mode: