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

MQ底层原理资料详解:新手入门指南

概述

本文详细介绍了消息队列(MQ)的基本概念、工作原理和应用场景,涵盖消息发送、存储、传输与消费的全过程。文章还比较了Kafka、RabbitMQ和RocketMQ等常见MQ技术的优缺点,并提供了开发和调试MQ系统的实用技巧。文中提供了丰富的MQ底层原理资料,帮助读者全面了解MQ技术。

MQ底层原理资料详解:新手入门指南
1. 什么是消息队列(MQ)及其基本概念

1.1 消息队列的主要功能和应用场景

消息队列(MQ)是一种软件应用程序,它为处理应用程序之间的数据交换提供了平台。它使应用程序异步通信,解耦了发送者和接收者的关系。在分布式系统中,消息队列可以用于减轻系统之间的耦合,实现流量削峰,缓存热点请求,并提供异步消息处理的能力。

消息队列具有以下主要功能和应用场景:

  • 解耦系统:通过引入消息队列,可以将发送者和接收者解耦,使它们不必同时运行或依赖于彼此的存在。
  • 流量削峰:在请求高峰时,使用消息队列可以将请求缓存起来,以平滑请求的波动。
  • 异步处理:应用程序之间通过发送异步消息实现通信,不必等待对方立即响应。
  • 扩展性:消息队列可以帮助系统扩展,通过负载均衡机制将消息分散到多个消费者处理。
  • 数据复制:消息队列支持消息的复制,确保数据不丢失。
  • 错误处理:通过重试机制,消息队列可以处理传输中的错误,确保消息最终被处理。

1.2 MQ的基本概念和术语介绍

在消息队列中,有几个核心概念和术语是理解MQ的关键:

  • 消息生产者:产生数据的程序,负责将消息发送到消息队列。
  • 消息消费者:处理消息的程序,负责从消息队列中读取消息并进行处理。
  • 消息队列:一个临时的存储空间,用于存放发送者发送过来的消息直到被接收者消费。
  • 消息:消息队列中传递的数据单元,可以是简单字符串、XML、JSON等格式。
  • 主题:消息队列中的一个逻辑命名空间,用于区分不同的消息流,消费者可以订阅一个或多个主题以接收消息。
  • 分发模式:消息队列中的消息分发方式,常用的分发模式包括“一对一”、“一对多”、“多对一”、“发布/订阅”等。
  • 持久化:消息在消息队列中的持续存储,确保消息不会因系统重启或故障而丢失。
  • 消息确认:消费者确认消息已被处理,通知队列可以安全地删除消息。
  • 消息过滤:通过设置规则来过滤不需要的消息,只接收符合规则的消息。

消息发送与接收示例代码

以下是一个简单的Python代码示例,展示如何使用pika库发送和接收消息到RabbitMQ消息队列:

# 发送消息
import pika

# 创建一个连接到 RabbitMQ 服务器
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()

# 接收消息
import pika

# 创建一个连接到 RabbitMQ 服务器
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    ch.basic_ack(delivery_tag=method.delivery_tag)

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

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
2. MQ工作原理概述

2.1 发送者与接收者模型

消息队列系统通常由发送者(Producer)、接收者(Consumer)和消息队列(Message Queue)组成,其基本的工作流程如下:

  1. 发送者模型

    • 发送者将消息发送到消息队列。
    • 消息队列根据配置的路由规则,将消息存储或转发给接收者。
  2. 接收者模型
    • 接收者从消息队列中读取消息并处理。
    • 接收者可以选择消费队列中的所有消息,或仅消费部分消息。

2.2 消息的生产和消费流程

在消息生产和消费的流程中,消息的传输、存储和处理是核心环节:

  1. 消息生产

    • 发送者创建一条消息。
    • 发送者将消息通过网络发送到消息队列。
    • 消息队列接收到消息并保存到存储介质中。
  2. 消息存储

    • 消息队列将消息暂存,以便后续处理。
    • 根据队列的配置,消息可以被持久化存储或者在内存中暂存。
  3. 消息传输

    • 消息队列根据配置的路由规则,将消息传输给接收者。
    • 接收者通过消息队列的API读取消息。
  4. 消息消费
    • 接收者从消息队列中读取消息。
    • 接收者处理消息并生成响应。
    • 接收者发送确认消息给消息队列,表示消息已被处理。

发送者与接收者模型示例代码

以下是一个简单的Python代码示例,展示如何发送和接收消息到RabbitMQ消息队列:

# 发送消息
import pika

# 创建一个连接到 RabbitMQ 服务器
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()

# 接收消息
import pika

# 创建一个连接到 RabbitMQ 服务器
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)

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

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
3. 通用消息队列架构详解

3.1 消息发送过程

在消息队列中,消息发送过程包括以下几个步骤:

  1. 创建消息

    • 消息生产者创建一条消息,包含必要的消息头和消息体。
    • 消息生产者对消息进行序列化,以便于网络传输。
  2. 发送消息

    • 消息生产者将消息封装成一个请求,通过网络发送到消息队列。
    • 消息队列接收到请求后,根据路由规则将消息存储到队列中。
  3. 路由规则

    • 使用路由规则决定消息的存储位置。
    • 常见的路由规则包括按主题、按队列等。
  4. 持久化

    • 消息队列将消息存储到持久化介质中,例如磁盘或分布式存储系统。
    • 消息队列确保消息的持久化,以便在系统故障时不会丢失消息。
  5. 持久化确认
    • 发送者收到消息队列的确认后,确认消息已被持久化。
    • 如果消息队列无法持久化消息,则会返回错误信息给发送者。

示例代码

以下是一个简单的Python代码示例,使用pika库发送消息到RabbitMQ消息队列:

import pika

# 创建一个连接到 RabbitMQ 服务器
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()

3.2 消息存储与传输机制

消息队列系统通常使用以下机制存储和传输消息:

  1. 内存存储

    • 消息队列可以将消息存储在内存中,以提高消息的传输速度。
    • 内存中的消息会在内存满时或系统重启时丢失。
  2. 磁盘存储

    • 消息队列可以将消息持久化存储在磁盘上,确保消息不会因系统故障而丢失。
    • 消息队列可以通过日志机制将消息记录在磁盘中,以支持故障恢复。
  3. 网络传输

    • 消息队列中的消息通过网络传输到接收者。
    • 传输过程通常使用TCP/IP协议,确保消息的可靠传输。
    • 消息队列可以使用压缩算法减少传输的数据量,提高传输速度。
  4. 分布式存储
    • 消息队列可以使用分布式存储系统,例如HDFS或Ceph,存储大量消息。
    • 分布式存储系统可以通过冗余机制防止数据丢失。

3.3 消息接收过程

在消息接收过程中,接收者从消息队列中读取消息并处理:

  1. 接收消息

    • 接收者通过消息队列的API从队列中读取消息。
    • 接收者可以选择消费队列中的所有消息,或仅消费部分消息。
  2. 消息处理

    • 接收者将接收到的消息解序列化,并根据消息类型进行处理。
    • 处理过程中,接收者可以执行业务逻辑,例如更新数据库或发送响应。
  3. 消息确认

    • 接收者处理完消息后,发送确认消息给消息队列。
    • 消息队列收到确认后,删除消息或将其标记为已处理。
  4. 错误处理
    • 如果接收者处理消息时发生错误,可以设置重试机制,确保消息最终被处理。
    • 接收者可以记录错误日志,以便追踪和调试。

示例代码

以下是一个简单的Python代码示例,使用pika库从RabbitMQ消息队列中接收消息:

import pika

# 创建一个连接到 RabbitMQ 服务器
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)
    # 处理消息
    print(" [x] Done")

# 启用消费模式
channel.basic_consume(queue='hello', on_message_callback=callback, auto_ack=True)

print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
4. 常见MQ技术比较

4.1 Kafka

Kafka是一个分布式流处理平台,主要特点是高吞吐量、持久化消息和水平扩展。Kafka可以用于构建实时数据管道、日志聚合和流处理应用。Kafka使用了分布式日志的模型,每个数据流称为一个主题。主题可以进一步分为多个分区,每个分区都是一个追加日志,可以独立扩展。Kafka采用拉取模型,消费者主动从Kafka服务器拉取消息,这样可以降低网络流量,并减少服务器的负载。

Kafka示例代码

以下是一个简单的Python代码示例,使用kafka-python库发送和接收消息到Kafka消息队列:

# 发送消息
from kafka import KafkaProducer

producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('my-topic', key=b'my-key', value=b'my-value')
producer.close()

# 接收消息
from kafka import KafkaConsumer

consumer = KafkaConsumer('my-topic', bootstrap_servers='localhost:9092')
for message in consumer:
    print(" [x] Received %s" % message.value)
    break

4.2 RabbitMQ

RabbitMQ是一个开源的消息代理,支持多种消息协议,包括AMQP。RabbitMQ的架构允许它支持大规模的消息传递,包括持久化、内存存储和分布式交换器。RabbitMQ提供了高可用性、负载均衡和集群管理等特性,使得它成为构建分布式系统和微服务的优秀选择。RabbitMQ的消息路由模型可以实现消息的灵活分发。

RabbitMQ示例代码

以下是一个简单的Python代码示例,使用pika库发送和接收消息到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()

# 接收消息
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    ch.basic_ack(delivery_tag=method.delivery_tag)

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

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

4.3 RocketMQ

RocketMQ是一个开源的分布式消息系统,由阿里巴巴开发并贡献给Apache基金会。RocketMQ支持高并发、高吞吐量的消息传递,并且具有优秀的可扩展性和可靠性。RocketMQ提供多样的消息传递模式,包括同步、异步和单向传递。RocketMQ还支持事务消息、消息顺序性等高级特性,使其能够满足各种复杂的应用需求。RocketMQ的集群模式提供了高可用性和容错性。

RocketMQ示例代码

以下是一个简单的Java代码示例,使用RocketMQ发送和接收消息:

// 发送消息
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;

public class SimpleProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
        producer.setNamesrvAddr("localhost:9876");
        producer.start();

        Message msg = new Message("TopicTest", "TagA", "OrderID001".getBytes(RemotingHelper.DEFAULT_CHARSET));

        SendResult sendResult = producer.send(msg);
        System.out.println(sendResult);

        producer.shutdown();
    }
}

// 接收消息
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;

public class SimpleConsumer {
    public static void main(String[] args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName");
        consumer.setNamesrvAddr("localhost:9876");
        consumer.subscribe("TopicTest", "TagA");

        consumer.registerMessageListener(new MessageListenerOrderly() {
            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                for (MessageExt msg : msgs) {
                    System.out.println("Receive New Messages: " + new String(msg.getBody()));
                }
                return ConsumeOrderlyStatus.SUCCESS;
            }
        });

        consumer.start();
    }
}

4.4 集群模式与扩展性

  • Kafka:Kafka的分区机制使其具备水平扩展能力,支持多个副本,确保高可用性。
  • RabbitMQ:RabbitMQ通过镜像队列和集群模式支持水平扩展,确保系统在节点故障时仍然可用。
  • RocketMQ:RocketMQ通过集群模式支持水平扩展,能够在多台机器之间分发消息,提高系统的吞吐量和可用性。

4.5 优缺点比较

  • Kafka
    • 优点:高吞吐量、持久化、水平扩展、实时流处理。
    • 缺点:配置复杂、不适合小规模应用、对硬件要求高。
  • RabbitMQ
    • 优点:灵活的消息路由、支持多种消息协议、高可用性。
    • 缺点:内存消耗较大、不适合处理大数据量的实时数据流。
  • RocketMQ
    • 优点:高性能、多种消息传递模式、支持事务消息。
    • 缺点:学习曲线较陡、可能存在消息丢失的风险。
5. MQ应用场景及案例分析

5.1 MQ在实际项目中的应用案例

在实际项目中,消息队列被广泛应用于各种场景。以下是一些具体的案例:

  • 物流配送系统

    • 需求:在物流配送系统中,需要将订单信息、物流信息等实时同步到各个服务模块。
    • 解决方案:使用消息队列将订单信息发送给配送系统、财务系统等模块,确保信息的实时同步。
    • 优势:解耦系统模块,提高系统可用性。
    • 示例代码
      
      import pika
    发送订单信息

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='order_queue')

    channel.basic_publish(exchange='',
    routing_key='order_queue',
    body='New order received')

    print("[x] Sent 'New order received'")
    connection.close()

  • 电商平台

    • 需求:电商平台需要实时处理大量的订单信息,包括支付、物流、库存等。
    • 解决方案:使用消息队列异步处理订单信息,减轻服务器的压力,提升用户体验。
    • 优势:异步处理提高系统性能,减少延迟。
    • 示例代码
      
      import pika
    发送订单支付信息

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='payment_queue')

    channel.basic_publish(exchange='',
    routing_key='payment_queue',
    body='Payment received')

    print("[x] Sent 'Payment received'")
    connection.close()

  • 金融行业

    • 需求:在金融行业中,需要实时处理大量的交易信息,确保数据的安全性和一致性。
    • 解决方案:使用消息队列处理交易信息,确保数据的一致性和可靠性。
    • 优势:高可用性,确保金融系统的稳定运行。
    • 示例代码
      
      import pika
    发送交易信息

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='transaction_queue')

    channel.basic_publish(exchange='',
    routing_key='transaction_queue',
    body='Transaction successful')

    print("[x] Sent 'Transaction successful'")
    connection.close()

5.2 MQ技术选择时应考虑的因素

在选择消息队列技术时,需要考虑以下几个因素:

  • 消息吞吐量:根据系统的吞吐量需求选择合适的消息队列技术。
  • 消息延迟:对于实时性强的应用,需要选择延迟较低的消息队列。
  • 消息可靠性:对于需要保障消息可靠性的系统,选择支持持久化存储的消息队列。
  • 扩展性:系统是否需要水平扩展,以及是否支持多节点部署。
  • 社区支持:选择具有活跃社区和丰富文档的技术,便于学习和维护。
  • 成本:考虑开源版本与商业版之间的成本差异,以及是否符合预算。
  • 开发语言:选择与项目开发语言兼容的消息队列技术。
6. MQ开发与调试技巧

6.1 常见问题与调试方法

在开发和调试消息队列系统时,经常遇到一些常见的问题和调试方法:

  • 消息丢失

    • 问题:消息在传输过程中丢失。
    • 调试方法:检查消息队列的配置,确保消息持久化存储,使用日志记录消息的生命周期。
    • 解决方案:增加消息重试机制,确保消息最终被处理。
    • 示例代码
      
      import pika
    设置持久化消息

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='persistent_queue', durable=True)

    channel.basic_publish(exchange='',
    routing_key='persistent_queue',
    body='Persistent message',
    properties=pika.BasicProperties(delivery_mode=pika.DeliveryMode.Transient))

    print("[x] Sent 'Persistent message'")
    connection.close()

  • 消息重复

    • 问题:消费者重复接收到相同的消息。
    • 调试方法:检查消息队列的配置,确保消息队列的唯一性检查机制。
    • 解决方案:使用消息ID或序列号来唯一标识消息,避免重复处理。
    • 示例代码
      
      import pika
    使用消息ID避免重复

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    def callback(ch, method, properties, body):
    print(" [x] Received %r" % body)
    ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_consume(queue='unique_queue', on_message_callback=callback)

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

  • 消息延迟

    • 问题:消息处理延迟,导致系统响应时间变长。
    • 调试方法:检查消息队列的性能瓶颈,例如网络延迟、CPU负载等。
    • 解决方案:优化消息队列的配置,增加消息队列的资源,提高系统的吞吐量。
    • 示例代码
      
      import pika
    优化消息处理时间

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    def callback(ch, method, properties, body):
    print(" [x] Processing message...")

    这里可以增加耗时处理逻辑,例如数据库操作或者复杂的业务逻辑
    ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_consume(queue='high_performance_queue', on_message_callback=callback)

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

  • 连接问题

    • 问题:消息队列客户端与服务器之间的连接中断。
    • 调试方法:检查网络连接,确保消息队列服务器的可用性。
    • 解决方案:增加连接重试机制,确保客户端能够重新连接。
    • 示例代码
      
      import pika
      import time
    增加连接重试机制

    def on_connection_open(connection_params):
    try:
    connection = pika.BlockingConnection(connection_params)
    channel = connection.channel()
    channel.queue_declare(queue='retry_queue')
    connection.close()
    except pika.exceptions.AMQPConnectionError:
    print("Connection lost, retrying...")
    time.sleep(5)

    connection_params = pika.ConnectionParameters('localhost')
    on_connection_open(connection_params)

  • 异常处理

    • 问题:消息处理中发生异常。
    • 调试方法:记录异常日志,分析异常原因。
    • 解决方案:增加异常处理逻辑,确保系统能够正确处理异常情况。
    • 示例代码
      
      import pika
    异常处理逻辑

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    def callback(ch, method, properties, body):
    try:
    print(" [x] Received %r" % body)

    这里可以增加异常处理逻辑,例如捕获并记录异常
    except Exception as e:
        print(" [x] Exception: %s" % e)
        ch.basic_nack(delivery_tag=method.delivery_tag)
    else:
        ch.basic_ack(delivery_tag=method.delivery_tag)

    channel.basic_consume(queue='error_queue', on_message_callback=callback)

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

6.2 MQ配置与优化建议

在配置和优化消息队列时,可以参考以下建议:

  • 消息持久化

    • 配置:确保消息持久化存储,避免系统重启时消息丢失。
    • 优化:使用分布式存储系统,提高消息的存储效率。
    • 示例代码
      
      import pika
    创建持久化队列

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='persistent', durable=True)

    发送持久化消息

    channel.basic_publish(exchange='',
    routing_key='persistent',
    body='Persistent message',
    properties=pika.BasicProperties(delivery_mode=pika.DeliveryMode.Transient))

    print(" [x] Sent 'Persistent message'")
    connection.close()

  • 负载均衡

    • 配置:使用负载均衡机制将消息分散到多个消费者处理。
    • 优化:根据消费者的负载情况动态调整消息的分配。
    • 示例代码
      
      from kafka import KafkaConsumer
    使用消费者组实现负载均衡

    consumer = KafkaConsumer('my-topic', group_id='my-group')

    for message in consumer:
    print(" [x] Received %s: %s" % (message.topic, message.value))

  • 消息压缩

    • 配置:启用消息压缩,减少传输的数据量。
    • 优化:选择合适的压缩算法,提高压缩效率。
    • 示例代码
      
      from kafka import KafkaProducer
    启用消息压缩

    producer = KafkaProducer(compression_type='gzip', bootstrap_servers=['localhost:9092'])

    发送压缩消息

    producer.send('my-topic', key=b'my-key', value=b'my-value')

    producer.close()

  • 错误重试

    • 配置:设置消息重试机制,确保消息最终被处理。
    • 优化:根据错误类型设置不同的重试策略。
    • 示例代码
      
      import pika
    设置消息重试

    connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
    channel = connection.channel()

    channel.queue_declare(queue='retry_queue', arguments={
    'x-message-ttl': 10000,
    'x-dead-letter-exchange': '',
    'x-dead-letter-routing-key': 'retry_queue.dead_letter'
    })

    发送一条消息

    channel.basic_publish(exchange='',
    routing_key='retry_queue',
    body='Retry message')

    print(" [x] Sent 'Retry message'")
    connection.close()

通过这些配置和优化方法,可以提高消息队列系统的性能和可靠性,确保系统的稳定运行。

点击查看更多内容
TA 点赞

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

评论

作者其他优质文章

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

100积分直接送

付费专栏免费学

大额优惠券免费领

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

举报

0/150
提交
取消