一,消息队列的好处
1,异步
对于异步,举个例子,例如购物下单,如果为同步操作,我们需要下单、减免优惠券、发送短信等等功能,如果不进行处理,那么购买一个物品可能需要十几秒,对于电商系统来说肯定是一个致命的问题,所以,我们需要消息队列来解决这个问题。
我们下单成功之后,可以让剩余的操作异步进行,在减免优惠的同时,给用户发送短信。这样就可以使的购物时间大大减小。
2,解耦
只需要将下单的id传入消息队列之中即可,如果后续功能需要id数据,直接在消息队列之中取即可,无需和下单功能发送请求,同时,其它功能是否成功也不影响另外的功能的运行,这样,所有的功能都解耦了。
3,流量削峰
例如,秒杀系统,某一时刻可能有5000条请求,但是只能处理3000条请求,如果我们不做处理,服务器、数据库、redis承受压力超过自身极限,那肯定会挂掉。
可以使用消息队列来处理,将请求放在消息队列之中,让机器去消息队列之中取自己可以承受的请求数就行,这样可能会使有些用户访问变慢,或者降级,但是起码不会挂掉,等到流量下去,就会恢复正常。
二,消息队列使用场景
1,对于数据量大或者处理时间长的系统,可以使用消息队列的异步优点来解决
2,对于功能模块多,后续还可能需要增加的系统,可以使用消息队列来进行解耦的操作
3,对于秒杀系统,消息队列的流量削峰优点也是必不可少的
三,消息队列的缺点
1,系统复杂性
由于消息队列是一个中间件,我们需要对其进行维护,而且还需要考虑重复消费,消息丢失,消息的顺序消费等问题
2,数据一致性
例如下单服务成功,但是你并不知道其他功能是否成功,如果优惠券并没有扣去,系统就是有问题的,所有的功能都成功才可以称这次下单成功。
3,可用性
虽然消息队列对系统进行解耦,但是消息队列挂掉怎么办,这样就会导致下单服务之后的功能出现问题。
四,解决消息队列的问题
1,系统复杂性
解决重复消费问题:
重复消费:例如根据用户的消费额度来进行奖励,在一个业务流程的下游出现问题的时候,会抛出异常,需要重新发送一次,由于业务很多,其他的业务也会监听,这样就会导致重复增加消费总额。
对于重复消费我们可以使用幂等函数,幂等函数就是使用相同参数重复执行,并能获得相同结果的函数。setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的。
一般情况下 MQ 是允许存在多条一样的数据的,只是消费端就不允许消费两条一样的数据,所以幂等性保障通常都是在消费者端实现。
具体的方法:
- 状态判断法:消费者消费数据后把消费数据记录在 redis 中,下次消费时先到 redis 中查看是否存在该消息,存在则表示消息已经消费过,直接丢弃消息。
- 业务判断法:通常数据消费后都需要插入到数据库中,使用数据库的唯一性约束防止重复消费。每次消费直接尝试插入数据,如果提示唯一性字段重复,则直接丢失消息。一般都是通过这个业务判断的方法就可以简单高效地避免消息的重复处理了。
2,数据一致性
-
事务机制(影响性能)
一些MQ系统支持事务机制,可以将一系列操作包装在一个事务中。只有当所有操作都成功时,事务才会提交,否则将被回滚。这可以确保消息的完整性和一致性。
-
异步机制
-
异步消息发送:将消息发送操作设计成异步的,即发送消息后不等待返回结果,而是继续执行后续的操作。这样能够提高发送消息的效率,避免由于等待返回结果而导致的延迟或阻塞。
-
异步消息处理:在接收到消息后,将消息的处理过程设计成异步的,即将消息交给后台线程或线程池进行处理,而不是在接收线程中直接处理。这样可以避免消息接收线程被阻塞或延迟,提高系统的吞吐量和响应速度。
-
异步消息确认:在消息处理完成后,异步地发送确认消息给MQ,表示消息已经成功处理。这样可以避免在消息处理过程中发生异常或故障时造成消息的丢失。
3,可用性
我们知道消息队列挂掉的后果是非常严重的,所以我们可以在多台机器上部署消息队列,需要集群/分布式。