在当前互联网爆发的时代,很多互联网应用程序时刻都将面对高并发问题。当应用程序在高并的发情况下,由于后端服务来不及同步处理,请求往往会发生堵塞,比如大量的:insert(插入)、update(更新)之类的请求同时到达数据库,直接导致无数的行锁、表锁,甚至最后请求会堆积很多,从而触发大量的 “too mang connnections” 错误。
因此,为了解决上面问题,很多互联网应用程序都引入了消息队列MQ。消息队列(MQ)可以异步处理请求,从而缓解系统的压力。MQ(message queue)是一种跨进程的通信机制,用于上下游传递消息。
不能先进先出,都不能说是队列了,消息队列的顺序在入队时基本已经确定,一般是不需要人工干预的。而且最重要的是,数据是只有一条数据在使用中,这也是mq在众多场景中被使用的原因。
发布订阅是一种很高效的处理方式,如果不发生阻塞,基本可以当做是同步操作。这种处理方式能非常有效的提升服务器利用率,这样的应用场景非常广泛。
持久化确保MQ的使用不只是一个部分场景的辅助工具,而是让MQ能像数据库一样存储核心的数据。
在现在大流量、大数据的使用场景下,只支持单体应用的服务器软件基本是无法使用的,支持分布式的部署,才能被广泛使用。而且,MQ的定位就是一个高性能的中间件。
基于上文所述的 MQ 特点,那么 MQ 就衍生出了很多的使用场景,在大型的系统中,应用非常广泛,这里我们就列举一下常见的应用场景。
系统之间进行数据交互时,在时效性和稳定性之间我们都要进行选择;基于线程的异步处理,能确保用户体验,但在极端情况下,可能会出现异常,影响系统的稳定性,而同步调用很多时候无法保证理想的性能,那么我们就可以用 MQ 来进行处理,上游系统将数据投递到 MQ,下游系统取 MQ 的数据进行消费,投递和消费可以用同步的方式处理,因为 MQ 接收数据的性能是非常高的,不会影响上游系统的性能,那么下游系统的及时率能保证吗?当然可以,不然就不会有下面的一个应用场景。
发布订阅,下游系统一直在监听 MQ 的数据,如果 MQ 有数据,下游系统则会按照先进先出这样的规则,逐条进行消费,而上游系统只需要将数据存入 MQ 里,这样既降低了不同系统之间的耦合度,同时也确保了消息通知的及时性,而且也不影响上游系统的性能。
上文有说了一个非常重要的特性,MQ 数据是只有一条数据在使用中。 在很多存在并发,而又对数据一致性要求高,而且对性能要求也高的场景,如何保证,那么MQ就能起这个作用了。不管多少流量进来,MQ都会让你遵守规则,排除处理,不会因为其他原因,导致并发的问题,而出现很多意想不到脏数据。
MQ的发布订阅肯定不是只是简单的一对一,一个上游和一个下游的关系,MQ中间件基本都是支持一对多或者广播的模式,而且都可以根据规则选择分发的对象。这样上游的一份数据,众多下游系统中,可以根据规则选择是否接收这些数据,这样扩展性就很强了。
PS:上文中的上游和下游,在MQ更多的是叫做生产者(producer)和消费者(consumer)
分布式事务是我们开发中一直尽量避免的一个技术点,但是,现在越来越多的系统是基于微服务架构开发,那么分布式事务成为必须要面对的难题,解决分布式事务有一个比较容易理解的方案,就是二次提交。基于MQ的特点,MQ作为二次提交的中间节点,负责存储请求数据,在失败的情况可以进行多次尝试,或者基于MQ中的队列数据进行回滚操作,是一个既能保证性能,又能保证业务一致性的方案,当然,这个方案的主要问题就是定制化较多,有一定的开发工作量。
为了更加直观的展示 MQ 的应用场景,这里我们就用一个常见的电商系统中的几个业务,来具体说明下 MQ 在实际开发中应用场景。
我们的实际场景大概是一个基于微服务架构的电商系统,分为用户微服务、商品微服务、订单微服务、促销微服务等。基于微服务模式开发的系统,MQ 的使用场景更多,下面我们逐一说明:
(1)注册后我们可能需要做很多初始化的操作,如:调用邮件服务器发送邮件、调用促销服务赠送优惠劵、下发用户数据到客户关系系统等。那么这时候我们将这些操作去监听MQ,当用户注册成功过后,通过MQ通知其他业务进行操作。确保注册用户的性能。
(2)后台发布商品的时候,商品数据需要从数据库中转换成搜索引擎数据(基于elasticsearch),那么我们应该将商品写入数据库后,再写入到MQ,然后通过监听MQ来生成elasticsearch对应的数据。
(3)用户下单后,24小时未支付,需要取消订单。以前我们可能是定时任务循环查询,然后取消订单。实际上,我更推荐类似延迟MQ的方式,避免了很多无效的数据库查询,将一个MQ设置为24小时后才让消费者消费掉,这样很大程度上能减轻服务器压力。
(4)支付完成后,需要及时的通知子系统(进销存系统发货,用户服务积分,发送短信)进行下一步操作,但是,支付回调我们都是需要保证高性能的,所以,我应该直接修改数据库状态,存入MQ,让MQ通知子系统做其他非实时的业务操作。这样能保证核心业务的高效及时。