webapi 持续接收 消息队列_webapi 用什么消息队列 - CSDN
精华内容
参与话题
  • 简单的说就是在对现有系统影响最小的情况下,系统功能可持续扩展及提升的能力,讲扩展性之前,我先讲下扩展性和伸缩性的区别,因为这两个点经常有人会混淆; 扩展性:指对现有系统影响最小的情况下,系统功能可持续...

    前言

    续上节大型网站架构核心要素性能之后,我们今天要讲的是第四个要素:扩展性,什么叫扩展性呢?简单的说就是在对现有系统影响最小的情况下,系统功能可持续扩展及提升的能力,讲扩展性之前,我先讲下扩展性和伸缩性的区别,因为这两个点经常有人会混淆;

    扩展性:指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力,表现在系统基础设施稳定,不需要经常变更,应用之间较少依赖和耦合,对需求变更可以快速敏捷响应。它是系统设计层面的开闭原则(对扩展开放,对修改关闭),架构设计考虑未来功能扩展,当系统增加新功能时,不需要对现有系统的结构和代码进行修改;

    伸缩性:指系统能够通过增加或者减少自身资源规模的方式来增强或者减小自己计算处理事务的能力,如果这种增减是成比例的,那就称作线性伸缩性。在网站架构中,通常指利用集群的方式增加服务器数量、提高系统的整体事务吞吐能力。

    搞清楚扩展性和伸缩性之间的区别之后,那么我们就从下面这几个方面开始讲如何构建可扩展性的架构设计:构建可扩展的网站架构、利用分布式消息队列降低系统耦合性、利用分布式服务打造可复用的业务平台、可扩展的数据结构、利用开放平台建设网站生态圈

     

    构建可扩展的网站架构

    开发低耦合系统是软件设计的终极目标之一,低耦合的系统更容易扩展,低耦合的模块更容易复用,一个低耦合的系统设计也会让开发过程和维护变得更加轻松和容易管理。那么如何分解系统的各个模块,如何定义各个模块的接口、如何复用组合不同的模块构成一个完整系统就成了软件设计中最有挑战的工作;

    设计网站的可扩展性架构的核心思想在于模块化,并在此基础之上,降低模块间的耦合性,提高模块的复用性;上节我们讲到网站通过分层和分割的方式进行架构伸缩,分层和分割也是模块化设计的主要手段,利用分层和分割的方式将软件分为若干个低耦合的独立化组件,这些组件模块以消息传递及依赖调用的方式聚合成一个完整的系统。

    在大型网站中这些模块通过分布式部署的方式,独立的模块部署在独立的服务器(集群)上,从物理上分离模块之间的耦合关系,进一步降低耦合性提高复用性;模块分布式部署以后具体聚合方式主要有分布式消息和分布式服务

     

    利用分布式消息队列降低系统耦合性

    如果模块之间不存在直接调用,那么新增的模块或者修改的模块就对其他模块影响最小,这样系统的可扩展性就会好些;

    • 事件驱动架构:通过在低耦合的模块之间传输事件消息,以保持模块的松散耦合,并借助事件消息的通信完成模块间合作,典型的事件驱动就是生产者消费者模式,在大型网站架构中,具体的实现方式很多,典型的就是分布式消息队列

      消息队列利用发布-订阅模式工作,消息发送者发布消息,一个或者多个消息接收者订阅消息。消息发送者是消息源,在对消息进行处理后将消息发送至分布式消息队列,消息接收者从队列中获取消息进行处理。整个过程中,消息发送者和消息消费者之间没有直接耦合,消息发送者将消息发送给消息队列之后就结束了对消息的处理,而消息接收者只需要从队列去获取消息进行处理就可以,不需要知道消息从何而来,由谁生产。对新增业务,如果需要调用消息,只需要订阅该消息,对原有系统和业务没有任何影响,从而实现了网站业务的可扩展性;

      消息接收者在对此消息进行过滤、处理、包装后,可以构成一个新的消息,继续发送出去,等待其他消息接收者订阅处理该消息;因此基于事件驱动的业务架构可以是一系列流程;

      事件驱动设计优势:由于消息发送者不需要等待消息接收者处理数据就可以直接返回,系统具有更好的响应延迟;同时在网站访问高峰的时候,消息可以暂时存储在消息队列里面,等待接收者根据自身负载处理能力控制消息处理速度,减轻数据库等后端存储的负载压力。

    • 分布式消息队列:队列是一种先进先出的数据结构,之前我们也讲过这点,分布式消息队列可以看作将这种数据结构部署到独立服务器上,应用程序可以通过远程访问接口使用分布式消息队列,进行消息存取操作,进而实现分布式的异步调用,基本原理如下图:

      消息生产者通过远程访问接口将消息推送给消息队列服务器,消息队列服务器将消息写入本地内存队列后立即返回成功响应给消息生产者。消息队列服务器根据消息订阅列表查找订阅该消息的消息消费者应用程序,将消息队列中的消息按先进先出的原则通过远程通信接口发送给消息消费者程序。

      目前开源的分布式消息队列有很多,比如RocketMQ,kafka等等,这些产品除了实现分布式消息队列的一般功能,在可用性,伸缩性,数据一致性,性能和可管理性方面也做了很大改善。

      伸缩性:由于消息队列服务器上的数据可以看作是被即时处理的,因此类似于无状态的服务器,伸缩性设计比较简单,将新服务器加入分布式消息队列集群中,通知生产者服务器更改消息队列服务器列表即可;

      可用性:为了避免消费者进程缓慢,分布式消息队列服务器内存空间不足造成的问题,如果内存队列满了,就会将消息写入磁盘,消息推送模块在将内存队列消息处理完以后,将磁盘内容加载到内存队列继续处理;

      防消息丢失:为了避免消息队列服务器宕机造成消息丢失,会将消息成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者处理之后才删除消息,在消息队列服务器宕机时,生产者服务器会选择分布式消息队列服务器集群中其他的服务器发布消息;

      分布式消息队列可以很复杂,例如企业总线ESB或者面向服务架构SOA;也可以很简单,例如我们就用MySQL来当做分布式消息队列,生产者将消息存入数据库,消费者按生成时间从数据库取消息消费,这就实现了一个简单的分布式消息队列,而且还有结合MySQL的主从,读写分离手段达到较高的可用性和性能指标。

     

    利用分布式服务打造可复用的业务平台

    使用分布式服务是降低系统耦合性的另一个手段,如果说分布式消息队列通过消息对象分解系统耦合性,不同子系统处理同一个消息;那么分布式服务则是通过接口分解系统耦合性,不同子系统通过相同的接口进行服务器调用。

    随着网站由小变大,表现为整个网站单一应用系统逐步膨胀发展的过程,在这个过程中,网站功能业务日益复杂,整个应该系统逐渐变成一个错综复杂的大系统,如果不使用分布式服务来解耦的话就会带来如下问题:编译部署困难;代码分支管理困难;数据库连接耗尽;新增业务困难。

    解决上述的问题方案就是拆分,将模块独立部署,降低系统耦合性。拆分又分为横向拆分和纵向拆分;

    横向拆分:将复用业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式业务,不需要依赖具体的模块代码,即可快速搭建一个应用系统,而模块内部业务逻辑变化时,只要接口保持一致就不会影响业务程序和其他模块。

    纵向拆分:将一个大应用拆分为多个小应用,如果新增业务较为独立,那就直接将其设计部署为一个独立的web应用系统。

    纵向拆分相对比较简单,通过梳理业务,将较少相关的业务剥离,使其成为独立的web应用,而横向拆分,不但需要识别可复用的业务,设计服务接口,规范服务依赖关系,还需要一个完善的分布式管理框架。

    • 大型网站分布式服务的需求与特点

      • 服务注册与发现:基本上现在都是基于zk来实现的

      • 服务调用:通过SOAP协议实现

      • 负载均衡:对热门服务,需要部署在一个集群上,分布式服务框架要能够支持服务请求者使用可配置的负载均衡算法访问服务,使服务提供者集群实现负载均衡

      • 失效转移:分布式服务框架支持服务者提供的失效转移机制,当某个服务实例不可用,就将访问切换到其他服务实例上,以实现服务整体高可用

      • 高效远程通信:对于大型网站,核心服务每天的调用次数达到数以亿计,如果没有高效的远程通信手段,服务调用就会成为整个系统性能的瓶颈

      • 整合异构系统:由于网站可能会使用不同的语言开发部署在不同的平台上,所以分布式服务框架需要整合这些异构系统

      • 对应用最少侵入:网站技术是为业务服务的,是否使用分布式服务需要根据业务发展规划,分布式服务也需要渐进式的演变,甚至出现反复,即使用了分布式服务后又退回到集中式部署,分布式服务框架需要支持这种渐进式演变和反复,当然服务模块本身也需要支持可集中式部署,也可分布式部署

      • 版本管理:分布式服务框架支持服务多版本发布,服务提供者先升级接口发布新版本服务,并同时提供旧版本的服务供请求者调用,当请求者调用接口升级后才可以关闭旧版本服务

      • 实时监控:没有监控的服务是不可能实现高可用的,分布式服务框架还需要监控服务提供者和调用者的各项指标

    • 分布式服务框架设计:大型网站需要更简单更高效的分布式服务框架构建其SOA,这里以阿里巴巴的Dubbo为例,分析其架构设计,如下图所示:

      流程分析

      服务消费者程序通过服务接口使用服务,而服务接口通过代理加载具体服务,具体服务可以是本地的代码模块,也可以是远程的服务,因此对应用侵入较少(应用程序只需要调用服务接口,服务框架根据配置自动调用本地或者远程实现);

      服务框架客户端模块通过服务注册中心加载服务提供者列表(服务提供者启动后自动向服务注册中心注册自己可提供的服务接口列表),查找需要的服务接口,并根据配置的负载均衡策略将服务调用请求发送到某台服务提供者服务器。如果服务调用失败,客户端模块会自动从服务者列表选择一个可提供同样服务的另一台服务器重新请求服务,实现服务的自动失效转移,保证服务高可用;

      Dubbo的远程服务通信模块支持多种通信协议和数据序列化协议,使用NIO通信框架具有更高的网络通信性能。

     

    可扩展的数据结构

    传统的关系数据库为了保证关系运算(SQL)的正确性,在设计数据库表结构的时候,就需要指定表的schema-字段名称,数据类型等,并要遵循特定的设计范式,这些规范带来的一个问题就是僵硬的数据结构难以面对需求变更带来的挑战,有些应用系统设计者通过预先设计一些冗余字段来应对,但是显然这是很糟糕的设计,难以做到扩展,那么有没有更好的方案呢,无需修改表结构就可以新增字段呢?很多NoSQL数据库使用ColumnFamily(列族)设计就是一种解决方案,这是一种面向列族的稀疏矩阵存储格式,使用ColumnFamily结构的NoSQL数据库,创建表的时候,只需要指定ColumnFamily的名字,无需指定字段(Column),可以在数据写入时在指定,通过这种方式数据表可以包含数百万的字段,使得应用程序的数据结构可以随意扩展,而在查询时,可以通过指定任意字段名称和值进行查询。

     

    利用开放平台建设网站生态圈

    大型网站为了更好的服务自己的用户,开发更多的增值服务,会把网站的服务封装成一些调用接口开放出去,提供开发接入文档,供外部的第三方开发者使用,这个提供开放接口的平台称为开放平台。第三方开发者利用这些开放的接口开发应用程序或者网站,为更多的用户提供价值。网站、用户、第三方开发者互相依赖,形成一个网站的生态圈,既为用户提供更多的价值,也提高了网站和第三方开发者的竞争力和盈利能力。

    开放平台是网站内部和外部交互的接口,外部需要面对众多的第三方开发者,内部需要面对网站内许多的业务服务。开放平台的架构设计大同小异,如下图所示:

     

                         

    API接口:开放平台暴露给开发者使用的一组API,其形式可以是restful,RPC等各种形式;

    协议转换:将各种API输入转换成内部服务可以识别的形式,并将内部服务的返回封装成API的格式;

    安全:除了一般应用需要的身份识别,权限控制等安全手段,开放平台还需要分级的访问带宽限制,保证平台资源被第三方应用公平合理使用,也保护网站内部服务不会被外部应用拖垮;

    审计:记录第三方应用的访问情况,并进行监控。计费等;

    路由:将开放平台的各种访问路由映射到具体的内部服务;

    流程:将一组离散的服务组织成一个上下文相关的新服务,隐藏服务细节,提供统一接口供开发者调用。

    展开全文
  • 根据RabbitMQ实战 高效部署分布式消息队列这本书来具体总结下

    仅供个人学习,如有抄袭请包容cry....

    理解消息通信

    一、       消息通信的概念--消费者、生产者和代理

    生产者创建消息,消费者接受这些消息。你的应用程序可以作为生产者,向其他应用程序发送消息,或者作为一个消费者,接收消息。也可以在两者之间进行切换。不过在此之前,它必须先建立一条信道(channel)。不论你是发布消息、订阅队列或是接受消息都是通过信道完成。

    二、       AMQP元素--交换器、队列和绑定

    从概念上讲,AMQP消息路由必须有三部分:交换器、队列和绑定。生产者把消息发布到交换器上;消息最终到达队列,并被消费者接受;绑定决定了消息如何从路由器路由到特定的队列。在研究交换器和绑定之前,需要先理解队列的概念和工作原理。如下图:


    消费者通过以下两种方式从特定队列中接收消息:

    (1) 通过AMQP的base.consumer命令订阅。这样做会将信道置为接收模式,直到取消对队列的订阅为止。

    (2) 有些时候,你只想从队列中获取单条消息而不是持续订阅。向队列请求单条消息是通过AMQP的base.get命令实现的。大致上讲,base.get命令会订阅消息,获取单条消息,然后取消订阅。消费者理应始终使用base.consumer来实现高吞吐量。

     

    A: 当有多个消费者订阅到同一个队列上是,消息是如何发布的:

    Q: 队列收到的消息将以循环(round-robin)的方式发送给消费者,每条消息只会发送给一个消费者。消息确认接收机制:消费者必须通过AMQP的base.ask命令显式的向RabbitMQ发送一个确认消息,或者在订阅到队列的时候就将base.ask参数设置成true。消费者对消息的确认和告诉生产者消息已经被接收这两件事毫不相关。

    如何创建队列。生产者和消费者都能使用AMQP的base.declare命令创建队列。如果消费者在同一条信道上订阅了另一条对列的话,就无法再声明队列了。则必须先取消队列,将信道置为“传输”模式。

    队列设置了一些有用的参数:

    1.exlusion--将参数设置成true后队列将变为私有,限制一个队列中只能有一个消费者。

    2.auto-delete--将参数设置为true后,最后一个消费者取消订阅之后队列将自动移除。

    联合:交换器和绑定。

    Q: 消息是如何到达队列的呢?

    A: 路由键规则来指定消息从路由器到哪个队列。

    Q: 那它是如何处理投递到多个队列的情况呢?

    A: 协议中定义的不同类型交换器发挥了作用。一共四种类型:direct、fanout、topic和header。

    direct:如果路由键匹配的话,消息就被投递到对应的队列。

    base_publish($msg,'默认交换器','队列名称');


    fanout:当你发送一条消息到fanout路由器时,他会把消息投递给所有附加在此交换器上的队列。可以轻而易举地添加应用程序的功能。

    base_publish($msg,'logs-exchange','error.msg-inbox');


    topic:跟direct比较相像,有一些通配规则。单个“.”把路由分成几部分,“*”匹配特定位置的任意文本,“#”匹配所有规则。

    queue_bind('msg-inbox-errors','logs-exchange','error.msg-inbox');

    queue_bind('msg-inbox-errors','logs-exchange','*.msg-inbox');

    queue_bind('all-logs','logs-exchange','#');

    三、       虚拟主机

    虚拟主机vhost是AMQP概念的基础,你必须在连接时进行指定。RabbitMQ包含了开箱即用的默认虚拟主机"/",因此使用非常简便。vhost之间是绝对隔离,保障了队列和交换机的安全性,因此消息路由的组件也无法进行交互。

    rabbitmqctl add_vhost[vhost_name]

    rabbitmqctl delete _vhost[vhost_name]

    四、       消息持久化

    重启rabbitmq服务器后,那些队列和交换器就都消失了,原因在于每个队列和交换器的durable属性,该属性默认情况为false。如果需要持久化,单纯将队列和交换器的durable属性设置为true是不够滴。消息发布之前,通过把它的“投递模式”(delivery mode)选项设置为2来把消息标记为持久化。代价则是消耗性能,虽然重启RabbitMQ服务器后队列和交换器能恢复。

    五、       一条消息经历从生产者到消费者的生命周期

    发布者需要完成的任务:1.连接到RabbitMQ。2.获取信道。3.声明交换机。4.创建消息。5.关闭消息。6.关闭信道。7.关闭连接。

    消费者需要执行的任务:1.连接到RabbitMQ。2.获取信道。3.声明交换机。4.声明队列。5.把队列和交换机绑定起来。6.消费消息。7.关闭信道。8.关闭连接。

    使用发送方确认模式来确认投递。

    运行和管理RabbitMQ

    一、       服务器管理—启动和停止节点

    运行子系统:rabbitmq安装目录下找到./sbin目录,运行./rabbitmq-server。通过日志查看运行情况,日志目录/var/log/rabbitmq/下。以守护程序的方式在后台运行:./rabbitmq-server detached,至此rabbitmq服务启动成功。

    当运行rabbitmq连接到控制台时,你按下CTRL+C组合键后你猜是哪个..

    在rabbitmq安装目录下运行./sbin/rabbitmqctl stop来干净地关闭。

    rabbitmq配置文件目录在/etc/rabbitmq/rabbitmq.config。

    二、       权限配置

    RabbitMQ权限工作原理:用户可以为连接到RabbitMQ主机的应用程序设计不同级别的权限(读、写和“/”或配置)。

    管理用户:在RabbitMQ中,用户是访问控制的基本单元。针对一到多个vhost,其可以被赋予不同级别的访问权限,并使用标准的用户名/密码对来认证用户。对用的增加、删除以及列出列表,都非常简单。这些操作都是通过rabbitmqctl完成的。

    添加用户:rabbitmqctl add_user username password

    删除用户:rabbitmqctl delete_user username

    用户列表:rabbitmqctl list_users


    设置权限:rabbitmqctl set_permissions –p sycamore \ cashing-tier “.*” “.*” “.*”

    –p sycamore:告诉set_permissions条目应该应用在哪个vhost上面。

    cashing-tier:被授予权限的用户。

    “.*” “.*” “.*”:这些是授予的权限。这些值分别映射到配置、写和读。

    移除权限:rabbbimqctl clear_permissions –p sycamore cashing-tier

    权限列表:rabbitmqctl list_user_permissions cashing-tier

    三、       使用统计

    其中经常看到的-p选项,它指明了虚拟主机和路径信息。

    rabbitmqctl list_queues -p sycamore 列出虚拟主机为sycamore的队列列表

    list_queues [-p Vhost_Path] [<QueueInfoItem>]

    rabbitmqctl list_exchanges

    list_exchanges  [ExchangeInfoItem]

    rabbitmqctl list_bindings

    理解RabbitMQ日志,LOG_BASE=/var/log/rabbitmq

    四、       RabbitMQ和Erlang问题疑难解答

    由badrpc、nodedown和其他Erlang引起的问题

    1. Erlang Cookie

    使用rabbitmqctl命令时常出现一些莫名错误。先理解下rabbitmqctl的工作原理。rabbitmqctl命令先启动Erlang节点,并从那个使用Erlang分布式系统尝试连接RabbitMQ节点。要完成这项工作需要两样东西:合适的Erlang Cookie和合适的主机名称。

    Q: 那么什么是Erlang Cookie呢?

    A: Erlang节点通过交换作为秘密令牌的Erlangcookie以获得认证。Erlang将令牌存储于home目录下的.erlang.cookie文件中

    2. Erlang节点

    当你启动Erlang节点时,你可以给它两个互斥的节点名选项,name和sname。

    当你想让rabbitmqctl能够连上RabbitMQ时,你必须使得这些参数两边都能匹配(rabbit@hostname)。

    3. Mnesia和主机名

    RabbitMQ使用Mnesia存储队列、交换器、绑定等信息。RabbitMQ启动时做的一件事就是启动Mnesia数据库。如果启动Mnesia失败,则RabbitMQ也会跟着失败。而导致Mnesia失败的原因大致有二:第一个也是最常见的MNESIA_BASE目录的权限问题。另一个常见问题是读取表格失败。如果主机名更改了,或是服务器运行在集群模式下,无法在启动的时候连接到其他节点,都会导致启动失败。

    4. Erlang故障排除技巧

    以test作为节点名启动Eralng节点:erl  sname  test。

    执行node()函数会展示--Erlang中方括号为界的列表--你连接上的节点列表。

    通过使用rpc:call,同时提供节点、模块、函数和参数作为入参,你可以在远程rabbit上执行其他参数以获取不同的信息。

    解决Rabbit相关问题:编码与模式

    一、       面向消息通信来设计应用程序

    1. 异步状态思维(分离请求和动作)

    2. 提供扩展性:没有负载均衡器的世界

    3. 使用AMQP来解耦应用程序最大好处:免费的API,语言不会约束消息通信。

    二、       消息通信模式

    解决耗时的任务和整合用不同语言编写的应用程序。这两个看似有不同的问题,但却有着共同的本质:解耦请求和操作。或者换种说法,这两个问题均需要从同步编程模式转向异步编程模式。

    三、       发后即忘模型

    匹配该模式的两种一般类型的任务

    1. 批处理(batchprocessing)--针对大型数据集合的工作和转换。这种类型的任务可以构建为单一的任务请求,或者多个任务对数据集合的独立部分进行操作。

    2. 通知(notifications)--对发生事件的描述。内容可以是消息的日志,也可以是真实的报告通知给另一个程序或者是管理员。

    这两个例子符合我们之前提到的两种类别:第一个是告警框架(发送告警)。另一个是将单张图片上传并将其转换成众多图片格式和尺寸(并行处理)。

    四、       用RabbitMQ实现RPC

    1. 私有队列和确认发送。

    2. 使用reply_to来实现简单的jsonRPC

    集群并处理失败

    一、       RabbitMQ集群架构

    RabbitMQ最优秀的功能之一就是其内建集群。同时能够将集群在5分钟内构建并运行起来。

    RabbitMQ内建集群的设计用于完成两个目标:允许消费者和生产者在Rabbit节点奔溃的情况下继续运行,以及通过添加更多的节点来线性扩展消息通信吞吐量。

    Q: RabbitMQ是如何记录你所有使用过的各种基础构件,同时他们又如何装配成一个消息通信服务器的呢?

    A: RabbitMQ会始终记录以下四种类型的内部元数据:

    1. 队列元数据--队列名称和属性(是否可持久化,是否自动删除)

    2. 交换器元数据--交换器名称、类型和属性(可持久化等)

    3. 绑定元数据--一张简单的表格展示了如何将消息路由到队列

    4. vhost元数据--为vhost内的队列、交换器和绑定提供命名空间和安全属性。

    我们深入到集群节点和他们如何存储元数据前,首先理解在集群环境中队列和交换器的行为。

    1. 集群中的队列。

    2. 分布交换器。

    3. 是内存节点还是磁盘节点。

    二、       在你的笔记本上搭建集群

    在笔记本上创建三个节点,然后将三个节点集群,具体操作可以参考之前两篇文章。

    三、       使用物理服务器创建集群

    分布在不同的服务器上创建不同的节点,将不同节点进行集群。

    四、       升级集群节点

    独立系统中升级节点只需解压新版本,然后运行即可,旧的数据也将会保留。如果是集群节点,需要备份配置信息后,关闭所有生产者等待消费者消费完队列中的所有信息(rabbitmqctl观察队列状态)。现在,关闭节点,并解压新版本到RabbitMQ到现有的安装目录。

    五、       与镜像队列一起工作

    当加入镜像队列后,信道负责将消息路由到合适的队列。


    镜像队列是如何影响事务和发送方确认模式的?

    1. 镜像队列主拷贝故障时,从拷贝变成主拷贝。

    2. 如果镜像队列失去一个从节点的话,则附加在镜像队列的任何消费者都不会注意到这一点。

    3. 如果客户端库不能支持消费者取消通知的话,你应该避免使用镜像队列。

    从故障中恢复

    一、       理解负载均衡

    负载均衡将服务器集群IP封装,提供暴露成统一接口。通过将负载均衡器放置在Rabbit的前端,你就可以让它来处理节点选择、故障服务器检测以及负载分布这些复杂的事情了。


    二、       安装并配置HAProxy来为Rabbit做负载均衡

    选择使用HAProxy的原因:它是免费的,而且非常可靠,并且为各种站点处理高负载,例如:StackOverFlow。同时,它可以运行在几乎所有的基于UNIX的平台上,并且非常容易配置。

    1. 安装HAProxy

    2. 配置HAProxy

    以上两步自己度娘。

    三、       重连并从故障中恢复

    现在开发系统上运行着负载均衡器,我们准备深入探索如何使用它来为消息通信应用程序植入故障转移和快速恢复的能力。

    1. 如果我重新连接到新的服务器,那么我的信道以及其上的所有消费循环会怎样呢?它们现在都失效了。你必须对它们进行重建。

    2. 当我进行重连的时候,我能否假设所有的交换器、队列和绑定仍然存在于集群之中?我能否重连之后立即开始从队列消费呢?

    Warren和Shovel:故障转移和复制

    一、       理解主/备方式(warren)

    集群迫使你不得不在以下两者之间做权衡:所有节点表现得像独立单元来分布负载的优点,但是在故障节点恢复前无法使用可持久化队列的缺点。这正是warren和Shovel的用武之地。

    二、       使用负载均衡器创建warren

    基于warren的负载均衡器的HAProxy配置。基于负载均衡器来做故障转移,最重要的是可以确保当故障转移发生时,你无须担心RabbitMQ无法在备用节点启动,因为它已经运行了。由于Rabbit始终在主节点和备用节点上运行,因此你们可以始终对它们进行监控。如果备机在派上用场之前就变为不可用的话,你在第一时间就能发现。这通过使用共享存储warren是无法做到的。

    三、       使用Shovel构建远距离复制

    在掌握了集群和warren之后,你就能处理故障并在数据中心之上进行扩展了,但是当你需要在不同的数据中心的Rabbit间复制消息时,改怎么办呢?这时,我们就需要Shovel了。

    1. 给Rabbit装备Shovel:Shovel插件介绍。

    2. 安装Shovel

    3. 配置并运行Shovel

    从Web端管理RabbitMQ

    一、       Managent插件相对于rabbitmqctl脚本的优势

    方便、简洁、功能齐全、浏览多方面同时监测。

    二、       启用RabbitMQ Management插件

    rabbitmq-plugins  enable  rabbitmq-management

    三、       Management插件功能

    四、       从Web控制台来管理用户、队列和交换器

    在web控制台上做如下操作:(具体结合界面应用)

    1. 创建用户

    2. 管理用户的权限

    3. 列出队列信息

    4. 创建队列

    五、       Management插件REST接口介绍

    1. 通过使用REST API,你可以轻松自动化那些到目前为止只能通过图形化界面完成的任务。

    2. CLI管理:一种更简洁的方式。

    3. 安装rabbitmqadmin脚本。

    4. 应用rabbitmqadmin脚本。

    使用REST API控制Rabbit

    一、       Rabbit REST API的限制和功能

    不管用API创建队列还是设置权限,每当使用PUT或POST动作的时候,都需要将函数参数编码为JSON格式的哈希表,然后添加到请求正文中。你可以通过浏览器访问http://localhost:55672/api来查看目前大多数(以及完整的)API列表和支持的HTTP动作。

    二、       访问消息通信数据统计和计数器

    Rabbit Management API使得你可以在任何能够访问网络的地方监控并控制Rabbit。具体详情看此书,代码来控制的。

    三、       自动化创建用户和虚拟主机

    我们在部署应用时,就使用了相似的脚本来自动化创建用户。通过构造这段脚本,你不仅学习了如何使用Management API来展示条目,还学习了如何展示条目列表,以及如何创建和删除这些条目。你这样将这些概念应用到处理其他条目/资源类型(用户、队列、交换器、连接、权限等)。具体脚本看此书。

    监控

    一、       编写Nagios健康检测的基础

    Nagios健康检测是一个独立程序,它在运行时监控服务并在程序停止运行时退出代码来指示服务的健康状态。从技术上来讲,你甚至不需要Nagios来运行健康检测--你可以在任何时候通过命令行执行并手工观测输出。Nagios健康检测可以用任何语言编写,可以是Python程序,甚至是BASE脚本。

    二、       使用AMQP和REST API来监控Rabbit内部状态

    构建的AMQP健康检测,当下列任务条件之一为真时,该检测程序会返回一个critical状态

    1. RabbitMQ没有响应TCP连接。

    2. 当发送AMQP命令时,Pika在接收到响应之前超时了。

    3. 当构造AMQP信道时,遇到了协议错误。

    仅当这些状态检测都为false时,健康检测程序才会返回OK状态。

    基于API的健康检测,aliveness-test,顾名思义,使用三个步骤来验证Rabbit服务器是否健康:

    1. 创建一个队列来接收测试消息。

    2. 用队列名称作为消息路由键,将消息发往默认交换器。

    3. 当消息到达队列的时候就消费该消息;否则就报错。

    三、       使用Rabbit可用并且能够进行响应

    有许多原因会致使RabbitMQ使用太多的内存,并达到Rabbit配置的最大内存上限。以下是最常见的几种原因:

    1. 应用程序有缺陷,消费消息之后忘记向RabbitMQ发回确认消息。这在高容量环境下,会导致成千上万条的消息堆积并耗尽Rabbit的内存。

    2. 应用程序使用RabbitMQ将大型数据(譬如图像)路由到处理节点。用不了多少张100MB大小的图像就可以将只有8GB内存大小的服务器内存耗尽。

    3. 使用了最新RabbitMQ版本中的新功能,但是该功能有个BUG会导致缓慢的内存泄漏。

    四、       观察队列状态以尽早检测消费者问题

    监控消费者是否正确运作的方式就是通过监控队列的消息总数,并在总数超过设定的warning或者critical阈值时触发警告。以下通过两种方式来监控队列消息总数:

    1. 使用AMQP的queue_declare()命令,设置passive=true参数来重新声明一个已存在的队列。当你在AMQP中声明一个队列时,如果将passive设置为true的话,那么该命令返回的结果中将包含队列消息的总数。

    2. 利用我们的老朋友RabbitManagement API来总队列上拉取数据统计,其中就有队列当前的消息总数。

    五、       检测消息通信结构中不合需求的配置更改

    确保消费者正常工作,检查消息通信结构配置问题:

    1. 通过AMQP监控队列等级。

    2. 使用REST API来监控队列级别。

    3. 建立队列的消息计数基准经验法则。

    提升性能,保障安全

    一、       交换器、队列和绑定的内存占用

    根据数据显示队列、交换器和绑定的内存占用很小,另一个施加在RabbitMQ上的硬性限制是每个Erlang节点的最大Erlang进程数。Erlang应用程序在整个生命周期中会多次创建并销毁进程。

    二、       消息持久化和磁盘I/O

    当发布消息时,你需要决定丢失其中的任何消息对你来说是否可以接受,这决定了deleverymode设置的值为1(非持久化)还是2(持久化)的问题。

    在消息消费过程中你该如何配置,加快消息投递的设定是no-ack标记,你可以在队列订阅时指明。

    路由算法和绑定规则,三种不同类型的交换器:direct、fanout和topic。每种交换器类型代表了服务器实现的特定路由算法。绑定规则的路由键模式将更占用内存。

     

    本节介绍了不同的算法和消息发布订阅设置如何影响整个系统的速度,以及像auto-ack模式标记设定能在很大程度上影响系统性能。

    三、       RabbitMQ的SSL连接及设置私钥架构

    1. SSL证书。

    2. 设置证书颁发机构。

    3. 生成根证书。

    4. 生成服务器端证书。

    5. 生成客户端证书。

    6. 启用RabbitMQ的SSL监听。

    7. 测试你的RabbitMQ SSL设置。

    聪明的Rabbit:扩展RabbitMQ

    一、       安装RabbitMQ插件

    我可以通过安装插件的方式来解决:

    1. 支持AMQP以外的协议。

    2. 不同的认证机制(LDQP,自定义数据库)。

    3. 消息复制。

    4. 新的交换器和路由算法。

    5. 消息日志和审计。

    如果你想启用的插件不是服务器发行的一部分该怎么办呢?首先,你得下载插件的.ez文件到RabbitMQ安装目录的plugins文件夹下,之后像往常一样运行./rabbitmq-plugins enable plugin_name命令即可。

    二、       实现自定义交换器插件

    1. 将交换器注册到Rabbit。

    2. 实现交换器behaviour。

    3. 编译自定义交换器。

    4. 测试你的插件。


    展开全文
  • MQ消息中间件技术

    万次阅读 多人点赞 2016-09-29 11:42:35
    消息是MQ中最小的概念,本质上就是一段数据,它能被一个或者多个应用程序所理解,是应用程序之间传递的信息载体。

    AMQP协议介绍

    AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。

    AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。

    AMQP在消息提供者和客户端的行为进行了强制规定,使得不同卖商之间真正实现了互操作能力。

    JMS是早期消息中间件进行标准化的一个尝试,它仅仅是在API级进行了规范,离创建互操作能力还差很远。

    与JMS不同,AMQP是一个Wire级的协议,它描述了在网络上传输的数据的格式,以字节为流。因此任何遵守此数据格式的工具,其创建和解释消息,都能与其他兼容工具进行互操作。

    AMQP规范的版本:
    0-8        是2006年6月发布
    0-9        于2006年12月发布
    0-9-1     于2008年11月发布
    0-10      于2009年下半年发布
    1.0 draft  (文档还是草案)

    AMQP的实现有:

    1)OpenAMQ
    AMQP的开源实现,用C语言编写,运行于Linux、AIX、Solaris、Windows、OpenVMS。

    2)Apache Qpid
    Apache的开源项目,支持C++、Ruby、Java、JMS、Python和.NET。

    3)Redhat Enterprise MRG
    实现了AMQP的最新版本0-10,提供了丰富的特征集,比如完全管理、联合、Active-Active集群,有Web控制台,还有许多企业级特征,客户端支持C++、Ruby、Java、JMS、Python和.NET。

    4)RabbitMQ
    一个独立的开源实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。RabbitMQ发布在Ubuntu、FreeBSD平台。

    5)AMQP Infrastructure
    Linux下,包括Broker、管理工具、Agent和客户端。

    6)ØMQ
    一个高性能的消息平台,在分布式消息网络可作为兼容AMQP的Broker节点,绑定了多种语言,包括Python、C、C++、Lisp、Ruby等。

    7)Zyre
    是一个Broker,实现了RestMS协议和AMQP协议,提供了RESTful HTTP访问网络AMQP的能力。

    JMS协议介绍

    JMS(Java Messaging Service)是Java平台上有关面向消息中间件的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。

           JMS本身只定义了一系列的接口规范,是一种与厂商无关的 API,用来访问消息收发系统。它类似于 JDBC(Java Database Connectivity):这里,JDBC 是可以用来访问许多不同关系数据库的 API,而 JMS 则提供同样与厂商无关的访问方法,以访问消息收发服务。许多厂商目前都支持 JMS,包括 IBM 的 MQSeries、BEA的 Weblogic JMS service和 Progress 的 SonicMQ,这只是几个例子。 JMS 使您能够通过消息收发服务(有时称为消息中介程序或路由器)从一个 JMS 客户机向另一个 JML 客户机发送消息。消息是 JMS 中的一种类型对象,由两部分组成:报头和消息主体。报头由路由信息以及有关该消息的元数据组成。消息主体则携带着应用程序的数据或有效负载。根据有效负载 的类型来划分,可以将消息分为几种类型,它们分别携带:简单文本 (TextMessage)、可序列化的对象 (ObjectMessage)、属性集合 (MapMessage)、字节流 (BytesMessage)、原始值流 (StreamMessage),还有无有效负载的消息 (Message)。


    STOMP协议介绍

    STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。

    它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互,类似于OpenWire(一种二进制协议)。

    由于其设计简单,很容易开发客户端,因此在多种语言和多种平台上得到广泛应用。其中最流行的STOMP消息代理是Apache ActiveMQ。

    STOMP协议工作于TCP协议之上,使用了下列命令:

        * SEND 发送
        * SUBSCRIBE 订阅
        * UNSUBSCRIBE 退订
        * BEGIN 开始
        * COMMIT 提交
        * ABORT 取消
        * ACK 确认
        * DISCONNECT 断开

    消息队列技术是分布式应用间交换信息的一种技术。消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读走。通过消息队列,应用程序可独立地执行--它们不需要知道彼此的位置、或在继续执行前不需要等待接收程序接收此消息。

           在分布式计算环境中,为了集成分布式应用,开发者需要对异构网络环境下的分布式应用提供有效的通信手段。为了管理需要共享的信息,对应用提供公共的信息交换机制是重要的。

           设计分布式应用的方法主要有:远程过程调用(PRC)-分布式计算环境(DCE)的基础标准成分之一;对象事务监控(OTM)-基于CORBA的面向对象工业标准与事务处理(TP)监控技术的组合;消息队列(MessageQueue)-构造分布式应用的松耦合方法。

           (a) 分布计算环境/远程过程调用 (DCE/RPC)

           RPC是DCE的成分,是一个由开放软件基金会(OSF)发布的应用集成的软件标准。RPC模仿一个程序用函数引用来引用另一程序的传统程序设计方法,此引用是过程调用的形式,一旦被调用,程序的控制则转向被调用程序。

           在RPC 实现时,被调用过程可在本地或远地的另一系统中驻留并在执行。当被调用程序完成处理输入数据,结果放在过程调用的返回变量中返回到调用程序。RPC完成后程序控制则立即返回到调用程序。因此RPC模仿子程序的调用/返回结构,它仅提供了Client(调用程序)和Server(被调用过程)间的同步数据交换。

           (b) 对象事务监控 (OTM)

           基于CORBA的面向对象工业标准与事务处理(TP)监控技术的组合,在CORBA规范中定义了:使用面向对象技术和方法的体系结构;公共的 Client/Server程序设计接口;多平台间传输和翻译数据的指导方针;开发分布式应用接口的语言(IDL)等,并为构造分布的 Client/Server应用提供了广泛及一致的模式。

           (c) 消息队列 (Message Queue)

           消息队列为构造以同步或异步方式实现的分布式应用提供了松耦合方法。消息队列的API调用被嵌入到新的或现存的应用中,通过消息发送到内存或基于磁盘的队列或从它读出而提供信息交换。消息队列可用在应用中以执行多种功能,比如要求服务、交换信息或异步处理等。

           中间件是一种独立的系统软件或服务程序,分布式应用系统借助这种软件在不同的技术之间共享资源,管理计算资源和网络通讯。它在计算机系统中是一个关键软件,它能实现应用的互连和互操作性,能保证系统的安全、可靠、高效的运行。中间件位于用户应用和操作系统及网络软件之间,它为应用提供了公用的通信手段,并且独立于网络和操作系统。中间件为开发者提供了公用于所有环境的应用程序接口,当应用程序中嵌入其函数调用,它便可利用其运行的特定操作系统和网络环境的功能,为应用执行通信功能。

           如果没有消息中间件完成信息交换,应用开发者为了传输数据,必须要学会如何用网络和操作系统软件的功能,编写相应的应用程序来发送和接收信息,且交换信息没有标准方法,每个应用必须进行特定的编程从而和多平台、不同环境下的一个或多个应用通信。例如,为了实现网络上不同主机系统间的通信,将要求具备在网络上如何交换信息的知识(比如用TCP/IP的socket程序设计);为了实现同一主机内不同进程之间的通讯,将要求具备操作系统的消息队列或命名管道(Pipes)等知识。

           目前中间件的种类很多,如交易管理中间件、面向Java应用的Web应用服务器中间件等,而消息传输中间件(MOM)是其中的一种。它简化了应用之间数据的传输,屏蔽底层异构操作系统和网络平台,提供一致的通讯标准和应用开发,确保分布式计算网络环境下可靠的、跨平台的信息传输和数据交换。它基于消息队列的存储-转发机制,并提供特有的异步传输机制,能够基于消息传输和异步事务处理实现应用整合与数据交换。


    发布-订阅消息模式

    一、 订阅杂志

          我们很多人都订过杂志,其过程很简单。只要告诉邮局我们所要订的杂志名、投递的地址,付了钱就OK。出版社定期会将出版的杂志交给邮局,邮局会根据订阅的列表,将杂志送达消费者手中。这样我们就可以看到每一期精彩的杂志了。


    仔细思考一下订杂志的过程,我们会发现这样几个特点:1、 消费者订杂志不需要直接找出版社;2、 出版社只需要把杂志交给邮局;3、 邮局将杂志送达消费者。邮局在整个过程中扮演了非常重要的中转作用,在出版社和消费者相互不需要知道对方的情况下,邮局完成了杂志的投递。
    二、 发布-订阅消息模式

           刚刚讲了订阅杂志,下面我们会讲传统调用模式演化到发布-订阅消息模式。
           有些网站在注册用户成功后发一封激活邮件,用户收到邮件后点击激活链接后才能使用该网站。一般的做法是在注册用户业务逻辑中调用发送邮件的逻辑。这 样用户业务就依赖于邮件业务。如果以后改为短信激活,注册用户业务逻辑就必须修改为调用发送短信的逻辑。如果要注册后给用户加点积分,再加一段逻辑。经过 多次修改,我们发现很简单的注册用户业务已经越来越复杂,越来越难以维护。相信很多开发者都会有类似痛苦的经历。


    即使用户业务实现中对其他业务是接口依赖,也避免不了业务变化带来的依赖影响。怎么办?解耦!将注册用户业务逻辑中注册成功后的处理剥离出来。
           再回头看看"订阅杂志",如果没有邮局,出版社就必须自己将杂志送达所有消费者。这种情形就和现在的注册用户业务一样。我们发现问题了,在用户业务和其他业务之间缺少了邮局所扮角色。
           我们把邮局抽象成一个管理消息的地方,叫"消息管理器"。注册用户成功后发送一个消息给消息管理器,由消息管理器转发该消息给需要处理的业务。现在,用户业务只依赖于消息管理器了,它再也不会为了注册用户成功后的其他处理而烦恼。


    注册用户的改造就是借鉴了"订阅杂志"这样原始的模式。我们再进一步抽象,用户业务就是消息的"生产者",它将消息发布到消息管理器。邮件业务就是 消息的"消费者",它将收到的消息进行处理。邮局可以订阅很多种杂志,杂志都是通过某种编号来区分;消息管理器也可以管理多种消息,每种消息都会有一个 "主题"来区分,消费者都是通过主题来订阅的。

    发布-订阅消息模式已经呈现在我们面前,利用它可以产生更灵活、更松散耦合的系统。


    1.消息(Message)

    消息是MQ中最小的概念,本质上就是一段数据,它能被一个或者多个应用程序所理解,是应用程序之间传递的信息载体。

    2.队列(Queue)

    2.1本地队列

    本地队列按照功能可划分为初始化队列,传输队列,目标队列和死信队列。

    初始化队列用作消息触发功能。

    传输队列只是暂存待传的消息,条件许可的情况下,通过管道将消息传送到其他的队列管理器。

    目标队列是消息的目的地,可以长期存放消息。

    如果消息不能送达目标队列,也不能再路由出去,则被自动放入死信队列保存。

    2.2别名队列&远程队列

    只是一个队列定义,用来指定远端队列管理器的队列。使用了远程队列,程序就不需要知道目标队列的位置。

    2.3模型队列

    模型队列定义了一套本地队列的属性结合,一旦打开模型队列,队列管理器会按照这些属性动态地创建出一个本地队列。

    3.队列管理器(Queue Manager)

    队列管理器是一个负责向应用程序提供消息服务的机构,如果把队列管理器比作数据库,那么队列就是其中一张表。

    4.通道(Channel)

    通道是两个管理器之间的一种单向点对点的的通信连接,如果需要双向交流,可以建立一对通道。

    5.监听器(listner)

    可靠性传输

    这个特点可以说是消息中间件的立足之本,对于应用来说,只要成功把数据提交给消息中间件,那么关于数据可靠传输的问题就由消息中间件来负责。

    不重复传输

    不重复传播也就是断点续传的功能,特别适合网络不稳定的环境,节约网络资源。

    异步性传输

    异步性传输是指,接受信息双方不必同时在线,具有脱机能力和安全性。

    消息驱动

    接到消息后主动通知消息接收方。

    支持事务

    应用程序可以把一些数据更新组合成一个工作单元,这些更新通常是逻辑相关的,为了保障数据完整性,所有的更新必须同时成功或者同时失败)。 


    常用MQ产品比较


    ActiveMQ Joram HornetQ OpenMQ MuleMQ SonicMQ RabbitMQ ZeroMQ
    关注度
    成熟度 成熟 比较成熟 比较成熟 比较成熟 新产品无成功案例 成熟 成熟 不成熟
    所属社区/公司 Apache OW2 Jboss Sun Mule Progress

    社区活跃度
    文档
    特点 功能齐全,被大量开源项目使用
    在Linux平台上直接调用操作系统的AIO,性能得到很大的提升
    性能非常好,与MuleESB无缝整合 性能优越的商业MQ 由于Erlang语言的并发能力,性能很好 低延时,高性能,最高43万条消息每秒
    授权方式 开源 开源 开源 开源 商业 商业 开源 开源
    开发语言 Java Java Java Java Java Java Erlang C
    支持的协议 OpenWire、STOMP、REST、XMPP、AMQP JMS JMS JMS JMS JMS AMQP TCP、UDP
    客户端支持语言 Java、C、C++、Python、PHP、Perl、.net等 Java Java Java Java Java、C、C++、.net Java、C、C++、Python、PHP、Perl等 python、java、php、.net等
    持久化 内存、文件、数据库 内存、文件 内存、文件 内存、文件 内存、文件 内存、文件、数据库 内存、文件 在消息发送端保存
    事务 支持 支持 支持 支持 支持 支持 不支持 不支持
    集群 支持 支持 支持 支持 支持 支持 支持 不支持
    负载均衡 支持 支持 支持 支持 支持 支持 支持 不支持
    管理界面 一般
    一般 一般 一般
    部署方式 独立、嵌入 独立、嵌入 独立、嵌入 独立、嵌入 独立 独立 独立 独立
    评价 成熟稳定,开源首选 依赖容器,不适合跨语言调用 推出的时间不长,尚无使用案例,不适合跨语言调用 依赖容器,不适合跨语言调用 推出的时间不长,无成功案例,目前仅支持Java 成熟稳定 Queue的数量大于50后,高并发下无法持续稳定的提供服务 不支持事务、集群,并且消息不能在服务端持久化 


    MQ适用场景介绍

    MQ消息队列是应运松偶合的概念而产生的,主要以队列和发布订阅为消息传输机制,以异步的方式将消息可靠的传输到消费端的一种基础产品。

    它被广泛的应用与跨平台、跨系统的分布式系统之间,为它们提供高效可靠的异步传输机制。

    • 消息通道(Message Channel)

           使用MQ将彼此协作的客户端和服务端连接起来,使他们可以交换消息。


    如客户端与服务端需要安全可靠的交互,可以将一个MQ的队列作为安全通道,是客户端与服务端能够安全高效的进行异步通讯。

    • 消息总线(Message Bus)

          对于由许多独立开发的服务组成的分布式系统,倘若要将它们组成一个完整的系统,这些服务必须能够可靠地交互,同时,为了系统的健壮性,

    每个服务之间又不能产生过分紧密的依赖关系,这样就可以通过消息总线将不同的服务连接起来,允许它们异步的传递数据。



    • 消息路由(Message Router)

           通过消息路由,可以将发送到MQ指定队列的消息根据规则路由到不同的队列。


    此外,JMS规范还支持通过selector条件,对消息进行过滤,可以用多个消费者消费同一个队列的消息,每个消费者只消费自己感兴趣的消息。

    • 发布/订阅(Publicsher/Subscriber)

          发布/订阅模式用于一对多的通讯,当消息发布者向一个主题(Topic)发送一条消息后,该主题的所有订阅者都会收到这条消息。

    展开全文
  • 网站的可扩展性架构设计,能够在对现有系统影响最小的情况下,系统功能可以可持续扩展及提升的能力。在此,对容易混为一谈的 “扩展性” 和 “伸缩性” 的概念进行详细说明:扩展性表现为:基础设施不需要经常变更,...

    网站的可扩展性架构设计,能够在对现有系统影响最小的情况下,系统功能可以可持续扩展及提升的能力。

    在此,对容易混为一谈的 “扩展性” 和 “伸缩性” 的概念进行详细说明:

    扩展性

    表现为:基础设施不需要经常变更,应用之间较少依赖或耦合,可以对需求变更快速响应。它对扩展开放,对修改关闭。架构设计会考虑到未来功能的可扩展性,所以当系统增加新功能时,不需要对现有系统的结构和代码进行修改。

    伸缩性

    是指系统通过增加(或减少)自身资源规模的方式增强(或减少)处理业务的能力。如果这种增减是成比例的,就可以称之为线性伸缩性。通常是利用集群的方式增加服务器的数量,以提高系统整体业务吞吐能力。

    1 构建可扩展的网站架构

    度量一个开发框架、设计模式或编程语言优劣的一个重要尺度就是它是否能够让软件开发过程和软件产品更加低耦合。

    因为低耦合的系统更容易扩展,也更容易被复用,而且也会让开发过程和维护变得更加容易。但如何分解系统的各个模块、如何定义各个模块的接口、如何复用、组合不同模块构造一个完整的系统,这是软件设计中最具挑战性的部分。

    软件架构师的最大价值,就在于把一个大系统分解为 N 个低耦合的子模块的能力,这些子模块包含横向的业务模块与纵向的基础技术模块。这种能力来源于专业技术能力与经验、业务场景的理解、对人性的把握以及对世界的认知。

    构建可扩展的网站架构的核心思想是模块化,并在此基础上,降低模块之间的耦合性,提高模块的复用性。

    可以利用分层与分割的方式,把软件分割为若干个低耦合、独立的组件模块,然后在这些组件模块之间以消息传递或依赖调用的方式聚合成一个完整的系统。

    这些模块可以通过分布式部署的方式,部署在独立的服务器上。这种从物理上分离模块之间的耦合关系,可以进一步降低耦合性。

    模块的分布式部署后的聚合方式有:

    • 分布式消息队列。
    • 分布式服务。

    1 使用分布式消息队列降低耦合性

    如果模块之间不存在直接调用关系,那么新增或修改模块对其他部分的影响最小,这样的扩展性自然更好。

    1.1 事件驱动架构

    事件驱动架构指的是:在低耦合的模块之间传输事件消息,保持模块之间的松散耦合,通过事件消息来完成模块之间的通信。 事件驱动架构最常见的实现方式就是使用分布式消息队列。

    基于消息队列的事件驱动架构

    消息队列基于发布——订阅模式工作,消息发送者发布消息,一个或多个消息接收者订阅消息。消息发送者把消息发送至分布式消息队列后就处理完毕,然后由消息订阅者从消息队列中获取消息进行处理。对于新增的业务,只要对某个消息感兴趣,就可以订阅该消息,而这对原有的系统和业务没有任何影响,从而实现系统的可扩展性设计。

    消息接收者还可以对收到的消息再构造,定义出一个新的消息类型,然后再把消息发送给订阅了这一新消息类型的接收者。所以基于消息对象的事件驱动架构可以是一系列的流程。

    因为消息发送者无须等待就可以返回,所以系统具有更好的响应时间;而且在访问高峰,消息可以暂存于消息队列中,从而减轻了数据库的存储负载压力。

    1.2 分布式消息队列

    队列是一种先进先出的数据结构,我们可以把消息队列部署到独立的服务器中。应用通过远程访问接口使用消息队列,进行消息的存取操作,从而实现分布式的异步调用:

    分布式消息队列原理

    目前较为流行的分布式消息队列是 Apache ActiveMQ。

    因为消息队列服务器上的数据可以看做是即时处理的,所以在伸缩性上,我们把新服务器加入分布式消息队列集群后,只需要通知生产者服务器更改消息队列的服务器列表就好啦O(∩_∩)O~

    可用性上,如果内存队列满了,要将消息写入磁盘,这样当消息推送模块把内存队列中的消息处理完毕后,就会把磁盘中的消息加载到队列中继续处理。

    为了避免消息队列服务器宕机造成消息丢失,会把消息存储在消息的生产者服务器上,这样等消息确实被消息消费者服务器处理后才会删除。如果消息队列服务器宕机,生产者服务器会选择分布式消息队列服务器集群内的其他服务器发布消息。

    分布式消息队列可以很复杂,比如支持 ESB(企业服务总线)和 SOA(面向服务的架构)等。也可以很简单,比如使用 MySQL 作为分布式消息队列:消息的生产者把消息作为记录写入数据库,消费者查询数据库(按记录写入库表的时间戳排序),这就是一个分布式消息队列啦。再配上成熟的 MySQL 运维手段,也可以达到一个较高的可用性和性能指标哦O(∩_∩)O~

    2 使用分布式服务构建可复用的业务平台

    分布式服务可以通过接口降低系统的耦合性,不同的子系统之间通过相同的接口描述调用服务。

    随着网站功能的日益复杂,系统会逐渐发展成为一个巨无霸,里面聚合了大量的应用和服务组件,这样的一个系统会给开发、维护、部署带来巨大的麻烦:

    • 编译、部署困难。
    • 代码分支管理困难:复用的代码模块由多个团队共同维护修改,所以在代码合并时总会发生冲突。
    • 耗尽数据库连接:假设一个应用设定了 10 个数据库连接,那么一个拥有数百台服务器集群的应用就会在数据库上创建数千个连接。
    • 新增业务困难。在这样一个剪不断、理还乱的系统中新增业务?开玩笑吧O(∩_∩)O~

    所以我们要做拆分,把模块独立部署,降低系统的耦合性:

    • 纵向拆分 - 把一个大应用拆分为多个小应用。如果新增的业务较为独立,就直接将其设计并部署为一个独立的 Web 应用。
    • 横向拆分 - 把复用的业务拆分出来,独立部署为分布式服务,新增的业务只需要调用这些分布式的服务,就可以快速搭建出一个应用系统。即使模块内的业务逻辑发生变化,只要保持接口一致,就不会影响其他模块。

    分布式服务架构

    纵向拆分较简单,通过梳理业务,把关联较少的业务剥离,使其成为独立的 Web 应用。而横向拆分不仅需要识别出可复用的业务、设计服务接口以及规范服务之间的依赖关系,而且还需要一个完善的分布式服务管理框架。

    2.1 Web Service 分布式服务

    Web Service 曾经是企业应用系统在开发领域中最时髦的词汇之一,它用于整合异构系统以及构建分布式系统:

    Web Service 原理

    服务提供者通过 WSDL(Web Services Description Language,Web 服务描述语言)向注册中心(Service Broker)描述自身所能提供的服务接口内容,然后注册中心使用 UDDI(Universal Description, Discovery, and Integration,统一描述、发现和集成)发布服务提供者提供的服务。服务请求者从注册中心检索到服务后,通过 SOAP(Simple Object Access Protocol ,简单对象访问协议)与服务提供者通信,使用该服务。

    Web Service 虽然有成熟的技术规范和实现,但有如下缺点:

    1. 臃肿的注册、发现机制。
    2. 低效的 XML 序列化手段。
    3. 开销较高的 HTTP 远程通信。
    4. 复杂的部署与维护手段。

    这些问题导致 Web Service 难以满足大型网站对高性能、高可用、易部署与易维护的要求。

    2.2 大型网站分布式服务的要求

    分布式服务框架需要能够支持以下特性:

    • 负载均衡 - 对于服务请求者能够使用可配置的负载均衡算法来访问热门服务(比如登录或商品服务,这些服务被部署在一个集群上)。
      *失效转移 - 可复用的服务被多个应用调用,一旦服务不可用,就会影响到很多应用的可用性。所以即使是很少访问的服务,也需要集群部署。分布式服务框架检测到某个服务不可用时,就会切换到其他服务实例上,保证整体高可用。
    • 高效的远程通信
    • 整合异构系统
    • 对应用最小侵入 - 分布式服务框架支持服务(服务模块需要即支持集中式部署,也支持分布式部署)的渐进式演化和反复。
    • 版本管理 - 网站服务不可中断,所以分布式服务框架需要支持服务的多版本发布,服务提供者升级发布接口新版本的同时,还会继续支持旧版本的服务,直到请求者调用的接口升级后,才会关闭旧版本的服务。
    • 实时监控 - 监控服务提供者和调用者的各项指标,提供运维与运营的支持。

    2.3 分布式服务框架设计

    大型网站需要更简单、更高效的分布式服务框架构建其 SOA(Service Oriented Architecture ,面向服务的体系结构)。目前国内有较多成功实施案例的开源分布式服务框架是阿里巴巴的 Dubbo。

    Dubbo 架构

    服务消费者通过接口使用服务,接口通过代理加载具体服务,可以是本地的代码,也可以是远程的服务,因此对应用侵入较小。

    客户端模块通过服务注册中心加载服务提供者列表(服务提供者启动后自动向服务注册中心注册自己可以提供的服务接口列表),然后根据配置的负载均衡策略把服务调用请求发送到某台服务提供者的服务器。如果服务调用失败,客户端模块会自动从服务提供者列表中选择一个可以提供同样服务的服务器重新请求,即自动失效转移,保证服务的高可用。

    Dubbo 使用 NIO 通信框架,因此具有较高的网络通信性能。

    4 可扩展的数据结构

    使用 NoSQL 数据库(如 Cassandra)的 ColumnFamily (列族)技术可以做到可扩展的数据结构设计。它是一种面向列族的稀疏矩阵的存储格式。

    只需要指定 ColumnFamily 的名字,即可创建表。字段可以在写入数据时再指定,通过这种方式,一张表可以包含数百万个字段。这就使得应用的数据结构可以随意扩展。只需要指定任意字段名称和值即可查询。

    5 利用开放平台建立生态圈

    用户只有得到他们想要价值,才会愿意使用网站的服务,这样的网站才有存在的意义。但一个网站毕竟不能满足所有用户的需求。

    用户不会为网站提供的价值买单,所以网站必须提供更多的增值服务才能赚钱。根据长尾效应,增值服务的数量越大,种类越多,盈利也就越多。但一个网站能够自己开发的增值服务也是有限的。

    大型网站为了更好地服务用户、为他们开发出更多的增值服务,会把网站内部的服务封装成接口开放出去,供外部第三方开发者使用,这个平台就叫做开放平台。第三方开发者利用这些开放的接口就可以开发应用程序(如 APP)或网站,为用户提供更多的价值。网站、用户、第三方开发者
    相互依赖,形成一个生态圈。

    开放平台是网站内部和外部交互的接口。外部会面对众多的第三方开发者,内部面对的是网站内众多的业务服务。下面是开放平台的架构:

    开放平台的架构

    • API 接口:暴露给开发者的一组 API,可以是 RESTful、WebService、RPC 等形式。
    • 协议转换:把各种 API 的输入转换为内部服务可识别的形式,并把内部服务的返回信息封装为 API 格式。
    • 安全:除了身份识别、权限控制等手段之外,还要对访问带宽进行分级限制,保证平台资源被第三方应用合理公平地使用,也能保证网站自身的内部服务不会被外部应用拖垮。
    • 审计:监控第三方应用的访问情况并计费。
    • 路由:把开放平台的各种访问路由映射到具体的内部服务。
    • 流程:把一组松散的服务组织成一个上下文相关的新服务,对外提供接口供开发者使用。
    展开全文
  • 面试问题:如何实现软件可扩展性

    万次阅读 2018-07-12 11:33:04
    网站的可扩展性架构设计,能够在对现有系统影响最小的情况下,系统功能可以可持续扩展及提升的能力。在此,对容易混为一谈的 “扩展性” 和 “伸缩性” 的概念进行详细说明:扩展性表现为:基础设施不需要经常变更,...
  • MQ消息

    万次阅读 2015-03-30 23:40:49
    AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。 AMQP的主要特征是面向消息队列、路由(包括点对点和发布/订阅)、可靠性、安全。 AMQP在...
  • 浅谈消息队列及常见的消息中间件

    千次阅读 2018-07-20 11:05:53
    当前使用较多的 消息队列 有 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ 等,而部分 数据库 如 Redis、MySQL 以及 phxsql 也可实现消息队列的功能。     正文 1. 消息队列概述...
  • MQ消息队列

    千次阅读 2015-03-30 23:39:55
    AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。AMQP的主要特征是面向消息队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP在消息...
  • 全面认识openstack:OpenStack架构详解

    万次阅读 多人点赞 2020-05-17 07:10:44
    OpenStack既是一个社区,也是一个项目和一个开源软件,提供开放源码软件,建立公共和私有云,它提供了一个部署云的操作平台或工具集,其宗旨在于:帮助组织运行为虚拟计算或存储服务的云,为公有云、私有云,也为大...
  • 消息队列常见问题和解决方案

    万次阅读 多人点赞 2018-10-28 21:42:25
    一、为什么使用消息队列消息队列使用的场景和中间件有很多,但解决的核心问题主要是:异步、解耦、消峰填谷。 二、消息队列的优缺点 异步、解耦、消峰填谷这是消息队列最大的优点,除了这些消息队列还可以会...
  • Openstack基础架构

    万次阅读 多人点赞 2020-09-15 20:21:00
    Openstack学习总结 Openstack简介 OpenStack是一个由美国国家航空航天局(NASA)和Rackspace合作研发并发起的开源项目。其中Rackspace贡献了Swift, NASA贡献了Nova项目,这两个子项目发展到现在的大大小小十多个...
  • 与网络数据包的发送不同,网络收包是异步的的,因为你不确定谁会在什么时候突然发一个网络包给你,因此这个网络收包...协议栈栈/应用边界:协议栈将数据包填充socket队列,通知应用程序有数据可读,应用程序负责接收
  • OpenStack架构

    万次阅读 2018-03-15 17:35:16
    一、概述openstack是一个综合的云计算管理平台,作为一个开源的IaaS平台,在openstack项目中包含了各种各样的组件,接下来简要介绍。 二、组件(项目)介绍1、认证服务-Keyston该组件在openstack中主要负责用户、...
  • 上篇文章我们提到了如何在Linux下安装... ActiveMQ 是 Apache 出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个 完全支持 JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现,尽管 JMS 规范出台已经是很久的事 情了
  • AMQP协议介绍

    千次阅读 2016-08-29 20:15:04
    AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。 AMQP的主要特征是面向消息队列、路由(包括点对点和发布/订阅)、可靠性、安全。 ...
  • 整体认识openstack-----五大组件各自的作用 ... (出处: about云开发) 可以带着下面问题来阅读: 1.OpenStack云实例生命期所需的各种动作都将由那个组件来进行处理和支撑? ...2.Nova是否具有虚拟能力?...
  • 高并发、高性能 Web 架构

    万次阅读 2017-02-28 14:59:53
    典型 Web App 架构 以下是一个典型的高负载 web 应用示例: 上图展示了一个典型的,三层架构的高性能 Web 应用。这种成熟的架构多年以来已被广泛部署于包括 Google、Yahoo、Facebook、Twitter、...
  • OpenStack主要组件及其作用

    万次阅读 2019-06-14 17:02:06
    文章大部分来自于OpenStack官方文档。部分来自于网络 参考资料 ... ... OpenStack是一个开源的云计算管理平台项目,由几个主要的组件组合起来完成具体工作。OpenStack支持几乎所有类型的云环境,项目目标是提供实施简单....
1 2 3 4 5 ... 20
收藏数 10,375
精华内容 4,150
关键字:

webapi 持续接收 消息队列