RabbitMQ, Kafka和Pulsar (一)

因为要引入Notification机制和log的监控和查看,大概率是需要MQ这类工具,所以研究了下目前比较火热的开源的MQ软件:

Rabbit MQ, Kafka还有Pulsar.

其实这三个软件虽说都适合MQ的场景,但是其实侧重点有很大的不同.

RabbitMQ: 是AMQP(Advance Message Queuing protocol)的实现,是典型的消息中间件产品。它的特点是富broker端,傻消费者,并且对消息路由支持的很好。

缺点是消息存储功能弱,在RabbitMQ中存储大量的消息是个典型的反模式,相应的,也不支持消息的回看。

RabbitMQ, Kafka和Pulsar (一)_第1张图片

Kafka: 不是典型的消息中间件产品,其实更像是流数据处理软件,但是pub-sub或者queue也能实现。特点是刹broker端,富消费者。优点是带数据存储的功能,支持消息回看,并且由Kafka stream用于在Topic之间进行数据的二次处理。缺点是消息路由功能弱。另外还要引入zookeeper。

RabbitMQ, Kafka和Pulsar (一)_第2张图片

Pulsar: 非常新,好像去年才进入Apach顶级项目的,目的是取代Kafka, Kafka支持的它全都支持,并且多了一个概念叫Subscription,增加了几种模式,比如独占,failover还有共享。我觉得,如果subscription能支持消息过滤,就在一定程度上实现了消息路由,目前还不支持这个功能,比较遗憾, https://github.com/apache/pulsar/issues/3302。它缺点也很明显,新玩家,在google上很难找到问题解答和有价值的讨论,但是我还是比较喜欢这个项目,java写的。

RabbitMQ, Kafka和Pulsar (一)_第3张图片

当然,他们都支持扩展,高吞吐,分布式部署等等高可用方面的功能,这个不是本文的重点。

本文想基于一个真实的案例,分别用RabbitMQ, Kafka和Pulsar进行设计,来观察他们的异同。

案例:

有两个主要的需求:

  1. Notification, 希望client端(GUI)能直接使用Websocket接口和MQ通信,并且client端只能获取到跟在client端登录的用户相关的消息(不能是把所有消息都介入到client然后再做过滤)。
  2. Log,要支持log的回看以及log的trace

这样看起来好像对RabbitMQ不是太公平,因为天生不支持消息存储,更不要说回看了,没关系,我们一步一步来,且看它能支持到多少。

RabbitMQ

之前提到RabbitMQ对消息路由支持的很好,所以对第一个需求能很好的满足。

RabbitMQ有几个概念:

  • Producer: 消息生产者
  • Exchange:交换器
  • queue:队列
  • Consumer: 消息消费者

基本流程是Producer产生消息并发往Exchange, Exchange其实是个路由器,负责将消息路由到不同的queue中,而consumer则从queue中取走消息。

Exchange和queue之前是通过一个叫做binding的东西联系到一起的,bind的时候会有一个参数:binding key,这很关键,它和Exchange的路由方式一起决定了message的走向。

RabbitMQ, Kafka和Pulsar (一)_第4张图片

上面第一个代码块生成了一个Exchange,注意”exchange_type“, 在RabbitMQ中,有四种exchange_type:

  • fanout: 无视”router key“,把每一个消息无差别的路由到每一个binding到它上的queue
  • direct:将message路由到router key跟message完全匹配的queue
  • topic: 这种类型的Exchange对router key有格式上的要求:xxx.xxx.xxxxx, 而binding时候queue提供的router key可以包含通配符,如:*(匹配一个字符), #(匹配0或者多个字符)。规则是一样的,Exchange会吧message路由到所有匹配的queue
  • Headers: 这种类型会无视router key了,转而用一个message中的数组参数:headers,在binding的时候queue要指定路由的规则。比如message中headers长这样:{type: error, from: security}, bing的时候指定可以指定”type = error or from = security“或者”type = error and from = security“。这样的多条件组合基本上可以搞定任何复杂的路由规则。

好的,言归正传,我们基于RabbitMQ看看我们的需求:

  1. 基于client logon的消息通知。
    这个需求是希望user登录client之后会从MQ得到并仅仅得到这个user权限允许的message,这个filter/router要在server(MQ或者后台service)端就完成。
    在RabbitMQ晚上router机制的支持下,这个还是很容易满足的:
    a. 建立一个direct类型的Exchange,Message中的router key是”user_id“, 则Exchange会将router key匹配的消息路由到相应的 queue中。但是因为user众多,不会在开始就为所有的user建立queue, 当Exchange发现要路由到的queue不存在,就会对消息做丢弃处理。
    b. User登录后通知后台service,service会在RabbitMQ上为该用户建立专用的queue,这样Exchange就开始向改queue路由消息,不再丢弃。
    c. Client建立跟它专用的queue的连接,开始接受消息
    d. 当User登出或者session过期,跟queue的连接中断以后,queue会根据RabbitMQ中”auto-delete“的配置自动销毁。
    这就满足了第一个需求,很完美。
  2. Log的回看和trace
    这个就难度大发了,基本上不是RabbitMQ的使用场景,如果必须用它,就得引入一个DB之类的东西,基本流程如下:
    a. 建立两个Exchange。 一个用于接受正常log Producer的输入(编号为#1);另外一个接受Log回看需求的输入(编号为#2)。
    b. 在server端(也许是GUI的rest层)建立一个特殊的consumer和它的queue,用于从Exchange #1中接受所有的message并存入DB
    c. 当正常的log trace功能是,client建立到跟Exchange #1 binding的queue,获取实时的log
    d. 当log回看时:
        # 1. client通知server端,server端会根据client端request的参数,如start_time, 从DB中查出相应的log,并作为producer将消息feed到#2 Exchange中
        # 2. client端建立到Exchange #2binding的queue中接受回看消息。

    非常牵强,但也能实现,下次我们在用Kafka试试看。

你可能感兴趣的:(MQ)