SAAS技术交流系列(一) - 消息队列

一、  消息队列的概念

消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。目前在生产环境,使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等。


二、 消息队列的应用场景

常用的使用场景。异步处理,应用解耦,流量削锋和消息通讯。

1、异步处理

场景说明: 用户注册后,需要发注册邮件和注册短信。传统的做法有两种1.串行的方式;2.并行方式。

(1)串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。

(2)并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。

小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?引入消息队列,将不是必须的业务逻辑,异步处理。


2、应用解耦

场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口

传统模式的缺点:

1)假如库存系统无法访问,则订单减库存将失败,从而导致订单失败;

2)订单系统与库存系统耦合;

l  订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。

l  库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。

l  假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。


3、流量削峰

流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。

应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。

l  可以控制活动的人数;

l  可以缓解短时间内高流量压垮应用;

l 用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面;

l  秒杀业务根据消息队列中的请求信息,再做后续处理。


4、日志处理

日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。

l  日志采集客户端,负责日志数据采集,定时写受写入Kafka队列;

l  Kafka消息队列,负责日志数据的接收,存储和转发;

l  日志处理应用:订阅并消费kafka队列中的日志数据;

新浪kafka日志处理应用案例:

(1)Kafka:接收用户日志的消息队列。

(2)Logstash:做日志解析,统一成JSON输出给Elasticsearch。

(3)Elasticsearch:实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能。

(4)Kibana:基于Elasticsearch的数据可视化组件,超强的数据可视化能力是众多公司选择ELKstack的重要原因。

 

5、消息通讯

消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

 

三、 消息模型

1、P2P模式

P2P模式包含三个角色:消息队列(Queue),发送者(Sender),接收者(Receiver)。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。

P2P的特点:

l  每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)

l  发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列

l  接收者在成功接收消息之后需向队列应答成功

如果希望发送的每个消息都会被成功处理的话,那么需要P2P模式。

 

2、Pub / Sub模式

包含三个角色主题(Topic),发布者(Publisher),订阅者(Subscriber) 。多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。

Pub/Sub的特点:

l  每个消息可以有多个消费者

l  发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息。

l  为了消费消息,订阅者必须保持运行的状态。

为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。

如果希望发送的消息可以不被做任何处理、或者只被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型。

 

四、 RabbitMQ消息队列

RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP(高级消息队列协议)的标准实现。支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

 

几个重要概念:

Broker:简单来说就是消息队列服务器实体。

Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。

Queue:消息队列载体,每个消息都会被投入到一个或多个队列。

Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。

Routing Key:路由关键字,exchange根据这个关键字进行消息投递。

vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。

producer:消息生产者,就是投递消息的程序。

consumer:消息消费者,就是接受消息的程序。

channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。

消息队列的使用过程,如下:

(1)客户端连接到消息队列服务器,打开一个channel。

(2)客户端声明一个exchange,并设置相关属性。

(3)客户端声明一个queue,并设置相关属性。

(4)客户端使用routing key,在exchange和queue之间建立好绑定关系。

(5)客户端投递消息到exchange。

exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

 

五、 RabbitMQ与Redis作为消息队列的区别

1、RabbitMQ

RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。

2、Redis

Redis是一个Key-Value的NoSQL数据库,开发维护很活跃,虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。

3、具体对比

1) 可靠消费

Redis:没有相应的机制保证消息的消费,当消费者消费失败的时候,消息体丢失,需要手动处理。

RabbitMQ:具有消息消费确认,即使消费者消费失败,也会自动使消息体返回原队列,同时可全程持久化,保证消息体被正确消费。

2) 可靠发布

Reids:不提供,需自行实现。

RabbitMQ:具有发布确认功能,保证消息被发布到服务器。

3)  高可用

Redis:采用主从模式,读写分离,但是故障转移还没有非常完善的官方解决方案。

RabbitMQ:集群采用磁盘、内存节点,任意单点故障都不会影响整个队列的操作。

4)  持久化

Redis:将整个Redis实例持久化到磁盘。

RabbitMQ:队列,消息,都可以选择是否持久化。

5)  消费者负载均衡

Redis:不提供,需自行实现。

RabbitMQ:根据消费者情况,进行消息的均衡分发。

6) 队列监控

Redis:不提供,需自行实现。

RabbitMQ:后台可以监控某个队列的所有信息,(内存,磁盘,消费者,生产者,速率等)。

7) 流量控制

Redis:不提供,需自行实现。

RabbitMQ:服务器过载的情况,对生产者速率会进行限制,保证服务可靠性。

8) 出入队性能

对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。

 

六、小结

      对于那些实时性要求不高,且比较耗时的任务,是队列的最佳应用场景。比如说在某网站注册一个账号,当我的信息入库注册成功后,网站需要发送一封激活邮件,激活账号,而这个发邮件的操作并不是需要实时响应的,没有必要卡在那个注册界面,等待邮件发送成功,再说发送邮件本来就是一个耗时的操作(需要调用第三方smtp服务器),此时,选择消息队列去处理。注册完成,只需要向队列投递一个消息,消息的内容中包含我要发送邮件的一些设置,以及发送时间,重试次数等消息属性。这里的投递操作(可以是入库,写入缓存等)是要消息进入一个实体的队列。其中应该有一进程(消费者)一直在后台运行,他不断的去轮训队列中的消息(按照时间正序,队列是先进先出),看有没有达到执行条件的,如果有就取出一条,根据消息配置,执行任务,如果成功,则销毁这条消息,继续轮训,如果失败,则重试,知道达到重试次数。这时用户已经收到注册成功的提示,但是已经去做其他事了,邮件也来了,用户点击邮件,注册成功。这就是消息队列的一个典型应用。
       点赞场景,这个在高并发的情况下,很容易造成数据库连接数占满,到时整个网站响应缓慢,才是就是想到要解决数据库的压力问题,一般就是两种方案,一是提高数据库本身的能力(如增加连接数,读写分离等),但是数据库总是有极限的,到达了极限无法再提升了,此时就要考虑第二种方案,释放数据库的压力,将压力转移到缓存里面。就拿实际的点赞来说吧,用户的点赞请求到来,可以将点赞请求投递到消息队列里面,后续的点赞请求可以将消息合并,即只更新点赞数,不产生新的任务,此时有个进程不断的轮训消息队列,将点赞消息消耗,并将值更新到数据库里面,这样就有效的降低了数据库的压力,因为在缓存层将数个数据库更新请求合并成一个,大大提高了效率,降低了负载。

    无论哪种消息队列都需要依据实际的业务来进行合理的选型,才能实现更好地效果。


七、参考文章

http://blog.csdn.net/shaobingj126/article/details/50585035 大型网站架构之分布式消息队列

http://www.cnblogs.com/wanpengcoder/p/5291627.html RabbitMQ消息队列(三):发布 / 订阅

http://blog.csdn.net/shudaqi2010/article/details/53639628 Redis作为消息队列与RabbitMQ的性能对比

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值