为了账号安全,请及时绑定邮箱和手机立即绑定

MQ底层原理资料详解:新手入门教程

标签:
中间件
概述

本文详细介绍了消息队列(MQ)的基本概念、工作原理及其在实际应用中的作用,包括消息的发送和接收过程、存储机制以及常见的消息模式,并深入探讨了MQ的可靠传输、持久化和负载均衡机制。MQ底层原理在此得到了全面解析,帮助读者深入了解MQ的实现细节。

1. 什么是MQ?

MQ的基本概念

消息队列(Message Queue,简称MQ)是一种用于处理应用间异步通信的软件,通过在发送方和接收方之间引入中间层,实现数据传输。MQ的作用是将生产者产生的消息发送到消息队列中,然后由消费者从消息队列中消费这些消息。这种架构模式使得系统可以更好地处理异步通信,并提高系统的可扩展性和可靠性。

MQ的作用和应用场景

MQ在实际应用中扮演着重要角色,以下是其主要作用和应用场景:

  • 异步解耦:通过MQ,可以将应用中的各个组件解耦,使得这些组件之间的交互是异步的,从而提高系统的整体性能。
  • 削峰填谷:在请求高峰时,MQ可以缓存请求,避免后端服务被瞬间压垮,从而实现削峰填谷。
  • 数据传输:MQ可以用于在不同应用之间传输数据,例如日志采集、数据同步等场景。
  • 消息路由:MQ可以根据消息的特性,将消息路由到不同的队列中,实现复杂的业务逻辑。
  • 消息重试:当消息无法被消费时,MQ可以尝试多次重新发送,保证消息最终被成功消费。
2. MQ的工作原理

消息的发送过程

消息的发送过程主要包括以下步骤:

  1. 连接MQ服务器:生产者首先需要连接到MQ服务器。
  2. 创建通道(Channel):生产者通过该通道发送消息。
  3. 创建队列:生产者可以选择创建一个队列,或者使用已存在的队列。
  4. 发送消息:生产者通过通道将消息发送到指定的队列中。

以下是一个简单的生产者发送消息的示例代码,使用的是RabbitMQ,一种开源的消息队列服务:

import pika

# 创建连接
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 创建队列
channel.queue_declare(queue='hello')

# 发送消息
channel.basic_publish(exchange='',
                      routing_key='hello',
                      body='Hello World!')
print(" [x] Sent 'Hello World!'")
connection.close()

消息的接收过程

消息的接收过程主要包括以下步骤:

  1. 连接MQ服务器:消费者首先需要连接到MQ服务器。
  2. 创建通道(Channel):消费者通过该通道接收消息。
  3. 声明队列:消费者需要声明队列,确保队列的存在。
  4. 接收消息:消费者通过通道从队列中接收消息。

以下是一个简单的消费者接收消息的示例代码,同样使用的是RabbitMQ:

import pika

# 创建连接
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# 声明队列
channel.queue_declare(queue='hello')

# 接收消息
def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)

channel.basic_consume(queue='hello',
                      auto_ack=True,
                      on_message_callback=callback)

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()

消息队列的存储机制

消息队列的存储机制通常有两种:

  • 内存存储:消息在内存中暂存,适用于对性能要求较高的场景。
  • 磁盘存储:消息在磁盘中存储,适用于需要持久化消息的场景。

内存存储主要依靠系统的内存来进行消息的存储,这种方式的优点是速度非常快,但缺点是如果系统重启,内存中的消息会被丢失。而磁盘存储则将消息持久化到磁盘中,即使系统重启,消息也不会丢失,但这种方式的速度会比内存存储慢一些。

3. MQ的常见类型及其特点

主题模式

主题模式(Topic)是一种消息模式,适用于消息需要被多个消费者接收的情况。消息根据路由键(Routing Key)决定是否被接收,路由键可以包含一个或多个点分隔的单词(如:topic.routing.key)。消费者通过订阅不同的主题(Topic)来接收消息。

以下是一个主题模式的示例代码,使用的是RabbitMQ:

import pika

# 生产者发送消息
def send_message(exchange_name, routing_key, message):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.exchange_declare(exchange=exchange_name, exchange_type='topic')
    channel.basic_publish(exchange=exchange_name,
                          routing_key=routing_key,
                          body=message)
    connection.close()

send_message("my_exchange", "topic.routing.key", "Hello World!")

# 消费者接收消息
def receive_message(exchange_name, routing_key):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.exchange_declare(exchange=exchange_name, exchange_type='topic')
    result = channel.queue_declare(queue='', exclusive=True)
    queue_name = result.method.queue
    channel.queue_bind(exchange=exchange_name,
                       queue=queue_name,
                       routing_key=routing_key)
    print(f' [*] Waiting for messages on {routing_key}.')

    def callback(ch, method, properties, body):
        print(f" [x] Received {body.decode()}")

    channel.basic_consume(queue=queue_name,
                          auto_ack=True,
                          on_message_callback=callback)
    channel.start_consuming()

receive_message("my_exchange", "topic.routing.key")

队列模式

队列模式(Queue)是消息模式中最简单的一种,消息按照先进先出(FIFO)的原则被消费。每个队列都有唯一的队列名,生产者将消息发送到指定的队列中,消费者从队列中消费消息。

以下是一个队列模式的示例代码,使用的是RabbitMQ:

import pika

# 生产者发送消息
def send_message(queue_name, message):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)
    channel.basic_publish(exchange='',
                          routing_key=queue_name,
                          body=message)
    print(f" [x] Sent {message}")
    connection.close()

send_message('hello_queue', 'Hello World!')

# 消费者接收消息
def receive_message(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        print(f" [x] Received {body.decode()}")

    channel.basic_consume(queue=queue_name,
                          auto_ack=True,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_message('hello_queue')

RPC模式

远程过程调用(RPC)模式是一种消息模式,适用于需要同步通信的场景。生产者发送请求消息到队列,消费者接收请求消息并执行请求,然后将结果发送回生产者。

以下是一个RPC模式的示例代码,使用的是RabbitMQ:

import pika
import uuid

class FibonacciRpcClient:
    def __init__(self):
        self.connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
        self.channel = self.connection.channel()
        result = self.channel.queue_declare(queue='', exclusive=True)
        self.callback_queue = result.method.queue
        self.channel.basic_consume(
            queue=self.callback_queue,
            on_message_callback=self.on_response,
            auto_ack=True)
        self.response = None
        self.corr_id = None

    def on_response(self, ch, method, props, body):
        if self.corr_id == props.correlation_id:
            self.response = body

    def call(self, n):
        self.corr_id = str(uuid.uuid4())
        self.channel.basic_publish(
            exchange='',
            routing_key='rpc_queue',
            properties=pika.BasicProperties(reply_to=self.callback_queue,
                                            correlation_id=self.corr_id),
            body=str(n))
        while self.response is None:
            self.connection.process_data_events()
        return int(self.response)

fibonacci_rpc = FibonacciRpcClient()
print(" [x] Requesting Fibonacci(30)")
response = fibonacci_rpc.call(30)
print(" [.] Got %r" % response)
4. MQ的实现机制

消息的可靠传输

消息的可靠传输是指消息从生产者到消费者的过程中能够确保消息不会丢失。MQ通常通过以下方式来实现消息的可靠传输:

  • 消息确认机制:消费者需要确认消息是否被成功接收,如果未被确认,则MQ会重新发送该消息。
  • 事务机制:MQ使用事务来确保消息在发送和接收过程中的一致性。
  • 消息重试机制:当消息发送失败时,MQ会通过重试机制来重新发送该消息。

以下是一个消息确认机制的示例代码,使用的是RabbitMQ:

import pika

# 消费者接收消息并确认
def receive_message(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        print(f" [x] Received {body.decode()}")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_message('hello_queue')

消息的持久化

消息的持久化是指将消息持久化到磁盘中,以防止系统重启后消息丢失。持久化消息需要满足以下条件:

  • 队列持久化:队列需要被设置为持久化。
  • 消息持久化:消息需要被设置为持久化。

以下是一个持久化消息的示例代码,使用的是RabbitMQ:

import pika

# 生产者发送持久化消息
def send_persistent_message(queue_name, message):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name, durable=True)
    channel.basic_publish(exchange='',
                          routing_key=queue_name,
                          body=message,
                          properties=pika.BasicProperties(delivery_mode=pika.spec.PERSISTENT_DELIVERY_MODE))
    print(f" [x] Sent {message}")
    connection.close()

send_persistent_message('hello_queue', 'Hello World!')

# 消费者接收持久化消息
def receive_persistent_message(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        print(f" [x] Received {body.decode()}")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_persistent_message('hello_queue')

消息的负载均衡

消息的负载均衡是指通过将消息均匀地分发到多个消费者,来提高系统的处理能力。MQ通常通过以下方式来实现负载均衡:

  • 消费者分组:将消费者分组,每个分组负责处理一部分消息。
  • 轮询算法:通过轮询算法将消息均匀地分发到各个消费者。
  • 优先级算法:通过优先级算法将高优先级的消息优先处理。

以下是一个负载均衡的示例代码,使用的是RabbitMQ:

import pika
import time

# 生产者发送消息
def send_message(queue_name, message):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)
    channel.basic_publish(exchange='',
                          routing_key=queue_name,
                          body=message)
    print(f" [x] Sent {message}")
    connection.close()

send_message('hello_queue', 'Hello World!')

# 消费者接收消息并处理
def receive_message(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        print(f" [x] Received {body.decode()}")
        time.sleep(body.count(b'.'))
        print(" [x] Done")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_message('hello_queue')
5. MQ的常用术语解释

生产者与消费者

在MQ中,生产者负责生成消息并发送到消息队列中,消费者负责从消息队列中消费消息。生产者和消费者之间没有直接的依赖关系,这使得系统可以更加灵活和可扩展。

消息路由与分发

消息路由是指根据消息的路由键(Routing Key)决定消息被发送到哪个队列中。消息分发是指将消息均匀地分发到各个消费者中,以实现负载均衡。

消息确认机制

消息确认机制是指消费者需要确认是否成功接收消息,如果未被确认,则MQ会重新发送该消息。这种机制能够确保消息的可靠传输。

以下是一个简单的消息确认机制示例代码,使用的是RabbitMQ:

import pika

# 消费者接收消息并确认
def receive_message(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        print(f" [x] Received {body.decode()}")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_message('hello_queue')
6. MQ的实际应用案例

网站浏览量统计

在网站浏览量统计的应用场景中,可以使用MQ来收集来自不同来源的浏览量数据,然后将这些数据发送到消息队列中。后台系统通过消费消息来处理这些数据,并计算出网站的浏览量。

以下是一个简单的浏览量统计的示例代码,使用的是RabbitMQ:

import pika
import random

# 生产者发送浏览量数据
def send_pv_data(queue_name, pv_data):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)
    channel.basic_publish(exchange='',
                          routing_key=queue_name,
                          body=str(pv_data))
    print(f" [x] Sent {pv_data}")
    connection.close()

pv_data = random.randint(1, 100)
send_pv_data('pv_queue', pv_data)

# 消费者接收并处理浏览量数据
def receive_pv_data(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        pv_data = int(body.decode())
        print(f" [x] Received {pv_data}")
        # 处理浏览量数据
        print(f" [x] Processed {pv_data}")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_pv_data('pv_queue')

系统异步解耦

在系统异步解耦的应用场景中,可以使用MQ来解耦应用中的各个组件,使得这些组件之间的交互是异步的。这可以提高系统的整体性能,并且使得系统更加灵活和可扩展。

以下是一个简单的系统异步解耦的示例代码,使用的是RabbitMQ:

import pika

# 生产者发送数据
def send_data(queue_name, message):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)
    channel.basic_publish(exchange='',
                          routing_key=queue_name,
                          body=message)
    print(f" [x] Sent {message}")
    connection.close()

send_data('async_queue', 'Hello World!')

# 消费者接收数据并处理
def receive_data(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        data = body.decode()
        print(f" [x] Received {data}")
        # 异步处理数据
        print(f" [x] Processed {data}")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_data('async_queue')

消息通知与提醒

在消息通知与提醒的应用场景中,可以使用MQ来发送通知和提醒消息到用户的设备上。例如,当有新的邮件或消息时,可以将通知消息发送到MQ中,然后由后台系统通过MQ将通知消息推送到用户的设备上。

以下是一个简单的消息通知与提醒的示例代码,使用的是RabbitMQ:


import pika

# 生产者发送通知消息
def send_notification(queue_name, message):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)
    channel.basic_publish(exchange='',
                          routing_key=queue_name,
                          body=message)
    print(f" [x] Sent {message}")
    connection.close()

send_notification('notification_queue', 'New message received!')

# 消费者接收通知消息并处理
def receive_notification(queue_name):
    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()
    channel.queue_declare(queue=queue_name)

    def callback(ch, method, properties, body):
        notification = body.decode()
        print(f" [x] Received {notification}")
        # 处理通知消息
        print(f" [x] Processed {notification}")
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_qos(prefetch_count=1)
    channel.basic_consume(queue=queue_name,
                          on_message_callback=callback)
    print(' [*] Waiting for messages. To exit press CTRL+C')
    channel.start_consuming()

receive_notification('notification_queue')
``

以上是MQ的基本概念、工作原理、常见类型、实现机制、常用术语以及实际应用案例的详细介绍。通过学习这些内容,你将能够更好地理解和使用MQ。如果你想深入学习MQ,可以参考[M慕课网](https://www.imooc.com/)上的相关课程。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消