MQ消息队列
references:
什么是MQ
消息队列(MQ)是一种不同应用程序之间(跨进程)的通信方法。
应用程序通过写入和检索出入列队的数据(消息)来通信,而无需通过专用连接来链接它们。
消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用(Remote Procedure Call. RPC)的技术。
排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求,这样就天然地实现了异步的目标
为什么要用MQ?
-
异步处理 - 增加吞吐量;
-
削峰填谷 - 提高系统稳定性;
-
系统解耦 - 业务边界隔离;
-
数据同步 - 最终一致性保证。
MQ的优缺点
异步、解耦、消峰填谷这是消息队列最大的优点,除了这些消息队列还可以会解决一些我们特殊业务场景的问题。但是缺点主要在于系统的可用性、复杂性、一致性问题,引入消息队列后,需要考虑MQ的可用性,万一MQ崩溃了岂不是要爆炸?而且复杂性明显提高了,需要考虑一些消息队列的常见问题和解决方案,还有就是一致性问题,一条消息由多个消费者消费,万一有一个消费者消费失败了,就会导致数据不一致。
有哪几种
- 从处理业务的范围来看
应用内部 - 采用线程池,比如 Java ThreadPool 中 BlockingQueue 来做任务级别的缓冲与处理;
应用外部 - 比如 RabbitMQ、ActiveMQ 就是做应用级别的队列,方便进行业务边界隔离与提高吞吐量。
- 从技术上来看
-
Pull 模型:消费者主动请求消息队列,获取队列中的消息;
-
Push 模型:消息队列主动推送消息到消费者。
其中 Pull 模式可以控制消费速度,不必担心自己处理不了消息,只需要维护队列中偏移量 Offset。所以对于消费量有限并且推送到队列的生产者不均匀的情况下,采用 Pull 模式比较合适。
Push 比较适合实时性要求比较高的情况,只要生产者消息发送到消息队列中,队列就会主动 Push 消息到消费者。不过这种模式对消费者的能力要求就提高很多,如果出现队列给消费者推送一些不能处理的消息,消费者出现 Exception 情况下,就会再次入队列,造成消费堵塞的情况。
不过互联网业界比较成熟的队列主要以采用 Pull 模式为主,像 Kafka、RabbitMQ(两种方式都支持)、RocketMQ 等。
幂等性
什么是幂等性
一次请求和多个请求的作用是一样的。用数学上的术语,即是 f(x) = f(f(x))。
为什么要有幂等性设计
现在的系统多是采用分布式的方式来设计,在分布式系统中调用一般分为 3 个状态:成功、失败、超时。
怎么设计
-
请求方一般会生产一个唯一性 ID 标识,这个标识可以具有业务一样,比如订单号或者支付流水号,在发起请求时候带上唯一性 ID;
-
接收者在收到请求后,第一步通过获取唯一性 ID 来查询接收端是否有对应的记录。如果有的话,就直接将上次请求的结果返回;如果没有的话,就进行操作,并在操作完成后记录到对应的表里。
削峰填谷
以订单系统和结算系统场景为例,如果订单系统通过RPC框架来调用结算系统,在有高峰促销的情况下生成订单的量会非常大,而且由于生成订单的速度也非常快,这样势必会给结算系统造成系统压力,服务器利用率则会偏高,但在不是高峰的时间点订单量比较小,结算系统的服务器利用率则会偏低
对于结算系统来说就会出现下面这样的高峰波谷现象图。
那么如果通过MQ的方式,将订单存储到MQ队列中,消费端通过拉取的方式,并且拉去速度有消费端来控制,则就可以控制流量趋于平稳。这样对于结算系统来讲,就达到了削峰填谷的目的,或者说起到了流控的目标。接下来,我们介绍一下拉取方式。
拉取模式指用户在代码里主动调用pull方法,不需要在配置文件里面再配置<mq:listener />,拉取的速度由用户控制,调用一次拉取一次消息进行消费,这里要重视消费的速度如果消费性能下降一定会造成积压,因此用户自己启用多线程控制并行度以提高消费速度。
与监听模式的区别是:监听模式由MQ客户端守护线程去不停地拉取消息进行消费,拉取模式由用户控制拉取的频率,不主动调用就不会消费消息。
但是都不需要主动对消息进行确认。这种方式更适合写场景,保证最终结果落地即可,因为读是需要立即返回以免让用户长时间等待从而影响用户体验。
解耦
MQ最直接的使用场景就是可以将两个系统进行解耦,比如我们的货款抵扣业务场景,用户生成订单发送MQ后立即返回,结算系统去消费该MQ进行用户账户金额的扣款。这样订单系统只需要关注把订单创建成功,最大可能的提高订单量,并且生成订单后立即返回用户。
而结算系统重点关心的是账户金额的扣减,保证账户金额最终一致。这个场景里面还会涉及到重试幂等性问题
服务降级
服务降级主要解决资源不足和访问量过大的问题,比如电商平台在 618、双十一等高峰时期采用部分服务不提供访问,减少对系统的影响。
降级的方式有哪些?
-
延迟服务:比如春晚,微信发红包就出现抢到红包,但是账号余额并没有增加,要过几天才能加上去。其实这是微信内部采用延迟服务的方式来保证服务的稳定,通过队列实现记录流水账单;
-
功能降级:停止不重要的功能是非常有用的方式,把相对不重要的功能暂停掉,让系统释放更多的资源。比如关闭相关文章的推荐、用户的评论功能等等,等高峰过去之后,在把服务恢复回来;
-
降低数据一致性:在大促的时候,我们发现页面上不显示真实库存的数据,只显示到底有还是没有库存这两种状态。
降级的注意点
清晰定义降级级别: 比如出现吞吐量超过 X,单位时间内响应时间超过 Y 秒、失败次数超过 Z 次等,这些阈值需要在准备的时候,通过压测的方式来确定;
梳理业务级别:降级之前,首先需要确定哪些业务是必须有,哪些业务是可以有的,哪些业务是可有可无的;
降级开关:可以通过接入配置中心(比如携程 Apollo、百度 Disconf )的方式直接后台降级。但是如果公司没有配置中心的话,可以封装一个 API 接口来切分,不过该 API 接口要做成幂等的方式,同时需要做一些简单的签名,来保证其一定的安全性
=====> 更多可以参考references
关于QPS TPS 的理解
并发数
并发数是指系统同时能处理的请求数量,这个也是反应了系统的负载能力
吞吐量
吞吐量是指单位时间内系统能处理的请求数量,体现系统处理请求的能力,这是目前最常用的性能测试指标
响应时间RT(Response-time)
响应时间是一个系统最重要的指标之一,它的数值大小直接反应了系统的快慢。响应时间是指执行一个请求从开始到最后收到响应数据所花费的总体时间,即从客户端发起请求到收到服务器响应结果的时间
QPS(Queries Per Second)
是每秒查询率,是一台服务器每秒能够相应的查询次数,即1秒内完成的请求数量,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准
TPS(TransactionsPerSecond)
也就是事物数/秒。它是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数
Qps基本类似于Tps,但是不同的是,对于一个页面的一次访问,形成一个Tps;但一次页面请求,可能产生多次对服务器的请求,服务器对这些请求,就可计入“Qps”之中
例:访问一个页面会请求服务器3次,一次返回,产生一个“T”,产生3个“Q”
之间的计算关系:
QPS = 并发量 / 平均响应时间
并发量 = QPS * 平均响应时间
注意:
对同一个系统而言,支持的线程数越多,QPS越高
最佳线程数量
刚好消耗完服务器的瓶颈资源的临界线程数,公式如下:
最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间)* cpu数量
特性:
1.在达到最佳线程数的时候,线程数量继续递增,则QPS不变,而响应时间变长,持续递增线程数量,则QPS开始下降
2.每个系统都有其最佳线程数量,但是不同状态下,最佳线程数量是会变化的
3.瓶颈资源可以是CPU,可以是内存,可以是锁资源,IO资源
超过最佳线程数目:
超过最佳线程数-导致资源的竞争
超过最佳线程数-响应时间递增
QPS和响应时间的关系:
对于大部分web系统,响应时间一般由++CPU执行时间++,++线程等待时间++(IO等待,sleep, wait)时间组成。QPS和RT成反比关系。