精华内容
下载资源
问答
  • 消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,...

    消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ。消息中间件到底该如何使用,何时使用这是一个问题,胡乱地使用消息中间件增加了系统的复杂度,如果用不好消息中间件还不如不用。

    0.消息队列通讯模式


    1)点对点通讯:点对点方式是最为传统和常见的通讯方式,它支持一对一、一对多、多对多、多对一等多种配置方式,支持树状、网状等多种拓扑结构。

    2)多点广播:MQ适用于不同类型的应用。其中重要的,也是正在发展中的是"多点广播"应用,即能够将消息发送到多个目标站点(DestinationList)。可以使用一条MQ指令将单一消息发送到多个目标站点,并确保为每一站点可靠地提供信息。MQ不仅提供了多点广播的功能,而且还拥有智能消息分发功能,在将一条消息发送到同一系统上的多个用户时,MQ将消息的一个复制版本和该系统上接收者的名单发送到目标MQ系统。目标MQ系统在本地复制这些消息,并将它们发送到名单上的队列,从而尽可能减少网络的传输量。

    3)发布/订阅(Publish/Subscribe)模式:发布/订阅功能使消息的分发可以突破目的队列地理指向的限制,使消息按照特定的主题甚至内容进行分发,用户或应用程序可以根据主题或内容接收到所需要的消息。发布/订阅功能使得发送者和接收者之间的耦合关系变得更为松散,发送者不必关心接收者的目的地址,而接收者也不必关心消息的发送地址,而只是根据消息的主题进行消息的收发。在MQ家族产品中,MQEventBroker是专门用于使用发布/订阅技术进行数据通讯的产品,它支持基于队列和直接基于TCP/IP两种方式的发布和订阅。

    4)群集(Cluster):为了简化点对点通讯模式中的系统配置,MQ提供Cluster(群集)的解决方案。群集类似于一个域(Domain),群集内部的队列管理器之间通讯时,不需要两两之间建立消息通道,而是采用群集(Cluster)通道与其它成员通讯,从而大大简化了系统配置。此外,群集中的队列管理器之间能够自动进行负载均衡,当某一队列管理器出现故障时,其它队列管理器可以接管它的工作,从而大大提高系统的高可靠性。

    1.使用消息队列的理由

    过去几年中,我们一直在使用、构建和宣传消息队列,我们认为它们是很令人敬畏的,这也不是什么秘密。我们相信对任何架构或应用来说,消息队列都是一个至关重要的组件,下面是十个理由:

    1. 1解耦

    在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。

    1.2 冗余

    有时在处理数据的时候处理过程会失败。除非数据被持久化,否则将永远丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。在被许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保存直到你使用完毕。

    1.3 扩展性

    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。

    1.4 灵活性 & 峰值处理能力

    当你的应用上了Hacker News的首页,你将发现访问流量攀升到一个不同寻常的水平。在访问量剧增的情况下,你的应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住增长的访问压力,而不是因为超出负荷的请求而完全崩溃。请查看我们关于峰值处理能力的博客文章了解更多此方面的信息。

    1.5可恢复性

    当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个沮丧透顶的用户之间的区别。

    1.6送达保证

    消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即可。在此基础上,IronMQ提供了一个"只送达一次"保证。无论有多少进程在从队列中领取数据,每一个消息只能被处理一次。这之所以成为可能,是因为获取一个消息只是"预定"了这个消息,暂时把它移出了队列。除非客户端明确的表示已经处理完了这个消息,否则这个消息会被放回队列中去,在一段可配置的时间之后可再次被处理。

    1.7排序保证

    在许多情况下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。IronMO保证消息浆糊通过FIFO(先进先出)的顺序来处理,因此消息在队列中的位置就是从队列中检索他们的位置。

    1.8缓冲

    在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行--写入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控制和优化数据流经过系统的速度。

    1.9 理解数据流

    在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳的处理过程或领域,这些地方的数据流都不够优化。

    1.10 异步通信

    很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后在你乐意的时候再去处理它们。


    2.消息队列应用场景

    以下介绍消息队列在实际应用中常用的使用场景。异步处理,应用解耦,流量削锋和消息通讯四个场景。

    2.1异步处理

    场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式
    a、串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。

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

    假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。
    因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)
    小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?

    引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:

    按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。

    2.2应用解耦

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

    传统模式的缺点:假如库存系统无法访问,则订单减库存将失败,从而导致订单失败,订单系统与库存系统耦合

    如何解决以上问题呢?引入应用消息队列后的方案,如下图:

    订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
    库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
    假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

    2.3流量削锋

    流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛
    应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
    a、可以控制活动的人数
    b、可以缓解短时间内高流量压垮应用

    用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。
    秒杀业务根据消息队列中的请求信息,再做后续处理

    2.4日志处理

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

    日志采集客户端,负责日志数据采集,定时写受写入Kafka队列
    Kafka消息队列,负责日志数据的接收,存储和转发
    日志处理应用:订阅并消费kafka队列中的日志数据 

    2.5消息通讯

    消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等
    点对点通讯:

    客户端A和客户端B使用同一队列,进行消息通讯。

    聊天室通讯:

    客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

    以上实际是消息队列的两种消息模式,点对点或发布订阅模式。模型为示意图,供参考。

    3.消息中间件示例

    3.1电商系统


    消息队列采用高可用,可持久化的消息中间件。比如Active MQ,Rabbit MQ,Rocket Mq。
    (1)应用将主干逻辑处理完成后,写入消息队列。消息发送是否成功可以开启消息的确认模式。(消息队列返回消息接收成功状态后,应用再返回,这样保障消息的完整性)
    (2)扩展流程(发短信,配送处理)订阅队列消息。采用推或拉的方式获取消息并处理。
    (3)消息将应用解耦的同时,带来了数据一致性问题,可以采用最终一致性方式解决。比如主数据写入数据库,扩展应用根据消息队列,并结合数据库方式实现基于消息队列的后续处理。

    3.2日志收集系统


    分为Zookeeper注册中心,日志收集客户端,Kafka集群和Storm集群(OtherApp)四部分组成。
    Zookeeper注册中心,提出负载均衡和地址查找服务
    日志收集客户端,用于采集应用系统的日志,并将数据推送到kafka队列
    Kafka集群:接收,路由,存储,转发等消息处理
    Storm集群:与OtherApp处于同一级别,采用拉的方式消费队列中的数据

    以下是新浪kafka日志处理应用案例:转自(http://cloud.51cto.com/art/201507/484338.htm)

     

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

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

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

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


    4.JMS消息服务

    讲消息队列就不得不提JMS 。JMS(JAVA Message Service,java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
    在EJB架构中,有消息bean可以无缝的与JM消息服务集成。在J2EE架构模式中,有消息服务者模式,用于实现消息与应用直接的解耦。

    4.1消息模型

    在JMS标准中,有两种消息模型P2P(Point to Point),Publish/Subscribe(Pub/Sub)。

    4.1.1 P2P模式


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

    P2P的特点
    每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
    发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
    接收者在成功接收消息之后需向队列应答成功
    如果希望发送的每个消息都会被成功处理的话,那么需要P2P模式。

    4.1.2 Pub/Sub模式


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

    Pub/Sub的特点
    每个消息可以有多个消费者
    发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息
    为了消费消息,订阅者必须保持运行的状态
    为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
    如果希望发送的消息可以不被做任何处理、或者只被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型。

    4.2消息消费

    在JMS中,消息的产生和消费都是异步的。对于消费来说,JMS的消息者可以通过两种方式来消费消息。
    (1)同步
    订阅者或接收者通过receive方法来接收消息,receive方法在接收到消息之前(或超时之前)将一直阻塞;

    (2)异步
    订阅者或接收者可以注册为一个消息监听器。当消息到达之后,系统自动调用监听器的onMessage方法。

    JNDI:Java命名和目录接口,是一种标准的Java命名系统接口。可以在网络上查找和访问服务。通过指定一个资源名称,该名称对应于数据库或命名服务中的一个记录,同时返回资源连接建立所必须的信息。
    JNDI在JMS中起到查找和访问发送目标或消息来源的作用。

    5.常用消息队列

    一般商用的容器,比如WebLogic,JBoss,都支持JMS标准,开发上很方便。但免费的比如Tomcat,Jetty等则需要使用第三方的消息中间件。本部分内容介绍常用的消息中间件(Active MQ,Rabbit MQ,Zero MQ,Kafka)以及他们的特点。

    5.1 ActiveMQ

    ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。

    ActiveMQ特性如下:

    • 多种语言和协议编写客户端。语言: Java,C,C++,C#,Ruby,Perl,Python,PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
    • 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
    •  对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
    •  通过了常见J2EE服务器(如 Geronimo,JBoss 4,GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
    •  支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
    • 支持通过JDBC和journal提供高速的消息持久化
    • 从设计上保证了高性能的集群,客户端-服务器,点对点
    • 支持Ajax
    • 支持与Axis的整合
    • 可以很容易得调用内嵌JMS provider,进行测试

    5.2 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代表一个会话任务。

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

    • 客户端连接到消息队列服务器,打开一个channel。
    • 客户端声明一个exchange,并设置相关属性。
    • 客户端声明一个queue,并设置相关属性。
    • 客户端使用routing key,在exchange和queue之间建立好绑定关系。
    • 客户端投递消息到exchange。

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

    5.3 ZeroMQ

    号称史上最快的消息队列,它实际类似于Socket的一系列接口,他跟Socket的区别是:普通的socket是端到端的(1:1的关系),而ZMQ却是可以N:M 的关系,人们对BSD套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而ZMQ屏蔽了这些细节,让你的网络编程更为简单。ZMQ用于node与node间的通信,node可以是主机或者是进程。

    引用官方的说法: “ZMQ(以下ZeroMQ简称ZMQ)是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ZMQ的明确目标是“成为标准网络协议栈的一部分,之后进入Linux内核”。现在还未看到它们的成功。但是,它无疑是极具前景的、并且是人们更加需要的“传统”BSD套接字之上的一 层封装。ZMQ让编写高性能网络应用程序极为简单和有趣。”

    特点是:

    • 高性能,非持久化

    • 跨平台:支持Linux、Windows、OS X等

    • 多语言支持; C、C++、Java、.NET、Python等30多种开发语言

    • 可单独部署或集成到应用中使用

    • 可作为Socket通信库使用

    与RabbitMQ相比,ZMQ并不像是一个传统意义上的消息队列服务器,事实上,它也根本不是一个服务器,更像一个底层的网络通讯库,在Socket API之上做了一层封装,将网络通讯、进程通讯和线程通讯抽象为统一的API接口。支持“Request-Reply “,”Publisher-Subscriber“,”Parallel Pipeline”三种基本模型和扩展模型。

    ZeroMQ高性能设计要点:

    1、无锁的队列模型

       对于跨线程间的交互(用户端和session)之间的数据交换通道pipe,采用无锁的队列算法CAS;在pipe两端注册有异步事件,在读或者写消息到pipe的时,会自动触发读写事件。

    2、批量处理的算法

       对于传统的消息处理,每个消息在发送和接收的时候,都需要系统的调用,这样对于大量的消息,系统的开销比较大,zeroMQ对于批量的消息,进行了适应性的优化,可以批量的接收和发送消息。

    3、多核下的线程绑定,无须CPU切换

       区别于传统的多线程并发模式,信号量或者临界区, zeroMQ充分利用多核的优势,每个核绑定运行一个工作者线程,避免多线程之间的CPU切换开销。


    5.4 Kafka

    Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群机来提供实时的消费。

    Kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性:

    • 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。(文件追加的方式写入数据,过期的数据定期删除)
    • 高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息
    • 支持通过Kafka服务器和消费机集群来分区消息
    • 支持Hadoop并行数据加载

    Kafka相关概念

    • Broker:Kafka集群包含一个或多个服务器,这种服务器被称为broker[5]
    • Topic:每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)
    • Partition:Parition是物理上的概念,每个Topic包含一个或多个Partition.
    • Producer:负责发布消息到Kafka broker
    • Consumer:消息消费者,向Kafka broker读取消息的客户端。
    • Consumer Group:每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。

    一般应用在大数据日志处理或对实时性(少量延迟),可靠性(少量丢数据)要求稍低的场景使用。

    6.使用消息队列需要考虑的问题

    6.1你也许并不需要消息队列

    消息队列是一个能让你获得容错性,分布式,解耦等架构能力的系统。纸上谈兵的话,它看起来还不错。

    或许消息列队在你的应用中有不少适用的场景。你可以看下这篇关于消息队列优点的文章,看看到底有哪些合适的场景。但可不要因为说"能解耦那太好了”就轻易使用它。我们来看一个例子——你希望你的邮件发送和订单处理互相解耦。

    因此你发送一个消息到消息队列里,然后邮件处理系统取出这个消息并发送邮件。那你在一个独立的单classpath的应用中怎么实现呢?让你的订单处理服务依赖于一个邮件服务,然后调用sendEmail()方法,而不是sendToMQ()方法。如果你使用了消息队列,你需要定义一个两个系统都能识别的消息格式 ;如果你不使用消息队列,那么你得定义一个方法签名。它们有什么本质的区别吗?其实没有。

    不过你可能还有别的消费者想要对某个指定的消息进行额外的处理?这的确是可能发生的,而并不只是针对我们这里说到的这个项目而已。尽管确有可能,但相比添加另一个方法调用而言,它可能并不值当。耦合?是的。不过这个耦合并没有什么不方便的。

    那我应该如何处理峰值流量?你可以通过消息队列将请求放到一个持久化队列中,然后再一并处理它们。这是一个非常有用的特性,不过它也受限于几个 因素——你的请求是在UI后台处理,还是需要即时响应?serlvet容器的线程池某种程度上可以当作是一个队列,用户最终会拿到响应,但是得需要等待(如果线程的超时时间过短的话,请求可能会丢失)。

    你可以使用一个内存队列来存储那些较重的请求(得在UI后台进行处理)。不过注意了,你的队列并不是默认高可用的。比如说,如果一个消息队列节点挂掉了,你的消息就丢失了。因此,不去使用应用节点内的内存队列,而是去使用一个消息队列,这可能并没有什么优势。

    消息队列使得我们可以进行异步处理——这的确是个有用的特性。你不希望在用户等待的时候做一些很重的操作。不过你也可以使用一个内存队列,或者简单地启动一个新的线程(比如Spring的@Async注解)。这样又有另一个问题——如果消息丢失的话是否有问题?如果你应用处理请求的节点挂了,你可以进行恢复吗?你会发现这事会经常发生,如果不保证所有消息都处理到的话,很难保证功能的正确性。因此,仅将较重的调用进行异步处理是比较可取的。

    把消息放到队列以便让另一个组件来进行处理,对于这个场景,如果消息丢失是无法接受的 ,这也有一个很简单的解决方案——数据库。你可以把一条processed=false的数据存储到数据库中。然后再运行一个调度作业,将所有未处理的记录挑选出来,异步地进行处理。当处理完成的时候,将标记设为true。我经常用这个方法,包括在一些大型的线上系统中,它也工作得挺好的。

    这样你还能不断地对你的应用节点进行扩展,只要它们的内存中没有任何的持久化状态的话。不管你是否使用了消息队列都可以(临时的内存处理队列并不属于持久化状态)。

    为什么我要给经常用到的消息队列提供一些备选方案?因为如果你由于不恰当的原因选择了它,那么消息队列可能会成为一个负担。它们并非如想像中那样容易使用。首先,它有一个学习曲线。一般来说,你集成的组件切分得越多,就越容易出现问题。其次,还有一个设置及配置的成本。比如说,当消息队列需要在一个集群中运行的话,比如说多个数据中心,那么这就变得复杂了。

    高可用性并不是上来就有的——默认它是不会打开的。还有就是你的应用节点如何连接到消息队列?通过一个刷新的连接池,或者使用短生命周期的DNS记录,还是通过一个负载均衡器?你的队列可能还有许多配置项,大小是多少,行为是怎样的(消费者需不需要确认接受,要不要通知处理失败,多个消费者能够取到同一个消息吗,消息有没有TTL,等等)同时还有网络及消息传递的开销,尤其是现在大家都喜欢用XML或者JSON来传输消息。如果你过度地使用了消息队列,那么它会增加你系统的延时。

    最后一点,但并不是最次要的——如果出现问题的话,使用消息队列会让问题跟踪变得异常困难。你没法在IDE中看到所谓的调用层次,因为一旦你发送消息到队列里了,你就得自己去查找它在哪里处理的了。这可不是听起来那么简单的。你看到了吧,它会给你增加许多的复杂性,以及许多需要注意的东西。

    通常而言,在某些上下文中,消息队列还是非常有用的。当它们的确适合的话,我也会在项目中使用它们——比方说,我们不想丢失消息,但又希望能快速地进行处理。我也见过它在一些不太常见的场景中使用的情况,比如说只有一个应用节点来进行消费,不管是哪个节点投递过来的消息。你还可以看下stackoverflow上的这个问题。还有一些使用场景就是,或许你的确需要进行多语言间的通信,又或者你的数据流已经过于复杂了,不使用新的消息消费者而是增加新方法调用的话代价会很大。

    我想说的是那句老掉牙的真理“杀鸡焉用牛刀”。如果你不是很确定已经没有别的更容易管理和维护的方法,一定要使用消息队列的话,最好不要使用它。不要因为”万一它有用呢“而去用它——只有你确实觉得需要的话再去使用。因为很有可能,就像这里说到的这个项目一样,消息队列其实是没有必要的。

    6.2如何避免消息丢失

    选择能够支持消息持久化的MQ方案。如:ActiveMQ、RabbitMQ等,给消息一个处理状态如:process=false。

    还可以使用缓存方案做:如Redis,它本身也是支持持久化的。


    7.本文参考资料来源


    消息队列MQ的原理及实现方法:http://blog.csdn.net/lzq_csdn_th/article/details/51945408


    关于消息队列的使用:http://www.cnblogs.com/linjiqin/p/5720865.html


    消息队列使用的四种场景介绍:http://blog.csdn.net/cws1214/article/details/52922267


    使用消息队列的十个理由:http://www.oschina.net/translate/top-10-uses-for-message-queue?p=2


    国外的一款消息队列IronMQ:http://iron.io/products/mq?rc=blog_mq_t10


    你可能并不需要消息队列:http://kb.cnblogs.com/page/212710/


    展开全文
  • 从技术角度告诉你,区块链到底有哪些特点和运作机制 王思宇 • 2016-06-28 13:18 摘要: 区块链技术的核心是实现了沿时间轴记录数据与合约,并且一旦写入,就只能读取,不能修改和删除。 自从今年1月20日,...

    从技术角度告诉你,区块链到底有哪些特点和运作机制

    王思宇 • 2016-06-28 13:18

    摘要: 区块链技术的核心是实现了沿时间轴记录数据与合约,并且一旦写入,就只能读取,不能修改和删除。

    自从今年1月20日,中国人民银行在数字货币研讨会上表示高度重视区块链(Blockchain)等技术带来的新机遇和挑战,并争取早日推出央行发行的数字货币[1]以来,区块链的概念在国内越发火热,吸引了金融机构空前的关注。

    这份报告是爱就投与研究中心第一次关于区块链技术的研究结果,参考了来自投行、咨询机构的多份研究报告,并结合爱就投项目经理与国内区块链创业者的交流整理而成。

    技术篇介绍区块链的技术特点和运作机制,并说明相关的重要技术概念;应用篇结合其在金融和非金融领域的应用案例,分析区块链的应用场景和市场前景。

    作者认为,区块链技术的核心是沿时间轴记录数据与合约,并且只能读取和写入,不能修改和删除。在应用层面,区块链的安全、透明、高效3大优势,使其特别有助于规范互联网金融的发展,以及促进物联网和共享经济的普及与创新;在资本市场,采用分布式数据库和智能合约还可以大幅减少人工核对工作,为金融机构节省成本。

    一.区块链的技术特点

    区块链是一种共享的分布式数据库技术[2]。尽管不同报告中对区块链的一句话介绍措辞都不相同,但以下4个技术特点是共识性的[3]。

    1.
    去中心化(Decentralized):图1的左侧描述了当今金融系统的中心化特征,右侧描述的是正在形成的去中心化金融系统,其没有中介机构,所有节点的权利和义务都相等,任一节点停止工作都会不影响系统整体的运作[4];

    图1,出自花旗报告Digital Disruption: How FinTech is Forcing Banking to a Tipping Point
    [4]

    2.
    去信任(Trustless):系统中所有节点之间无需信任也可以进行交易,因为数据库和整个系统的运作是公开透明的,在系统的规则和时间范围内,节点之间无法欺骗彼此;

    3. 集体维护(Collectively Maintain):系统是由其中所有具有维护功能的节点共同维护的,系统中所有人共同参与维护工作;

    4. 可靠数据库(Reliable
    Database):系统中每一个节点都拥有最新的完整数据库拷贝,修改单个节点的数据库是无效的,因为系统会自动比较,认为最多次出现的相同数据记录为真。

    图2,出自高盛报告Blockchain: Putting Theory into Practice [2]

    图2为简化起见,仅展示了6处保留数据库副本的节点;在3个交易序列中,前2个交易的数据和签名得到了所有6个节点的验证,但第三个交易的位置5没有通过验证,将被其它节点的“一致意见”更改[2]。

    二.公有链、私有链、侧链

    区块链按照访问和管理权限可以分为公有链(Public Blockchain)和私有链或联盟链(Private
    Blockchain)。公有链是完全开放的区块链,全世界的人都可以参与系统维护工作,这使得公有链还具有以下2个特点[3]。

    1. 开源(Open Source):由于整个系统的运作规则公开透明,这个系统是开源系统;

    2. 匿名(Anonymity):由于节点之间无需信任彼此,所有节点也无需公开身份,系统中每一个节点的匿名和隐私都受到保护。

    私有链或联盟链在开放程度和去中心化程度方面有所限制[5],参与者需要被提前筛选,数据库的读取权限可能是公开的,也可能像写入权限一样只限于系统的参与者[6]。

    公有链的典型代表是比特币区块链,任何人都可以通过交易或挖矿读取和写入数据[7]。私有链或联盟链的典型案例是Ripple和R3
    CEV,前者目前为属于联盟成员的银行类金融机构提供跨境支付服务,希望取代环球同业银行金融电讯协会(SWIFT)的跨境转账平台,打造全球统一的网络金融传输协议;后者旨在推动制定适合金融机构使用的区块链技术标准[8]。

    侧链(Sidechains)是用于确认来自于其它区块链的数据的区块链,通过双向挂钩(Two Way
    Peg)机制使比特币、Ripple币等多种资产在不同区块链上以一定的汇率实现转移[9][10]。

    图3,出自Blockstream Moves Ahead with Sidechain Elements. Giulio Prisco [10]

    侧链进一步扩展了区块链技术的应用范围和创新空间,使区块链支持包括股票、债券、金融衍生品等在内的多种资产类型,以及小微支付、智能合约、安全处理机制、真实世界财产注册等;侧链还可以增强区块链的隐私保护[10][11]。

    所谓“多种资产在不同区块链上转移”其实并不会实际发生。以比特币为例,侧链的运作机制是,将比特币暂时锁定在比特币区块链上,同时将辅助区块链上的等值数字货币解锁;当辅助区块链上的数字货币被锁定时,原先的比特币就被解锁[12]。

    三.比特币区块链如何运作?

    比特币网络从2009年1月开始至今,在没有专人维护的情况下已经平稳运行7年多,期间没有出现一次宕机。图4以Bob接收来自Alice的比特币的场景,详细描述了比特币区块链的工作方式,一并解释了涉及到的钱包和地址(Wallets
    and Addresses)、私钥和公钥(Private Key and Public Key)、加密哈希(Cryptographic
    Hashes)、随机数(Nonces)等概念[13]。

    图4,出自A Guide to Bitcoin Mining. Alec Liu [13]

    钱包和地址:

    1. Bob和Alice的电脑上都有比特币钱包。2. 钱包是一种文件,可以让用户访问多个比特币地址。3. 一个地址是一串由字母和数字组成的字符串。4.
    每一个地址都有自己的比特币余额。

    新建一个地址:

    5. Bob创建一个新的比特币地址,用于接收Alice的付款。

    私钥和公钥:

    6.
    当Bob创建一个新地址时,他真正在做的是生成一个密钥对,由一个私钥和一个公钥组成。如果你使用私钥(只有你知道)对一个消息进行签名,它可以被对应的公钥(所有人都知道)所验证。Bob的新地址代表一个唯一的公钥,对应的私钥则保存在他的钱包里。公钥允许所有人来验证被私钥签名的消息的有效性。

    7.
    可以将地址看做银行账号,但工作方式稍有不同。比特币用户可以任意创建多个地址,并且被鼓励为每一个新的交易单独创建新地址,以增强隐私性。只要没有人知道哪些地址是Alice的,她的匿名就受到保护。

    提交一个支付:

    8. Alice告诉她的比特币客户端,她要向Bob的收款地址转账。9.
    Alice的钱包里有她的每一个比特币地址的私钥。比特币客户端用Alice此次使用的付款地址的私钥,对她的这一交易申请进行签名。10.
    此时,网络上的任何人都可以使用公钥来验证,这个交易申请实际来自一个合法的账户所有者。

    验证交易:

    11. Gary、Garth和Glenn都是比特币矿工。12. 他们的电脑将过去约10分钟内的交易打包成一个新的交易区块。13.
    矿工的电脑被设置用于计算加密哈希(Cryptographic Hash)函数。14.
    加密哈希函数将一个数据集转换成特定长度的包含字母和数字的字符串,称为哈希值。源数据的细微改变会彻底改变哈希值的结果。并且基本不可能预测初始的数据集将会产生的特定哈希值。

    15.
    为相同的数据创建不同的哈希值,比特币使用随机数来实现。随机数是在进行哈希计算之前,在数据中添加的随机数字。改变这个随机数会产生极不相同的哈希值。16.
    每一个新的哈希值包含关于此前所有比特币交易的信息。17. 矿工的电脑基于前一个区块的哈希值、新交易区块和随机数,来计算新的哈希值。18.
    创建哈希在计算上微不足道,但比特币系统要求新的哈希值拥有特定格式——必须以特定数量的0作为开始。

    19. 矿工无法预测哪个随机数会产生以要求的数量的0作为开始的哈希值,所以他们被迫用不同的随机数创建很多哈希,直到获得有效的那一个。20.
    每一个区块都包含一个名为coinbase的初始交易,这是给胜出矿工的50比特币的支付——在这个例子中是矿工Gary。Gray的钱包里生成了一个新地址,里面的余额是新挖到的比特币数量。

    注:

    只有在比特币发行的阶段1,每一个区块的coinbase支付给胜出矿工的新币是50个。从2009年1月3日创世区块诞生开始,新比特币的发行大约每4年减半,2012年11月28日,阶段2开始,每一个区块包含的新币减为25个,这是历史上第一次减半;预计今年7月11日,挖矿奖励会再次减半;直到第33次减半时,每一个区块从产生0.0021个新币直接减为0个,比特币的总量固定在将近2100万个[14][15]。

    交易验证:

    21.
    随着时间流逝,Alice向Bob的转账被埋在了其它更近期的交易下面。任何人要想修改历史交易的细节,就必须重做一遍Gary的工作,然后再重做所有下一级矿工的工作,因为所有的改变都需要一个完全不同的胜出随机数。这样的操作几乎不可能成功。

    四.双重支付如何解决?

    以比特币为代表的数字货币,关键的创新是通过时间戳(Timestamp)和工作量证明(Proof of Work)机制解决双重支付(Double
    Spending)和拜占庭将军问题(Byzantine Generals’
    Problem),即保证同一笔比特币不会同时出现在两个地址[7],并且在信道可靠的基础上,所有节点都可以让其它节点接收到自己的真实意图,并最终一致行动[16]。

    这一技术方案最早见于化名为中本聪(Satoshi Nakamoto)的个人或团体在2008年发表的论文Bitcoin: A Peer-to-Peer
    Electronic Cash System [17]。

    在Bob接收来自Alice的比特币的场景中,一方面,这笔付款被广播给系统中所有节点,任何人都可以使用Bob的公钥来验证这个交易的合法性,如果Alice试图双重支付,就必须先删除这个交易记录,否则新交易无法通过验证。中本聪在论文中写道:

    “时间戳服务器为一个区块的数据的哈希计算结果加上时间戳,并大范围发布这一哈希计算结果,好比在报纸或新闻网上发表。显然,时间戳证实这些数据一定在这一特定时间存在,只有这样才能得到哈希计算结果(A
    timestamp server works by taking a hash of a block of items to be timestamped
    and widely publishing the hash, such as in a newspaper or Usenet post. The
    timestamp proves that the data must have existed at the time, obviously, in
    order to get into the hash)”[17]。

    另一方面,工作量证明机制使得生成下一个区块的节点和矿工几乎无法被预测到,所以删除交易记录几乎不可能。系统中的节点将过去约10分钟内的比特币交易进行打包,而只有获得有效哈希值的矿工才能生成新区块,并得到挖矿奖励;矿工除了打包比特币交易,还要结合随机数来完成有效哈希值的创建工作,获得以要求的数量的0作为开始的哈希值。

    中本聪在论文中写道:

    图5,出自中本聪论文Bitcoin: A Peer-to-Peer Electronic Cash System [17]

    “工作量证明本质上是一CPU一票(Proof-of-work is essentially one-CPU-one-vote)”;

    >

    >
    “如果两个节点同时广播不同版本的新区块,那么一些节点会先收到其中一个的广播。在这种情况下,节点在先收到的区块基础上工作,并保留另外一个分支,以防后者变成较长的链。这个僵局要等到发现下一个工作量证明才能被打破,其中一条链将成为较长的链,在另一个分支上工作的节点将切换到较长的链上继续工作(If
    two nodes broadcast different versions of the next block simultaneously, some
    nodes may receive one or the other first. In that case, they work on the first
    one they received, but save the other branch in case it becomes longer. The
    tie will be broken when the next proof-of-work is found and one branch becomes
    longer; the nodes that were working on the other branch will then switch to
    the longer one)”;

    >

    “节点永远认为最长的链是正确的链,并将持续在它上面延长(Nodes always consider the longest chain to be
    the correct one and will keep working on extending it)”[17]。

    所以除非永久控制整个系统中超过一半的节点,才能阻止矿工把这个交易添加到新区块中。

    最后,考虑到硬件运算速度的增长和节点参与程度的变化,中本聪用移动平均目标来确定工作量证明的难度,使得两个区块生成的时间间隔约为10分钟[17]。

    五.区块链技术目前问题

    区块链技术还处于不断完善的阶段,就其第一个应用的比特币来说,有3个主要问题正在被其它系统所完善或试图完善。

    区块容量和交易速度限制
    中本聪设计比特币时,为区块设置了1MB的容量限制,使每一个区块只能容纳4096个交易;同时,工作量证明机制使得确认交易并将交易记录到区块链中需要约10分钟,当运算量达到极限时,运算时间就会放缓[18]。目前,比特币网络还没有成熟到可以将规模扩展至主要信用卡网络的程度,提高这一上限的工作正在进行中[19]。

    另外,区块扩容已经成为迫切需求。曾有比特币核心开发者提出从Bitcoin Core切换到硬分叉链Bitcoin
    XT的方案,区块从1MB扩容至8MB,此后每2年翻倍。这一变动需要1000个连续区块中的750个包含矿工的变更批准。目前这一事件正在发展中[18]。

    挖矿浪费巨大资源

    2014年6月曾有工程师系统计算,在比特币全网计算能力为110,000,000
    GH/S的情况下,整个网络的挖矿成本约为每年8亿美元,包括电力成本约7,071.2万美元和矿机投资约7.33亿美元[20]。

    矿机投资方面,支持这样的算力大约需要36,670台KnCMiner海王星矿机,每台功率3,000GH,售价9,995美元,按照一年支出2次计算,结果约为7.33亿美元/年;电力成本方面,每日需要耗电80,666千瓦,按照每兆瓦100美元计算,结果约为7,071.2万美元/年。另外,这些矿机产生的二氧化碳为424,725吨/年[20]。

    图6展示了从2014年6月到2016年6月,比特币网络计算能力的增长趋势,最高点的Hash Rate已经达到1,800,000,000 GH/S [21]。

    图6 Hash Rate,出自Blockchain.info [21]

    由于挖矿工作只为搜索到随机数以获得有效哈希值,并不产生其它价值,比特币网络的算力资源和消耗的电力成本被诟病为资源浪费[22]。其它系统改进这个问题的总思路是,减少其中参与维护工作的节点的数量,减轻挖矿竞争的激烈程度。具体有2种方式,一是采用私有链或联盟链,将“记账权”强制规定给某些节点;二是引入权益证明(Proof
    of Stake)机制,配合工作量证明来维护可靠数据库。

    权益证明是一种对货币所有权的证明[23],证明人需要提供一定数量的货币的所有权,系统根据每一个节点所占有的货币的比例和占有时间来确定“记账权”[22];权益证明的核心是只让在区块链中具有经济利益的人参与系统的维护工作,这就使得挖矿的成本远低于工作量证明机制之下的挖矿成本[24]。

    缺少图灵完备性

    既然区块链可以保证比特币交易记录不被删改,理论上也可以保证任何代码一旦被写入,就不能删改。然而,比特币的脚本语言并不是图灵完备的,即不支持循环语句,意味着比特币只能作为数字货币,不能直接支持智能合约及更复杂的去中心化应用[25]。

    区块链技术平台以太坊的脚本语言(Ethereum Virtual Machine
    code)就是图灵完备的;用EVM代码来建立应用,理论上可以实现任何可以想象的计算,包括无限循环[25]。以太坊实现了让任何人可以上传和执行任意的应用程序,并且程序的有效执行能得到保证[22]。

    六.智能合约如何运作?

    在英语里,Code这个单词既有“代码”的意思,也有“法典”的意思,这暗示了智能合约(Smart Contracts)的功能和意义。

    智能合约是一种直接控制数字资产的电脑程序[26]。图7描述了基于比特币的智能合约的工作方式[27],通过在区块链上写入类似if-
    then语句的程序,使得当预先编好的条件被触发时,程序自动触发支付及执行合约中的其它条款[28]。

    图7,出自德勤报告Blockchain: Enigma. Paradox. Opportunity [27]

    1. 多方之间的定期交付合同被以代码的形式写入区块链。其中的个体是匿名的,但合同记录在公共账本中。

    2. 当扳机事件触发时,比如到期、执行价格达到,合约按照编程的条款自动执行。

    3. 监管者可以通过这个区块链了解市场上的活动,同时维护个体成员的隐私。

    Bob是接受数字货币支付的线上商家,Alice是使用数字货币进行支付的购物者,智能合约可以在去信任的情况下使Bob的商品与Alice的数字货币实现交换。Alice可以创建一个智能合约,将这样一段代码写入区块链:“如果我在24小时内收到这一商品,则我会将这笔数字货币发到寄件人的收款地址,并将这个商品寄给我的创建者,否则我将会将这笔数字货币发回给我的创建者”。

    智能合约中的资产和资金没有拥有者(Owner),在这个例子中,当Alice把这笔数字货币加入智能合约,就无法通过修改这个合约把这笔数字货币拿回来,只能等待交易成功并收到Bob寄出的商品,或者24小时后交易没有成功,再收到自己的数字货币。

    七.技术篇结论

    以上介绍了区块链的技术特点及相关的数字货币、智能合约、侧链等的运作机制,并说明了相关的时间戳、工作量证明、权益证明、加密哈希等概念。区块链技术的核心是实现了沿时间轴记录数据与合约,并且一旦写入,就只能读取,不能修改和删除。

    有一种较为主流的观点将区块链技术的演进分为1.0数字货币、2.0智能合约、3.0(Meta
    Technology)去中心化应用3个阶段[29]。应用篇将对这3类应用进行分析,并展望区块链的市场前景。

    参考文献:
    [1] 中国人民银行数字货币研讨会在京召开
    网址:http://www.pbc.gov.cn/goutongjiaoliu/113456/113469/3008070/index.html
    [2] Blockchain: Putting Theory into Practice 高盛报告
    [3] 什么是区块链 网址:http://chainb.com/?P=Cont &id=6
    [4] Digital Disruption: How FinTech is Forcing Banking to a Tipping Point 花旗报告
    [5] 详解区块链——颠覆式创新技术 申万宏源报告
    [6] On Public and Private Blockchains
    网址:https://blog.ethereum.org/2015/08/07/on-public-and-private-blockchains
    [7] Mastering Bitcoin: Unlocking Digital Cryptocurrencies 出版社:O’Reilly Media
    [8] 区块链——银行业游戏规则的颠覆者 麦肯锡大中华区报告
    [9] 论文Enabling Blockchain Innovations with Pegged Sidechains
    网址:https://www.blockstream.com/sidechains.pdf
    [10] Blockstream Moves Ahead with Sidechain Elements, the First Implementation
    of Sidechains 网址:https://bitcoinmagazine.com/articles/blockstream-moves-ahead-
    sidechain-elements-first-implementation-sidechains-1433883105
    [11] How Sidechains Work 网址:https://blockstream.com
    [12] Sidechains, Drivechains, and RSK 2-Way peg Design
    网址:http://www.rootstock.io/blog/sidechains-drivechains-and-rsk-2-way-peg-
    design
    [13] A Guide to Bitcoin Mining: Why Someone Bought a 1,500BitcoinMineroneBayfor20,600 网址:http://motherboard.vice.com/blog/a-guide-to-bitcoin-
    mining-why-someone-bought-a-1500-bitcoin-miner-on-ebay-for-20600
    [14] 比特币总量为什么是2100万? 网址:http://www.8btc.com/21million00
    [15] 定于7月11日的比特币挖矿奖励减半日,中外看法大不相同 网址:http://www.8btc.com/china-
    bitcoin-711-halving
    [16] 拜占庭将军问题深入探讨 网址:http://www.8btc.com/baizhantingjiangjun
    [17] 论文Bitcoin: A Peer-to-Peer Electronic Cash System
    网址:https://bitcoin.org/bitcoin.pdf
    [18] 区块链和数字货币系列报告之一 申万宏源报告
    [19] 比特币能否扩大规模成为一个主要的支付网络? 网址:https://bitcoin.org/zh_CN/faq#can-bitcoin-scale-
    to-become-a-major-payment-network
    [20] Under the Microscope: Economic and Environmental Costs of Bitcoin Mining
    网址:http://www.coindesk.com/microscope-economic-environmental-costs-bitcoin-
    mining
    [21] Hash Rate. Blockchain.info 网址:https://blockchain.info/charts/hash-
    rate?timespan=2year&showDataPoints=false&daysAverageString=1&show_header=true&scale=0&address=
    [22] 区块链:互联网的诗和远方 安信证券报告
    [23] PPC: 一种P2P(点对点)的权益证明(Proof of Stake)电子密码货币
    网址:http://8btc.com/thread-540-1-1.html
    [24] What Proof of Stake Is And Why It Matters
    网址:https://bitcoinmagazine.com/articles/what-proof-of-stake-is-and-why-it-
    matters-1377531463
    [25] [中文] 以太坊白皮书
    网址:https://github.com/ethereum/wiki/wiki/%5B%E4%B8%AD%E6%96%87%5D-%E4%BB%A5%E5%A4%AA%E5%9D%8A%E7%99%BD%E7%9A%AE%E4%B9%A6
    [26] Platform Review - Opportunities and Challenges for Private and Consortium
    Blockchains 以太坊报告(R3出版)
    [27] Blockchain: Enigma. Paradox. Opportunity 德勤报告
    [28] 智能合约将使我们未来不需要银行和律师? 网址:http://haogetalks.baijia.baidu.com/article/505826
    [29] Blockchain: Blueprint for a New Economy 出版社:O’Reilly Media

    http://www.tmtpost.com/2398844.html

    展开全文
  • 消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,...

    附原文链接:https://blog.csdn.net/boonya/article/details/68064231

    消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ。消息中间件到底该如何使用,何时使用这是一个问题,胡乱地使用消息中间件增加了系统的复杂度,如果用不好消息中间件还不如不用。

    0.消息队列通讯模式

    1)点对点通讯:点对点方式是最为传统和常见的通讯方式,它支持一对一、一对多、多对多、多对一等多种配置方式,支持树状、网状等多种拓扑结构。

    2)多点广播:MQ适用于不同类型的应用。其中重要的,也是正在发展中的是"多点广播"应用,即能够将消息发送到多个目标站点(DestinationList)。可以使用一条MQ指令将单一消息发送到多个目标站点,并确保为每一站点可靠地提供信息。MQ不仅提供了多点广播的功能,而且还拥有智能消息分发功能,在将一条消息发送到同一系统上的多个用户时,MQ将消息的一个复制版本和该系统上接收者的名单发送到目标MQ系统。目标MQ系统在本地复制这些消息,并将它们发送到名单上的队列,从而尽可能减少网络的传输量。

    3)发布/订阅(Publish/Subscribe)模式:发布/订阅功能使消息的分发可以突破目的队列地理指向的限制,使消息按照特定的主题甚至内容进行分发,用户或应用程序可以根据主题或内容接收到所需要的消息。发布/订阅功能使得发送者和接收者之间的耦合关系变得更为松散,发送者不必关心接收者的目的地址,而接收者也不必关心消息的发送地址,而只是根据消息的主题进行消息的收发。在MQ家族产品中,MQEventBroker是专门用于使用发布/订阅技术进行数据通讯的产品,它支持基于队列和直接基于TCP/IP两种方式的发布和订阅。

    4)群集(Cluster):为了简化点对点通讯模式中的系统配置,MQ提供Cluster(群集)的解决方案。群集类似于一个域(Domain),群集内部的队列管理器之间通讯时,不需要两两之间建立消息通道,而是采用群集(Cluster)通道与其它成员通讯,从而大大简化了系统配置。此外,群集中的队列管理器之间能够自动进行负载均衡,当某一队列管理器出现故障时,其它队列管理器可以接管它的工作,从而大大提高系统的高可靠性。

    1.使用消息队列的理由


    过去几年中,我们一直在使用、构建和宣传消息队列,我们认为它们是很令人敬畏的,这也不是什么秘密。我们相信对任何架构或应用来说,消息队列都是一个至关重要的组件,下面是十个理由:

    1. 1解耦


    在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。

    1.2 冗余


    有时在处理数据的时候处理过程会失败。除非数据被持久化,否则将永远丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。在被许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保存直到你使用完毕。

    1.3 扩展性


    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。

    1.4 灵活性 & 峰值处理能力


    当你的应用上了Hacker News的首页,你将发现访问流量攀升到一个不同寻常的水平。在访问量剧增的情况下,你的应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住增长的访问压力,而不是因为超出负荷的请求而完全崩溃。请查看我们关于峰值处理能力的博客文章了解更多此方面的信息。

    1.5可恢复性


    当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个沮丧透顶的用户之间的区别。

    1.6送达保证


    消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即可。在此基础上,IronMQ提供了一个"只送达一次"保证。无论有多少进程在从队列中领取数据,每一个消息只能被处理一次。这之所以成为可能,是因为获取一个消息只是"预定"了这个消息,暂时把它移出了队列。除非客户端明确的表示已经处理完了这个消息,否则这个消息会被放回队列中去,在一段可配置的时间之后可再次被处理。

    1.7排序保证


    在许多情况下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。IronMO保证消息浆糊通过FIFO(先进先出)的顺序来处理,因此消息在队列中的位置就是从队列中检索他们的位置。

    1.8缓冲


    在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行--写入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控制和优化数据流经过系统的速度。

    1.9 理解数据流


    在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳的处理过程或领域,这些地方的数据流都不够优化。

    1.10 异步通信


    很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后在你乐意的时候再去处理它们。


    2.消息队列应用场景


    以下介绍消息队列在实际应用中常用的使用场景。异步处理,应用解耦,流量削锋和消息通讯四个场景。

    2.1异步处理


    场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式
    a、串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。


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


    假设三个业务节点每个使用50毫秒钟,不考虑网络等其他开销,则串行方式的时间是150毫秒,并行的时间可能是100毫秒。
    因为CPU在单位时间内处理的请求数是一定的,假设CPU1秒内吞吐量是100次。则串行方式1秒内CPU可处理的请求量是7次(1000/150)。并行方式处理的请求量是10次(1000/100)
    小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢?

    引入消息队列,将不是必须的业务逻辑,异步处理。改造后的架构如下:

    按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。

    2.2应用解耦


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

    传统模式的缺点:假如库存系统无法访问,则订单减库存将失败,从而导致订单失败,订单系统与库存系统耦合

    如何解决以上问题呢?引入应用消息队列后的方案,如下图:

    订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
    库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
    假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦

    2.3流量削锋


    流量削锋也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。
    应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
    a、可以控制活动的人数
    b、可以缓解短时间内高流量压垮应用

    用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。
    秒杀业务根据消息队列中的请求信息,再做后续处理

    2.4日志处理


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

    日志采集客户端,负责日志数据采集,定时写受写入Kafka队列
    Kafka消息队列,负责日志数据的接收,存储和转发
    日志处理应用:订阅并消费kafka队列中的日志数据 

    2.5消息通讯


    消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等
    点对点通讯:

    客户端A和客户端B使用同一队列,进行消息通讯。

    聊天室通讯:

    客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。

    以上实际是消息队列的两种消息模式,点对点或发布订阅模式。模型为示意图,供参考。

    3.消息中间件示例


    3.1电商系统

    消息队列采用高可用,可持久化的消息中间件。比如Active MQ,Rabbit MQ,Rocket Mq。
    (1)应用将主干逻辑处理完成后,写入消息队列。消息发送是否成功可以开启消息的确认模式。(消息队列返回消息接收成功状态后,应用再返回,这样保障消息的完整性)
    (2)扩展流程(发短信,配送处理)订阅队列消息。采用推或拉的方式获取消息并处理。
    (3)消息将应用解耦的同时,带来了数据一致性问题,可以采用最终一致性方式解决。比如主数据写入数据库,扩展应用根据消息队列,并结合数据库方式实现基于消息队列的后续处理。

    3.2日志收集系统

    分为Zookeeper注册中心,日志收集客户端,Kafka集群和Storm集群(OtherApp)四部分组成。
    Zookeeper注册中心,提出负载均衡和地址查找服务
    日志收集客户端,用于采集应用系统的日志,并将数据推送到kafka队列
    Kafka集群:接收,路由,存储,转发等消息处理
    Storm集群:与OtherApp处于同一级别,采用拉的方式消费队列中的数据

    以下是新浪kafka日志处理应用案例:转自(http://cloud.51cto.com/art/201507/484338.htm)

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

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

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

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


    4.JMS消息服务


    讲消息队列就不得不提JMS 。JMS(JAVA Message Service,java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
    在EJB架构中,有消息bean可以无缝的与JM消息服务集成。在J2EE架构模式中,有消息服务者模式,用于实现消息与应用直接的解耦。

    4.1消息模型


    在JMS标准中,有两种消息模型P2P(Point to Point),Publish/Subscribe(Pub/Sub)。

    4.1.1 P2P模式

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

    P2P的特点
    每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
    发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
    接收者在成功接收消息之后需向队列应答成功 
    如果希望发送的每个消息都会被成功处理的话,那么需要P2P模式。

    4.1.2 Pub/Sub模式

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

    Pub/Sub的特点
    每个消息可以有多个消费者
    发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息
    为了消费消息,订阅者必须保持运行的状态
    为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
    如果希望发送的消息可以不被做任何处理、或者只被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型。

    4.2消息消费


    在JMS中,消息的产生和消费都是异步的。对于消费来说,JMS的消息者可以通过两种方式来消费消息。
    (1)同步
    订阅者或接收者通过receive方法来接收消息,receive方法在接收到消息之前(或超时之前)将一直阻塞;

    (2)异步
    订阅者或接收者可以注册为一个消息监听器。当消息到达之后,系统自动调用监听器的onMessage方法。

    JNDI:Java命名和目录接口,是一种标准的Java命名系统接口。可以在网络上查找和访问服务。通过指定一个资源名称,该名称对应于数据库或命名服务中的一个记录,同时返回资源连接建立所必须的信息。
    JNDI在JMS中起到查找和访问发送目标或消息来源的作用。

    5.常用消息队列


    一般商用的容器,比如WebLogic,JBoss,都支持JMS标准,开发上很方便。但免费的比如Tomcat,Jetty等则需要使用第三方的消息中间件。本部分内容介绍常用的消息中间件(Active MQ,Rabbit MQ,Zero MQ,Kafka)以及他们的特点。

    5.1 ActiveMQ


    ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。

    ActiveMQ特性如下:

    多种语言和协议编写客户端。语言: Java,C,C++,C#,Ruby,Perl,Python,PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
    完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)
     对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性
     通过了常见J2EE服务器(如 Geronimo,JBoss 4,GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上
     支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
    支持通过JDBC和journal提供高速的消息持久化
    从设计上保证了高性能的集群,客户端-服务器,点对点
    支持Ajax
    支持与Axis的整合
    可以很容易得调用内嵌JMS provider,进行测试


    5.2 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代表一个会话任务。


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

    客户端连接到消息队列服务器,打开一个channel。
    客户端声明一个exchange,并设置相关属性。
    客户端声明一个queue,并设置相关属性。
    客户端使用routing key,在exchange和queue之间建立好绑定关系。
    客户端投递消息到exchange。
    exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。

    5.3 ZeroMQ


    号称史上最快的消息队列,它实际类似于Socket的一系列接口,他跟Socket的区别是:普通的socket是端到端的(1:1的关系),而ZMQ却是可以N:M 的关系,人们对BSD套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而ZMQ屏蔽了这些细节,让你的网络编程更为简单。ZMQ用于node与node间的通信,node可以是主机或者是进程。

    引用官方的说法: “ZMQ(以下ZeroMQ简称ZMQ)是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ZMQ的明确目标是“成为标准网络协议栈的一部分,之后进入Linux内核”。现在还未看到它们的成功。但是,它无疑是极具前景的、并且是人们更加需要的“传统”BSD套接字之上的一 层封装。ZMQ让编写高性能网络应用程序极为简单和有趣。”

    特点是

    高性能,非持久化

    跨平台:支持Linux、Windows、OS X等

    多语言支持; C、C++、Java、.NET、Python等30多种开发语言

    可单独部署或集成到应用中使用

    可作为Socket通信库使用

    与RabbitMQ相比,ZMQ并不像是一个传统意义上的消息队列服务器,事实上,它也根本不是一个服务器,更像一个底层的网络通讯库,在Socket API之上做了一层封装,将网络通讯、进程通讯和线程通讯抽象为统一的API接口。支持“Request-Reply “,”Publisher-Subscriber“,”Parallel Pipeline”三种基本模型和扩展模型。

    ZeroMQ高性能设计要点:

    1、无锁的队列模型

       对于跨线程间的交互(用户端和session)之间的数据交换通道pipe,采用无锁的队列算法CAS;在pipe两端注册有异步事件,在读或者写消息到pipe的时,会自动触发读写事件。

    2、批量处理的算法

       对于传统的消息处理,每个消息在发送和接收的时候,都需要系统的调用,这样对于大量的消息,系统的开销比较大,zeroMQ对于批量的消息,进行了适应性的优化,可以批量的接收和发送消息。

    3、多核下的线程绑定,无须CPU切换

       区别于传统的多线程并发模式,信号量或者临界区, zeroMQ充分利用多核的优势,每个核绑定运行一个工作者线程,避免多线程之间的CPU切换开销。


    5.4 Kafka


    Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群机来提供实时的消费。

    Kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性:

    通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。(文件追加的方式写入数据,过期的数据定期删除)
    高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息
    支持通过Kafka服务器和消费机集群来分区消息
    支持Hadoop并行数据加载
    Kafka相关概念

    Broker:Kafka集群包含一个或多个服务器,这种服务器被称为broker[5]
    Topic:每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处)
    Partition:Parition是物理上的概念,每个Topic包含一个或多个Partition.
    Producer:负责发布消息到Kafka broker
    Consumer:消息消费者,向Kafka broker读取消息的客户端。
    Consumer Group:每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。
    一般应用在大数据日志处理或对实时性(少量延迟),可靠性(少量丢数据)要求稍低的场景使用。

    6.使用消息队列需要考虑的问题


    6.1你也许并不需要消息队列


    消息队列是一个能让你获得容错性,分布式,解耦等架构能力的系统。纸上谈兵的话,它看起来还不错。

    或许消息列队在你的应用中有不少适用的场景。你可以看下这篇关于消息队列优点的文章,看看到底有哪些合适的场景。但可不要因为说"能解耦那太好了”就轻易使用它。我们来看一个例子——你希望你的邮件发送和订单处理互相解耦。

    因此你发送一个消息到消息队列里,然后邮件处理系统取出这个消息并发送邮件。那你在一个独立的单classpath的应用中怎么实现呢?让你的订单处理服务依赖于一个邮件服务,然后调用sendEmail()方法,而不是sendToMQ()方法。如果你使用了消息队列,你需要定义一个两个系统都能识别的消息格式 ;如果你不使用消息队列,那么你得定义一个方法签名。它们有什么本质的区别吗?其实没有。

    不过你可能还有别的消费者想要对某个指定的消息进行额外的处理?这的确是可能发生的,而并不只是针对我们这里说到的这个项目而已。尽管确有可能,但相比添加另一个方法调用而言,它可能并不值当。耦合?是的。不过这个耦合并没有什么不方便的。

    那我应该如何处理峰值流量?你可以通过消息队列将请求放到一个持久化队列中,然后再一并处理它们。这是一个非常有用的特性,不过它也受限于几个 因素——你的请求是在UI后台处理,还是需要即时响应?serlvet容器的线程池某种程度上可以当作是一个队列,用户最终会拿到响应,但是得需要等待(如果线程的超时时间过短的话,请求可能会丢失)。

    你可以使用一个内存队列来存储那些较重的请求(得在UI后台进行处理)。不过注意了,你的队列并不是默认高可用的。比如说,如果一个消息队列节点挂掉了,你的消息就丢失了。因此,不去使用应用节点内的内存队列,而是去使用一个消息队列,这可能并没有什么优势。

    消息队列使得我们可以进行异步处理——这的确是个有用的特性。你不希望在用户等待的时候做一些很重的操作。不过你也可以使用一个内存队列,或者简单地启动一个新的线程(比如Spring的@Async注解)。这样又有另一个问题——如果消息丢失的话是否有问题?如果你应用处理请求的节点挂了,你可以进行恢复吗?你会发现这事会经常发生,如果不保证所有消息都处理到的话,很难保证功能的正确性。因此,仅将较重的调用进行异步处理是比较可取的。

    把消息放到队列以便让另一个组件来进行处理,对于这个场景,如果消息丢失是无法接受的 ,这也有一个很简单的解决方案——数据库。你可以把一条processed=false的数据存储到数据库中。然后再运行一个调度作业,将所有未处理的记录挑选出来,异步地进行处理。当处理完成的时候,将标记设为true。我经常用这个方法,包括在一些大型的线上系统中,它也工作得挺好的。

    这样你还能不断地对你的应用节点进行扩展,只要它们的内存中没有任何的持久化状态的话。不管你是否使用了消息队列都可以(临时的内存处理队列并不属于持久化状态)。

    为什么我要给经常用到的消息队列提供一些备选方案?因为如果你由于不恰当的原因选择了它,那么消息队列可能会成为一个负担。它们并非如想像中那样容易使用。首先,它有一个学习曲线。一般来说,你集成的组件切分得越多,就越容易出现问题。其次,还有一个设置及配置的成本。比如说,当消息队列需要在一个集群中运行的话,比如说多个数据中心,那么这就变得复杂了。

    高可用性并不是上来就有的——默认它是不会打开的。还有就是你的应用节点如何连接到消息队列?通过一个刷新的连接池,或者使用短生命周期的DNS记录,还是通过一个负载均衡器?你的队列可能还有许多配置项,大小是多少,行为是怎样的(消费者需不需要确认接受,要不要通知处理失败,多个消费者能够取到同一个消息吗,消息有没有TTL,等等)同时还有网络及消息传递的开销,尤其是现在大家都喜欢用XML或者JSON来传输消息。如果你过度地使用了消息队列,那么它会增加你系统的延时。

    最后一点,但并不是最次要的——如果出现问题的话,使用消息队列会让问题跟踪变得异常困难。你没法在IDE中看到所谓的调用层次,因为一旦你发送消息到队列里了,你就得自己去查找它在哪里处理的了。这可不是听起来那么简单的。你看到了吧,它会给你增加许多的复杂性,以及许多需要注意的东西。

    通常而言,在某些上下文中,消息队列还是非常有用的。当它们的确适合的话,我也会在项目中使用它们——比方说,我们不想丢失消息,但又希望能快速地进行处理。我也见过它在一些不太常见的场景中使用的情况,比如说只有一个应用节点来进行消费,不管是哪个节点投递过来的消息。你还可以看下stackoverflow上的这个问题。还有一些使用场景就是,或许你的确需要进行多语言间的通信,又或者你的数据流已经过于复杂了,不使用新的消息消费者而是增加新方法调用的话代价会很大。

    我想说的是那句老掉牙的真理“杀鸡焉用牛刀”。如果你不是很确定已经没有别的更容易管理和维护的方法,一定要使用消息队列的话,最好不要使用它。不要因为”万一它有用呢“而去用它——只有你确实觉得需要的话再去使用。因为很有可能,就像这里说到的这个项目一样,消息队列其实是没有必要的。

    6.2如何避免消息丢失


    选择能够支持消息持久化的MQ方案。如:ActiveMQ、RabbitMQ等,给消息一个处理状态如:process=false。

    还可以使用缓存方案做:如Redis,它本身也是支持持久化的。

    7.本文参考资料来源


    消息队列MQ的原理及实现方法:http://blog.csdn.net/lzq_csdn_th/article/details/51945408

    关于消息队列的使用:http://www.cnblogs.com/linjiqin/p/5720865.html

    消息队列使用的四种场景介绍:http://blog.csdn.net/cws1214/article/details/52922267

    使用消息队列的十个理由:http://www.oschina.net/translate/top-10-uses-for-message-queue?p=2

    国外的一款消息队列IronMQ:http://iron.io/products/mq?rc=blog_mq_t10

    你可能并不需要消息队列:http://kb.cnblogs.com/page/212710/

    展开全文
  • 消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。 当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、...

    消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。

    当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的Notify、MetaQ、RocketMQ等。

    本文主要探讨主流的消息队列MQ比较,特征,以及典型使用场景。

    目前主流的MQ产品

    消息中间件系列(三):主流的消息队列中间件有哪些?

    1.ZeroMQ

    号称最快的消息队列系统,尤其针对大吞吐量的需求场景。

    扩展性好,开发比较灵活,采用C语言实现,实际上只是一个socket库的重新封装,如果做为消息队列使用,需要开发大量的代码。ZeroMQ仅提供非持久性的队列,也就是说如果down机,数据将会丢失。其中,Twitter的Storm中使用ZeroMQ作为数据流的传输


    2.RabbitMQ

    结合erlang语言本身的并发优势,支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级,更适合于企业级的开发。

    性能较好,但是不利于做二次开发和维护。


    3.ActiveMQ

    历史悠久的开源项目,是Apache下的一个子项目。已经在很多产品中得到应用,实现了JMS1.1规范,可以和spring-jms轻松融合,实现了多种协议,不够轻巧(源代码比RocketMQ多),支持持久化到数据库,对队列数较多的情况支持不好。


    4.Redis

    做为一个基于内存的K-V数据库,其提供了消息订阅的服务,可以当作MQ来使用,目前应用案例较少,且不方便扩展。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。


    测试数据分为 128Bytes、512Bytes、1K和10K四个不同大小的数据。

    消息中间件系列(三):主流的消息队列中间件有哪些?

    实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如 果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于 Redis。


    5.Kafka/Jafka

    Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。

    具有以下特性:

    • 快速持久化,可以在O(1)的系统开销下进行消息持久化;
    • 高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;
    • 支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。
    • Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。

    何时需要消息队列

    当你需要使用消息队列时,首先需要考虑它的必要性。

    可以使用mq的场景有很多,最常用的几种:

    1. 做业务解耦
    2. 最终一致性
    3. 广播
    4. 错峰流控等

    反之,如果需要强一致性,关注业务逻辑的处理结果,则RPC显得更为合适。

    消息队列使用场景

    消息中间件系列(三):主流的消息队列中间件有哪些?

    1.解耦

    解耦是消息队列要解决的最本质问题。所谓解耦,简单点讲就是一个事务,只关心核心的流程。而需要依赖其他系统但不那么重要的事情,有通知即可,无需等待结果。换句话说,基于消息的模型,关心的是“通知”,而非“处理”。

    举一个例子,关于订单系统,订单最终支付成功之后可能需要给用户发送短信积分什么的,但其实这已经不是我们系统的核心流程了

    如果外部系统速度偏慢(比如短信网关速度不好),那么主流程的时间会加长很多,用户肯定不希望点击支付过好几分钟才看到结果。那么我们只需要通知短信系统“我们支付成功了”,不一定非要等待它立即处理完成


    2.最终一致性

    最终一致性指的是两个系统的状态保持一致,要么都成功,要么都失败

    当然有个时间限制,理论上越快越好,但实际上在各种异常的情况下,可能会有一定延迟达到最终一致状态,但最后两个系统的状态是一样的。

    业界有一些为“最终一致性”而生的消息队列,如:

    • Notify(阿里)
    • QMQ(去哪儿)等

    其设计初衷,就是为了交易系统中的高可靠通知。


    以一个银行的转账过程来理解最终一致性,转账的需求很简单,如果A系统扣钱成功,则B系统加钱一定成功。反之则一起回滚,像什么都没发生一样。


    然而,这个过程中存在很多可能的意外:

    1. A扣钱成功,调用B加钱接口失败。
    2. A扣钱成功,调用B加钱接口虽然成功,但获取最终结果时网络异常引起超时。
    3. A扣钱成功,B加钱失败,A想回滚扣的钱,但A机器down机。

    可见,想把这件看似简单的事真正做成,真的不那么容易。


    所有跨VM的一致性问题,从技术的角度讲通用的解决方案是:

    1. 强一致性,分布式事务,但落地太难且成本太高,后文会具体提到。
    2. 最终一致性,主要是用“记录”和“补偿”的方式。在做所有的不确定的事情之前,先把事情记录下来,然后去做不确定的事情,结果可能是:成功、失败或是不确定,“不确定”(例如超时等)可以等价为失败。成功就可以把记录的东西清理掉了,对于失败和不确定,可以依靠定时任务等方式把所有失败的事情重新搞一遍,直到成功为止。
    3. 回到刚才的例子,系统在A扣钱成功的情况下,把要给B“通知”这件事记录在库里(为了保证最高的可靠性可以把通知B系统加钱和扣钱成功这两件事维护在一个本地事务里),通知成功则删除这条记录,通知失败或不确定则依靠定时任务补偿性地通知我们,直到我们把状态更新成正确的为止。
    4. 整个这个模型依然可以基于RPC来做,但可以抽象成一个统一的模型,基于消息队列来做一个“企业总线”。
    5. 具体来说,本地事务维护业务变化和通知消息,一起落地(失败则一起回滚),然后RPC到达broker,在broker成功落地后,RPC返回成功,本地消息可以删除。否则本地消息一直靠定时任务轮询不断重发,这样就保证了消息可靠落地broker。
    6. broker往consumer发送消息的过程类似,一直发送消息,直到consumer发送消费成功确认。
    7. 我们先不理会重复消息的问题,通过两次消息落地加补偿,下游是一定可以收到消息的。然后依赖状态机版本号等方式做判重,更新自己的业务,就实现了最终一致性。

    最终一致性不是消息队列的必备特性,但确实可以依靠消息队列来做最终一致性的事情


    另外,所有不保证100%不丢消息的消息队列,理论上无法实现最终一致性。好吧,应该说理论上的100%,排除系统严重故障和bug。

    像Kafka一类的设计,在设计层面上就有丢消息的可能(比如定时刷盘,如果掉电就会丢消息)。哪怕只丢千分之一的消息,业务也必须用其他的手段来保证结果正确。


    2.广播


    消息队列的基本功能之一是进行广播。

    如果没有消息队列,每当一个新的业务方接入,我们都要联调一次新接口。有了消息队列,我们只需要关心消息是否送达了队列,至于谁希望订阅,是下游的事情,无疑极大地减少了开发和联调的工作量。

    比如本文开始提到的产品中心发布产品变更的消息,以及景点库很多去重更新的消息,可能“关心”方有很多个,但产品中心和景点库只需要发布变更消息即可,谁关心谁接入。


    3.错峰与流控

    试想上下游对于事情的处理能力是不同的。

    比如,Web前端每秒承受上千万的请求,并不是什么神奇的事情,只需要加多一点机器,再搭建一些LVS负载均衡设备和Nginx等即可。

    但数据库的处理能力却十分有限,即使使用SSD加分库分表,单机的处理能力仍然在万级。由于成本的考虑,我们不能奢求数据库的机器数量追上前端。

    这种问题同样存在于系统和系统之间,如短信系统可能由于短板效应,速度卡在网关上(每秒几百次请求),跟前端的并发量不是一个数量级。

    但用户晚上个半分钟左右收到短信,一般是不会有太大问题的。如果没有消息队列,两个系统之间通过协商、滑动窗口等复杂的方案也不是说不能实现。

    但系统复杂性指数级增长,势必在上游或者下游做存储,并且要处理定时、拥塞等一系列问题。而且每当有处理能力有差距的时候,都需要单独开发一套逻辑来维护这套逻辑。所以,利用中间系统转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。

    消息队列使用总结

    1.消息队列不是万能的,对于需要强事务保证而且延迟敏感的,RPC是优于消息队列的

    2.对于一些无关痛痒,或者对于别人非常重要但是对于自己不是那么关心的事情,可以利用消息队列去做。

    3.支持最终一致性的消息队列,能够用来处理延迟不那么敏感的“分布式事务”场景,而且相对于笨重的分布式事务,可能是更优的处理方式

    4.当上下游系统处理能力存在差距的时候,利用消息队列做一个通用的“漏斗”,在下游有能力处理的时候,再进行分发。

    5.如果下游有很多系统关心你的系统发出的通知的时候,果断地使用消息队列吧。


    money.jpg
    展开全文
  • 二、Redis,Memcache,MongoDb的特点 1.Redis 优点: 1.支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基数估算) 2.支持持久化操作,可以...
  • 目前在业界有哪些比较知名的消息引擎呢?如下图所示 这里面几乎完全列举了当下比较知名的消息引擎,包括: ZeroMQ 推特的Distributedlog ActiveMQ:Apache旗下的老牌消息引擎 RabbitMQ、Kafka:AMQP的默认...
  • Android消息推送:第三方消息推送平台详细解析

    万次阅读 多人点赞 2016-10-19 19:33:50
    消息推送在Android开发中应用的场景是越来越多了,比如说电商产品进行活动宣传、资讯类产品进行新闻推送等等,如下图: 本文将介绍Android中实现消息推送的第三方推送的详细解决方案 阅读本文前,建议先阅读我的写...
  • MFC消息分类与消息队列

    千次阅读 2017-02-08 11:22:22
    消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样。 time表示...
  • 消息中间件Kafka

    千次阅读 2016-11-07 17:05:02
    Kafka简介消息 Message网络中的两台计算机或者两个通讯设备之间传递的数据。例如说:文本、音乐、视频等内容。队列 Queue一种特殊的线性表(数据元素首尾相接),特殊之处在于只允许在首部删除元素和在尾部追加元素...
  • 手把手教你如何玩转消息中间件(ActiveMQ)

    万次阅读 多人点赞 2018-07-15 18:07:39
    非操作系统软件,非业务应用软件,不是直接给最终用户使用,不能直接给用户带来价值的软件,我们就可以称为中间件(比如Dubbo,Tomcat,Jetty,Jboss都是属于的)。 什么是消息中间件? 百度百科解释:消息...
  • Redis的特点

    千次阅读 2018-01-20 15:31:14
    我们看看它的特点。 一 独特的键值对模型 我们知道很多数据库只能处理一种数据结构: SQL数据库:处理表格。 MemCached:键值对数据库,键和值都是字符串。 文档数据库(MongoDB):由Json/Bson组成的文档。 ...
  • 我们将消息队列这个组件加入到了我们的商城系统里,并且通过秒杀这个实际的案例进行了实际演练,知道了它对高并发写流量做削峰填谷,对非关键业务逻辑做异步处理,对不同的业务系统做解耦合。场景:现...
  • MQ消息队列使用场景

    千次阅读 多人点赞 2017-12-19 14:09:33
    一、消息队列概述 消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,...
  • 点击上方“码农进阶之路”,选择“设为星标”回复“面经”获取面试资料分布式消息系统作为实现分布式系统可扩展、可伸缩性的关键组件,需要具有高吞吐量、高可用等特点。而谈到消息系统的设计,就回避...
  • 分布式-消息中间件介绍

    万次阅读 2018-07-26 16:01:46
    一、消息队列概述 消息队列中间件是分布式系统中重要的组件 主要解决应用耦合,异步消息,流量削锋等问题。实现高性能,高可用,可伸缩和最终一致性(分布式事务)架构。是大型分布式系统不可缺少的中间件。 目前在...
  • RabbitMQ的特点与应用场景(二)

    千次阅读 2018-12-18 11:48:05
    1、RabbitMQ的主要特点 (1)可靠性:RabbitMQ可通过队列持久化,交换机持久化,消息持久化及ACK回应等机制保证可靠性 (2)支持多种语言与协议:RabbitMQ几乎支持所有的编程语言,还支持AMQP,STOMP,MQTT等多种...
  • 分布式消息系统作为实现分布式系统可扩展、可伸缩性的关键组件,需要具有高吞吐量、高可用等特点。而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一款高...
  • 【RabbitMQ消息中间件】1.RabbitMQ简介

    千次阅读 2018-02-25 20:28:02
    遵循Message Queue规则开发出来的,具有消息队列特点的产品,都可以称之为“消息中间件”(JMS消息服务器)。目前业内有很多消息中间件产品,例如Apache出品的“ActiveMQ”和“Kafka”(分布式发布订阅消息系统)、...
  • 消息中间件 —— 简介

    千次阅读 2020-05-18 11:03:29
    常用的消息中间件有哪些? 什么是消息中间件? 上面提到过消息中间件,那么什么是消息中间件呢?     消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行 分布式系统 ...
  • 分布式消息系统作为实现分布式系统可扩展、可伸缩性的关键组件,需要具有高吞吐量、高可用等特点。而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一...
  • 分布式消息中间件-Rocketmq

    万次阅读 多人点赞 2017-11-28 23:02:24
    消息中间件主要是实现分布式系统中解耦、异步消息、流量销锋、日志处理等场景,后面我也会结合一些场景进行探讨。现在生产中用的最多的消息队列有Activemq,rabbitmq,kafka,rocketmq等。  不过这个题目写的有点...
  • HDFS的特点

    千次阅读 2017-07-24 19:31:42
    4.当block1接收完毕,DN1,DN2,DN4向NN汇报消息(接收完毕),DN1再向client汇报block1接收完毕,于是,client开始发送block2. 5.... hdfs读取 1.client会想NameNode发送读取请求,NameNode会将元数据查出来,每一个...
  • 消息队列介绍

    千次阅读 2019-01-19 18:04:21
    消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,...
  • kappa架构的层级及其特点

    千次阅读 2020-01-02 21:16:04
    1、消息传输层 这一层有如下特点 持久性------数据可任意设定存储时间 分布式------数据分布式存储 数据可重放------数据可以被replay,从头重新处理 高性能------能够提供高性能数据读写访问 有了这几点保证之后...
  • Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于...
  • kafka实战篇(二):消息消费实战

    千次阅读 多人点赞 2020-04-24 16:00:44
    关于三种分区分配策略,我的一篇文章已经举例讲的很清楚了,这里就不重复做对应的实验了,强烈建议对照着,多启动几个消费者实验一下数据的消费情况,来印证一下它们的特点,加深印象。 相关文章:深入分析Kafka...
  • OpenFlow消息类型

    千次阅读 2018-07-08 21:16:09
    最近在接触SDN(软件定义网络),本文针对SDN南向接口中的OpenFlow协议消息类型进行简单整理,参考链接为... OpenFlow协议支持三种消息类型,分别为:controll...
  • Zookeeper介绍和特点

    千次阅读 2019-05-15 22:58:21
    另外,在ZooKeeper的官方文档中也指出,ZAB协议并不像 Paxos 算法那样,是一种通用的分布式一致性算法,它是一种特别为Zookeeper设计的崩溃可恢复的原子消息广播算法。 6.2 ZAB 协议介绍 ZAB(ZooKeeper Atomic ...
  • 理解面向消息的中间件和JMS

    千次阅读 2015-08-08 11:20:29
    第二章:理解面向消息的中间件和jms 2.1企业级消息简介 企业级消息是在分布式系统之间进行传递的数据。当前有很多方法可以完成这一目的: 1.远程过程调用,例如COM、CORBA、DCE和EJB 2.事件通知、进程间通信和消息...
  • 分布式消息系统作为实现分布式系统可扩展、可伸缩性的关键组件,需要具有高吞吐量、高可用等特点。而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 44,850
精华内容 17,940
关键字:

哪些属于消息的特点