Application of RabbitMQ in practical projects
Business scenario
explain:
For some reasons, the specific business is not explained. The general business scenario is that module A will send A message to module B, and module B will update the local cache encache And module B is A cluster deployment in the project.
Switch selection:
1. fanout will route messages on all switches to all queues bound with the switch, and BindingKey is not required to take effect
2. direct: it routes the message to a queue whose BindingKey exactly matches the RoutingKey.
3. topic: it is an extension of direct. It also uses RoutingKey and BindingKey to match, but the matching rules are different. It supports fuzzy matching. There are the following rules
-
-
- RoutingKey is a dot "." Separated string, each separated independent string is a word, which is the matching unit;
- BindingKey, like RoutingKey, is also "." Split string;
- But the difference is that BindingKey can use "#" and "" for fuzzy matching similar to placeholders, "#" represents one word and "" represents multiple words (or zero)
-
4. Headers: match by relying on the headers attribute in the sending message content. Specify a set of key value pairs when binding the queue and the switch. Here is headers. When sending a message to the switch, RabbitMQ will get the headers of the message and route it to the relevant queue through comparison. This switch has poor performance and is generally not used.
The above is the switch type. According to this scenario, we will generally consider using fanout (or direct)
See the figure below for details:
Illustration
realization
It is explained here that spring boot integrates rabbitmq and uses the direct model switch to realize the business scenario and show the code of consumers
pom.xml add dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
application.proerties adding switch and routing configurations
rabbitmq.admin.exchange=admin.billinfo rabbitmq.admin.routingkey=admin.billinfo
Add RabbitmqConfig class
@Configuration public class RabbitMqConfig { private final Logger logger = LoggerFactory.getLogger(RabbitMqConfig.class); @Value("${rabbitmq.admin.exchange}") String adminExchange; @Value("${rabbitmq.admin.routingkey}") String adminRouteKey; @Value("${stationno}") public Integer stationno;//Site number //Queue naming and switch naming @Bean public Queue AdminQueue() { return new Queue("admin.billinfo"+station,true); //Whether true is persistent } @Bean DirectExchange AdminQueueExchange() { return new DirectExchange(adminExchange==null?"admin.billinfo":adminExchange.trim()); } //Switch and queue binding @Bean Binding bangdingDirect() { return BindingBuilder.bind(AdminQueue()).to(AdminQueueExchange()).with(adminRouteKey==null?"":adminRouteKey.trim()); } }
Message consumer
@Component @RabbitListener(queues = "admin.billinfo")//Name of queue listening public class CacheReceiver { private final Logger logger = LoggerFactory.getLogger(DirectReceiver.class); @Autowired PredictPoolMemory predictPoolMemory; @Autowired PreviewPoolMemory previewPoolMemory; @Autowired AgentPoolMemory agentPoolMemory; @Autowired PredictNumberPoolDao predictNumberPoolDao; @Autowired PreviewNumberPoolDao previewNumberPoolDao; @Autowired AgentNumberPoolDao agentNumberPoolDao; @Autowired JobCache jobCache; //Received message @RabbitHandler public void process(String billInfoMessage){ logger.info("adminbillinfo:{}",billInfoMessage); JSONObject jsonobj = JSON.parseObject(billInfoMessage); String cmd = jsonobj.getString("cmd"); int type = jsonobj.getIntValue("type"); int companyid = jsonobj.getIntValue("companyid"); //Modify enterprise information if ("updatecompanyinfo".equals(cmd)){ try { predictPoolMemory.addAll(); } catch (Exception e) { logger.error("Exception:{}"+e.getMessage(),e); } try { previewPoolMemory.addAll(); } catch (Exception e) { logger.error("Exception:{}"+e.getMessage(),e); } try { agentPoolMemory.addAll(); } catch (Exception e) { logger.error("Exception:{}"+e.getMessage(),e); } try{ jobCache.initCache(); }catch (Exception e){ logger.error("Exception{}"+e.getMessage(),e); } } }
Solution to the problem of message backlog in online mq
The mq automatic confirmation mode acknowledge = auto, without exception handling, will cause mq consumers to consume abnormally, and the messages will return to the queue, resulting in message backlog
Configuration can be added
# Enable ACK no confirmation mode spring.rabbitmq.listener.direct.acknowledge-mode=none spring.rabbitmq.listener.simple.acknowledge-mode=none
In addition to NONE and MANUAL, the acknowledge mode also has AUTO. It will decide whether to confirm or reject (whether to re-enter the queue) according to the execution of the method
-
If the message is successfully consumed (success means that no exception is thrown in the process of consumption), it is automatically confirmed
-
When the AmqpRejectAndDontRequeueException exception is thrown, the message will be rejected and request = false (do not re-enter the queue)
-
When the ImmediateAcknowledgeAmqpException exception is thrown, the consumer will be confirmed
-
For other exceptions, the message will be rejected and request = true (if only one consumer listens to the queue at this time, there is a risk of life and death cycle, and multiple consumers will also cause a great waste of resources, which must be avoided in the development process). You can set it through setDefaultRequeueRejected (the default is true)
Detailed online mq troubleshooting, please pay attention to official account: gentlemen and hooligans.