A. Distributed delay task
Traditional practice is to delay the task into the database, using the timing to scan, whether to match the task expires, and the set task is performed due to the completion status. This approach is also in a distributed environment require special handling (plus distributed lock) avoid the timing task is repeated for scanning.
However, the use RabbitMQ can achieve a natural delay task to solve the problem in distributed environments executed repeatedly (consumer will only be a consumer of this feature allows a delay task will be executed using the consumer mq message). Based on the core task delay RabbitMQ do it is to use the RabbitMQ message expiration forwarding feature. Set to send a message when the message expiration time, and so the message will expire when the message was not forwarded to the consumer a new queue, the queue of new customers receive the message and then processed using this delay time difference characteristics to achieve the task trigger .
II. RabbitMQ and set the delay to prepare the task used in the relevant queue
1. Install and erlang RabbitMQ (note erlang correspondence relationship with RabbitMQ version)
2. Openrabbitmq_management
Open RabbitMQ Command Prompt enter the command:rabbitmq-plugins enable rabbitmq_management
3. Create two Exchange
Create an Exchange add delay task, the following configuration
Exchange then create a task for receiving the expiration of the delay, the following configuration
4. Create two Queue
Create the first Queue, for adding the delay task, the following configuration
The above configuration creates a queue q1, setting a destination Exchange expiration message is transferred (DLX) and Route key (dlx_rk)
Next, configure Exchange q1 bound to ExQ1, Route key to send
Then create a second Queue, due to the receive queue q1 task is transferred, the following configuration
And bind to the Exchange: dlx, Route key: dlx_rk
Through the above two and two Exchange Queue configuration support make RabbitMQ message expiration q1 q2 is transferred to the rear. So we only use the service to send mission to delay q1, so that the task is triggered due to business code execution monitor (consumption) q2. So basically it enables the creation and expiration task scheduling in distributed environments delay trigger execution.
III. Specific code implementation
1. Create a simple maven project, add the following dependence
<dependencies> <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>5.7.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency> </dependencies>
2. The operation of the package used RabbitMQ
. 1 Import com.rabbitmq.client *. ; 2 . 3 Import java.io.IOException; . 4 Import java.util.concurrent.TimeoutException; . 5 . 6 / ** . 7 * 1. connection RabbitMQ . 8 * 2. A delay Task 9 * 3. consumption delay task 10 * / . 11 public class RabbitMQUtil { 12 is 13 is Private static connection Conn; 14 Private static Channel Channel; 15 16 / ** . 17 * initialize RabbitMQ connected to Channel 18 is * / 19 static { 20 ConnectionFactory factory = new ConnectionFactory(); 21 factory.setUsername("guest"); 22 factory.setPassword("guest"); 23 factory.setVirtualHost("/"); 24 factory.setHost("localhost"); 25 factory.setPort(5672); 26 27 try { 28 conn = factory.newConnection(); 29 channel = conn.createChannel(); 30 } catch (IOException e) { 31 System.out.println("获取RabbitMQ连接失败"); 32 } catch (TimeoutException e) { 33 System.out.println("获取RabbitMQ连接超时"); 34 } 35 } 36 37 // public static void close() throws IOException, TimeoutException { 38 // if (Objects.nonNull(channel)) 39 // channel.close(); 40 // if (Objects.nonNull(conn)) 41 // conn.close(); 42 // } 43 is 44 is / ** 45 * Key exchange sends a route specified delay task 46 is * @param MSG bytes delay task the JSON 47 * @param exchangeName 48 * @param routingKey 49 * @param expiration time delay 50 * / 51 is public static void addTask ( byte [] MSG, exchangeName String, String routingKey, int expiration) { 52 is the try { 53 is channel.basicPublish (exchangeName, routingKey, 54 is new newAMQP.BasicProperties.Builder () 55 .expiration (String.valueOf (expiration)) 56 is .build (), MSG); 57 is } the catch (IOException E) { 58 e.printStackTrace (); 59 } 60 } 61 is 62 is / * * 63 * message queue of the specified consumption (delay task) 64- * @param queueName 65 * @param Handler task processor 66 * @param consumerTag consumer label (multiple consumers simultaneously can use consumerTag distinguish the same message queue) 67 * / 68 public static void bindConsumer(String queueName, DemoTaskHandler handler, String consumerTag) { 69 try { 70 channel.basicConsume(queueName, false, consumerTag, 71 new DefaultConsumer(channel) { 72 @Override 73 public void handleDelivery(String consumerTag, 74 Envelope envelope, 75 AMQP.BasicProperties properties, 76 byte[] body) 77 throws IOException { 78 long deliveryTag = envelope.getDeliveryTag(); 79 // (process the message components here ...) 80 handler.execute(body, consumerTag); 81 channel.basicAck(deliveryTag, false); // 应答,告知queue成功收到消息 82 } 83 }); 84 } catch (IOException e) { 85 e.printStackTrace(); 86 } 87 } 88 89 }
3. Analog Delay Task POJO
1 import java.io.Serializable; 2 3 public class DemoTask implements Serializable { 4 5 private int id; 6 7 public int getId() { 8 return id; 9 } 10 11 public void setId(int id) { 12 this.id = id; 13 } 14 }
4. Delay Task Processor
. 1 Import com.alibaba.fastjson.JSON; 2 . 3 public class DemoTaskHandler { . 4 . 5 public void Execute ( byte [] body, String consumerTag) { . 6 DemoTask Task JSON.parseObject = ( new new String (body), DemoTask. Class ); . 7 System.out.println (consumerTag + "receive delay task id:" + task.getId () + " and processed" ); 8 } 9 }
5. Design a main delay queue to send to the task q1
. 1 Import com.alibaba.fastjson.JSON; 2 . 3 Import java.util.Scanner; . 4 . 5 public class Producer { . 6 . 7 public static void main (String [] args) { . 8 // add delay task . 9 the System.out. println ( "A delay press the keyboard task" ); 10 Scanner SC = new new Scanner (the System.in); . 11 int I =. 1 ; 12 is the while (sc.hasNextLine ()) { 13 is sc.nextLine (); 14 DemoTask bo =new new DemoTask (); 15 bo.setId (I ++ ); 16 RabbitMQUtil.addTask (JSON.toJSONString (BO) .getBytes (), . 17 "ExQ1" , 18 is "Send" , . 19 10000 ); 20 is System.out.println ( "successfully added a task delay" ); 21 } 22 } 23 is 24 }
6. Create two consumers (processing delay the task of business) consumption delay task, distributed simulation environment
. 1 public class Consumer1 { 2 . 3 public static void main (String [] args) { . 4 // simulate a distributed environment, the processing delay due tasks . 5 RabbitMQUtil.bindConsumer ( "Q2" , . 6 new new DemoTaskHandler (), . 7 " consumer1 " ); . 8 . 9 } 10 . 11 }
. 1 public class Consumer2 { 2 . 3 public static void main (String [] args) { . 4 // simulate a distributed environment, the processing delay due tasks . 5 RabbitMQUtil.bindConsumer ( "Q2" , . 6 new new DemoTaskHandler (), . 7 " consumer2 " ); . 8 } . 9 }
7. Run Producer, Consumer1, Consumer2 observations
The observation that, after a delay of each transmission job, will be 10 seconds or consumer2 consumer1 consumption, more basically a distributed scheduling delay.