队列的基本操作

1,队列的概念

只允许在一端插入数据操作,在另一端进行删除数据操作的特殊线性表;进行插入操作的一端称为队尾(入队列),进行删除操作的一端称为队头(出队列);队列具有先进先出(FIFO)的特性。

2,顺序队列

(1)队头不动,出队列时队头后的所有元素向前移动

 

 缺陷:操作是如果出队列比较多,要搬移大量元素

(2)队头移动,出队列时队头向后移动一个位置

 

 如果还有新元素进行入队列容易造成假溢出。

假溢出:顺序队列因多次入队列和出队列操作后出现的尚有存储空间但是不能进行入队操作的溢出。

真溢出:顺序队列的最大存储空间已经存满而又要求进行入队列操作所引起的溢出。

3.循环队列

 

 循环队列如何进行判 空和满 操作:

   少用一个存储单元

   设置一个标记flag

         初始值 flag=0;入队列:flag=1;出队列:flag=0

         队列为空时:(front == rear && flag==0)

         队列为满时:(front == rear && flag == 1)

  设置一个计数器

4,链式队列

链式队列:特殊单链表,只在单链表上进行头删尾插的操作

【1.定义一个队列结构体】

由于是链式队列,所有先定义一个存放数据域和指针域的结构体

队列结构体中定义一个队头指针和队尾指针

[3.初始化队列]

  让队列的队头,队尾分别指向空

[4.入队列]

 

 判断队中是否有元素

找到队尾元素

让新入队的元素链在原先队列的队尾上,更新新的队尾

 

 这里的出队列采用是让队头元素不断后移,刷新队头元素,这样优化时间效率

一,消息队列概述

消息队列,是分布式系统中重要的组件,其通用的使用场景可以简单地描述为:

当不需要立即获取结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。

消息队列主要解决了应用耦合、异步处理、流量削锋等问题。

当前使用较多的消息队列又RabbitMQ、RocketMQ\ActiveMQ\Kafka\ZeroMQ、MetaMq等,而部分数据库如Redis、Mysql以及phxsql也实现消息队列的功能。

二、消息队列使用场景

消息队列在实际应用中包括如下四个场景:

       应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;

       异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;

       限流削峰:广泛应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况

       消息驱动的系统:系统分为消息队列、消息生产者、消息消费者、生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;

2.1 异步处理

具体场景:用户为了使用某个应用,进行注册,系统需要发送注册邮件并验证短信。对这两个操作的处理方式有两种:串行及并行

(1)串行方式:新注册信息生成后,先发送注册邮件,再发送验证短信;

 

 (2)并发处理:新注册信息写入后,由发短信和发邮件并行处理;

 

 在这种方式下,发短信和发邮件,需处理完成后在返回给客户端。

假设以上三个子系统处理的时间均为50ms,且不考虑网络延迟,则总的处理时间

串行:50+50+50 = 150ms

并行:50+50 = 100ms

如使用消息队列:

 

 并在写入消息队列后立即返回成功给客户端,则总的响应时间依赖于写入消息队列的时间,而写入消息队列的时间本身是可以很快的,基本可以忽略不计,因此总的处理时间相比串行提高了2倍,相比并行提高了一倍;

2.2 应用耦合

具体场景:用户使用QQ相册上传一张图片,人脸识别系统会对该图片进行人脸识别,一般的做法是,服务器接收到图片后,图片上传系统立即调用人脸识别,调用完成后再返回成功,如下图所示:

 

 该方法有如下缺点:

   人脸识别系统被调失败,导致图片上传失败;

   延迟高,需要人脸识别系统处理完成后,在返回给客户端,即使用户并不需要立即知道结果;

  图片上传系统与人脸识别系统之间互相调用,需要做耦合;

若使用消息队列:

 

 客户端上传图片后,图片上传系统将图片信息如uin,批次写入消息队列,直接返回成功;而人脸识别系统则定时从消息队列中取数据,完成对新增图片的识别。

此时图片上传系统并不需要关心人脸识别系统是否对这些图片信息的处理、以及何时对这些图片信息进行处理。事实上,由于用户并不需要立即知道人脸识别结果,人脸识别系统可以选择不同的调度策略,按照闲时、忙时、正常时间,对队列中的图片信息进行处理。

2.3 限流削峰

具体场景:购物网站开展秒杀活动,一般由于瞬时访问量过大,服务器接受过大,会导致流量暴增,相关系统无法处理请求甚至崩溃。而加入消息队列后,系列可以从消息队列中取数据,相当于消息队列做了以次缓冲。

       

 

 该方法有如下优点:

  1,请求先入消息队列,而不是由业务处理系统直接处理,做了一次缓存,极大地减少业务处理系统压力:

  2,队列长度可以做限制,事实上,秒杀时,后入队列的用户无法秒杀到商品,这些请求可以直接被抛弃,返回活动已结束或商品已售完信息;

2.4 消息驱动的系统

 具体场景:用户新上传了一批照片,人脸识别系统需要对这个用户的所有照片进行聚类,聚类完成后由对账系统重新生成用户的人脸索引(加快查询)。这三个子系统间消息队列连接起来,前一个阶段的处理结果放入队列中,后一个阶段从队列中获取消息继续处理。

 

 该方式有如下优点:

  避免了直接调用下一个系统导致当前系统失败:

每个系统对于消息的处理方式可以更为灵活,可以选择收到消息时就处理,可以选择定时处理,也可以划分时间段按不同处理速度处理;

三,消息队列的两种模式

消息队列包括两种模式,点对点模式(point to point ,queue)和发布/订阅模式(publish/subscribe , topic)

3.1 点对点模式

点对点模式下包括三个角色

     消息队列

     发送者(生产者)

     接收者(消费者)

 

 消息发送者生产消息发送到queue中,然后消息接收者从queue取出并且消费消息。消息被消费以后,queue中不再有存储,所以消息接收者不可能消费到已经被消费的消息。

点对点模式特点:

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

发送者和接收者间没有依赖性,发送者发送消息之后,不管有没有接收者在运行,都不会影响到发送者下次发送消息

接收者在成功接收消息之后需向队列应答成功,以便消息队列删除当前接收的消息

3.2 发布/订阅模式

发布/订阅模式下包括三个角色:

角色主题

发布者

订阅者

 

 发布/订阅模式特点:

每个消息可以有多个订阅者;

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

为了消费消息,订阅者需要提前订阅该角色主题,并保持在线运行;

四,常用消息队列介绍

本部分主要介绍四种常用的消息队列(RabbitMQ/ActiveMQ/RocketMQ/Kafka)的主要特性、优点、缺点。

4.1 RabbitMQ

RabbitMQ 2007年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。

主要特性:

1.可靠性:提供多种技术可以让你在性能和可靠性之间进行权衡。这些技术包括持久性机制、投递确认、发布者证实和高可用性机制;

2,灵活的路由:消息在到达队列前是通过交换机进行路由的。RabbitMQ典型的路由逻辑提供了多种内置交换机类型。如果你有更复杂的路由需求,可以将这些交换机组合起来使用,你甚至可以实现自己的交换机类型,并且当作RabbitMQ的插件来使用;

3消息集群:在相同局域网中的多个RabbitMQ服务器可以聚合在一起,作为一个独立的逻辑代理来使用;

4,队列高可用:队列可以在集群中的机器上进行镜像,以确保在硬件问题下还保证消息安全;

5,多种协议的支持:支持多种消息队列协议;

6,服务器端用Erlang语言编写,支持只要是你能想到的所有编程语言;

7,管理界面:RabbitMQ有一个易用的用户界面,使得用户可以监控和管理消息Broker的许多方面;

8,跟踪机制:如果消息异常,RabbitMQ提供消息跟踪机制,使用者可以找出发生了什么;

9,插件机制:提供了许多插件,来从多方面进行扩展,也可以编写自己的插件

使用RabbitMQ需要:

Erlang语言包

RabbitMQ安装包

RabbiMQ可以运行在Erlang语言所支持的平台之上:

Solatis     BSD   Linux    MacOSX  TRU64  Windows NT/2000/XP/Vista/Windows 7/Windows 8

Windows Server 2003/2008/2012

Windows 95,98

VxWorks

优点:

1.由于erland 语言的特性,mq性能较好,高并发

2,健壮、稳定、易用、跨平台、支持多种语言、文档齐全

3,有消息确认机制和持久化机制,可靠性高

4,高度可定制的路由

5,管理界面较丰富,在互联网公司也有较大规模的应用

6,社区活跃度高

缺点:

1,尽量结合erlang语言本身的并发优势,性能较好,但是不利于做二次开发和维护

2,实现了代理架构,意味着消息在发送到客户端之前可以在中央节点上排队。此特性使得RabbitMQ易于使用和部署,但是使得其运行速度较慢,因为中央节点增加了延迟,消息封装后也比较大;

3,需要学习比较复杂的接口和协议,学习和维护成本较高

4.2 Kafka

Apacha Kafka是一个分布式消息发布订阅系统。它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统(a distributed commit log),之后称为Apache项目的一部分。Kafka系统快速、可扩展并且可持久化。他的分区特性,可复制和可容错都是其不错的特性,

主要特性:

1,快速持久化,可以在O(1)的系统开销下进行消息持久化

2,高吞吐,在一台普通的服务器上既可以达到10w/s的吞吐率

3,完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡

4,支持同步和异步复制两种HA

5,支持数据批量发送和拉取

6,zero-copy:减少IO操作步棸;

7,数据迁移,扩容对用户透明

8,无需停机即可扩展机器

9,其他特性:严格的消息顺序、丰富的消息拉取模型、高校订阅者水平扩展、实时的消息订阅、亿级的消息堆积能力、定期删除机制

使用Kafka需要

java JDK

kafka 安装包

优点:

1,客户端语言丰富,支持java、.net、php、ruby、python、go等多种语言

2,性能卓越,单机写入TPS约在百万条/秒,消息大小10个字节

3,提供完全分布式架构,并有replica机制,拥有较高的可用性和可靠性,理论上支持消息无限堆积

4,支持批量操作

5,消费者采用pull方式获取消息,消息有序,通过控制能够保证所有消息被消息且仅被消息一次

6,有优秀的第三档Kafka Web管理界面Kafka-Manager

7,在日志领域比较成熟,被多家公司和多个开源项目使用;

缺点

1,kafka单机超过64个队列/分区,load会发生明显得飙高现象,队列越多,load越高,发送消息时间边长

2,使用短轮询方式,实时性取决于轮询间隔时间

3,消费失败不支持重试

4,支持消息顺序,但是一台代理宕机后,就会产生消息乱序

5,社区更新较慢

五、参考资料:

5.1 消息队列:

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

  2. 消息队列的使用场景 https://www.zhihu.com/question/34243607/answer/127666030

  3. 浅谈异步消息队列模型 http://www.cnblogs.com/sunkeydev/p/5248855.html

  4. 消息队列的两种模式 http://blog.csdn.net/heyutao007/article/details/50131089

5.2 RabbitMQ

  1. RabbitMQ主页 https://www.rabbitmq.com/

  2. RabbitMQ学习教程 https://www.rabbitmq.com/getstarted.html

  3. 专栏:RabbitMQ从入门到精通 http://blog.csdn.net/column/details/rabbitmq.html

  4. RabbitMQ能为你做些什么 http://rabbitmq.mr-ping.com/description.html

  5. RabbitMQ指南(1)-特性及功能 https://blog.zenfery.cc/archives/79.html

5.3 ActiveMQ

  1. ActiveMQ主页 http://activemq.apache.org/

  2. Apache ActiveMQ介绍 http://jfires.iteye.com/blog/1187688

  3. ActiveMQ的简介与安装 http://blog.csdn.net/sl1992/article/details/72824562

  4. ActiveMQ 和消息简介 http://www.cnblogs.com/craftsman-gao/p/7002605.html

5.4 RocketMQ

  1. 主页 https://github.com/alibaba/RocketMQ

  2. RocketMQ 原理简介 http://alibaba.github.io/RocketMQ-docs/document/design/RocketMQ_design.pdf

  3. RocketMQ与kafka对比(18项差异) http://jm.taobao.org/2016/03/24/rmq-vs-kafka/

5.5 Kafka

1.Kafka主页: http://kafka.apache.org/

  1. Kafka特性 http://www.cnblogs.com/lsx1993/p/4847719.html

  2. Kafka客户端支持语言 https://cwiki.apache.org/confluence/display/KAFKA/Clients

5.6 RabbitMQ/ActiveMQ/RocketMQ/Kafka对比

  1. RocketMQ,队列选型 http://www.zmannotes.com/index.php/2016/01/17/rocketmq/

  2. RabbitMQ和Kafka http://www.dongcoder.com/detail-416804.html

  3. 即时通信RabbitMQ二-性能测试 http://www.jianshu.com/p/d31ae9e3bfb6

  4. RabbitMq、ActiveMq、ZeroMq、kafka之间的比较,资料汇总 http://blog.csdn.net/linsongbin1/article/details/47781187

  5. 消息队列软件产品大比拼 http://www.cnblogs.com/amityat/archive/2011/08/31/2160293.html

总结:

消息队列利用有效可靠得消息传递机制进行平台无关得数据交流,并基于数据通信来进行分布式系统得集成。也有直接使用数据库redis充当消息队列得案例。而这些消息队列产品,各有侧重,在实际选型时,需要结合自身需求及MQ产品特性,综合考虑。

转载于:https://www.cnblogs.com/shangfz/p/11434514.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
循环队列基本操作包括初始化、入队、出队、求队列长度、求队头元素、判空、清空和销毁等。以下是循环队列基本操作的实现方法: 1. 初始化:创建一个空的循环队列,需要指定队列的最大长度。 2. 入队:将元素插入到队列的队尾,如果队列已满则无法插入。 3. 出队:将队列的队头元素删除并返回,如果队列为空则无法删除。 4. 求队列长度:返回队列中元素的个数。 5. 求队头元素:返回队列的队头元素,但不删除。 6. 判空:判断队列是否为空。 7. 清空:清空队列中的所有元素。 8. 销毁:销毁队列,释放内存空间。 以下是一个基于顺序表实现的循环队列的代码示例: ``` #define MAXSIZE 100 // 队列的最大长度 typedef struct { int data[MAXSIZE]; // 存储队列元素的数组 int front; // 队头指针 int rear; // 队尾指针 } CircularQueue; // 初始化循环队列 void InitQueue(CircularQueue *q) { q->front = q->rear = 0; } // 判断队列是否为空 int IsEmpty(CircularQueue *q) { return q->front == q->rear; } // 判断队列是否已满 int IsFull(CircularQueue *q) { return (q->rear + 1) % MAXSIZE == q->front; } // 入队 int EnQueue(CircularQueue *q, int x) { if (IsFull(q)) { return 0; // 队列已满,无法插入 } q->data[q->rear] = x; q->rear = (q->rear + 1) % MAXSIZE; return 1; } // 出队 int DeQueue(CircularQueue *q, int *x) { if (IsEmpty(q)) { return 0; // 队列为空,无法删除 } *x = q->data[q->front]; q->front = (q->front + 1) % MAXSIZE; return 1; } // 求队列长度 int QueueLength(CircularQueue *q) { return (q->rear - q->front + MAXSIZE) % MAXSIZE; } // 求队头元素 int GetHead(CircularQueue *q, int *x) { if (IsEmpty(q)) { return 0; // 队列为空,无法获取队头元素 } *x = q->data[q->front]; return 1; } // 清空队列 void ClearQueue(CircularQueue *q) { q->front = q->rear = 0; } // 销毁队列 void DestroyQueue(CircularQueue *q) { free(q); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值