程序员进阶工程师必备技能之中间件深度使用与运维(一)

简介: 教程来源 https://zlpow.cn/ 中间件是分布式系统的“神经系统”,位于操作系统与应用之间,屏蔽底层异构性,提供消息队列、缓存、分库分表、服务治理等标准化能力。它是高并发、高可用架构的核心基石。

中间件——分布式系统的“神经系统”
如果说操作系统是计算机的“大脑”,那么中间件就是分布式系统的“神经系统”。它连接着系统中的各个部分,协调它们的工作,传递信息与数据,保障整个系统的协同运转。

当你从初级程序员成长为工程师,你会发现一个残酷的现实:单纯写对业务逻辑已经不够了。你需要回答这些问题:

消息队列为什么会积压?如何让它在双十一洪峰中屹立不倒?

数据库连接池为什么总在凌晨三点爆满?是慢SQL还是连接泄漏?

Redis 主从切换后,缓存雪崩如何预防?

如何保证消息不丢失、不重复,Exactly-Once 真的能做到吗?

这些问题,触及了中间件深度使用与运维的核心。本文将系统性地剖析消息队列、数据库中间件、缓存中间件的核心原理与运维实践,帮助你从“会用”走向“精通”。

一、中间件在工程化体系中的定位

1.1 中间件的定义与价值
中间件是位于操作系统、数据库和应用程序之间的软件层,它屏蔽了底层系统的复杂性,为上层应用提供标准化的服务接口。

在工程化体系中,中间件承担着四大核心职责:

┌─────────────────────────────────────────────────────────────────┐
│                      中间件在架构中的定位                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────┐                                               │
│   │  业务应用    │                                               │
│   └──────┬──────┘                                               │
│          │                                                      │
│   ┌──────▼──────────────────────────────────────────────────┐  │
│   │                    中间件层                               │  │
│   │  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐        │  │
│   │  │消息队列 │ │ 分库分表 │ │  缓存   │ │ 服务发现 │        │  │
│   │  │ RabbitMQ│ │  Mycat  │ │  Redis  │ │  Nacos  │        │  │
│   │  │  Kafka  │ │ Sharding │ │  Memcache│ │  Consul │        │  │
│   │  │  Pulsar │ │  JDBC   │ │         │ │   Etcd  │        │  │
│   │  └─────────┘ └─────────┘ └─────────┘ └─────────┘        │  │
│   └──────┬──────────────────────────────────────────────────┘  │
│          │                                                      │
│   ┌──────▼──────┐    ┌──────────┐    ┌──────────┐              │
│   │   数据库    │    │  文件系统 │    │  外部API  │              │
│   └─────────────┘    └──────────┘    └──────────┘              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

中间件的四大核心价值:
image.png
1.2 中间件的分类体系
从功能维度,中间件可以分为以下几大类:

1.消息中间件

功能:异步通信、应用解耦、流量削峰

代表产品:RabbitMQ、Kafka、RocketMQ、Pulsar

核心特性:持久化、确认机制、死信队列、事务消息

2.数据库中间件

功能:读写分离、分库分表、数据源路由

代表产品:Mycat、ShardingSphere、Vitess

核心特性:SQL解析、分片策略、结果聚合

3.缓存中间件

功能:高速数据存取、热点数据缓存

代表产品:Redis、Memcached、Hazelcast

核心特性:持久化、哨兵/集群、多数据结构

4.服务治理中间件

功能:服务注册发现、配置管理、负载均衡

代表产品:Nacos、Consul、Etcd、ZooKeeper

核心特性:CP/AP权衡、健康检查、服务路由

1.3 云原生时代的中间件进化
在容器化时代,中间件正经历着深刻的变革。传统中间件(如MySQL、Redis)的容器化适配面临三大挑战:

状态管理困境:有状态中间件的持久化数据卷在Pod漂移时需要无缝迁移,这对存储层网络性能、数据一致性算法提出更高要求

网络模型变革:容器网络接口(CNI)需要支持Service Mesh所需的透明流量劫持,同时满足中间件节点间的低延迟通信

配置中心迁移:传统ZooKeeper等配置管理工具需适应Kubernetes CRD模式,实现配置变更与Pod生命周期的自动同步

云原生中间件的设计正朝着以下方向演进:

无状态化改造:通过外部化存储(如S3兼容对象存储)解耦计算与数据

弹性伸缩单元:基于Horizontal Pod Autoscaler实现QPS驱动的自动扩缩容

可观测性内置:集成Prometheus Exporter与分布式追踪(OpenTelemetry)

二、消息中间件深度实践

2.1 核心概念与架构原理
消息中间件的核心是队列和主题两种模型:

队列模型:点对点通信,一条消息只能被一个消费者处理

发布-订阅模型:一条消息可以被多个消费者处理

以RabbitMQ为例,其核心架构包括:

┌─────────────────────────────────────────────────────────────────┐
│                      RabbitMQ 架构图                             │
│                                                                 │
│   Producer ──► Exchange ──► Binding ──► Queue ──► Consumer     │
│                    │                                            │
│                    ▼                                            │
│              ┌──────────┐                                       │
│              │  Types:  │                                       │
│              │ Direct   │                                       │
│              │ Fanout   │                                       │
│              │ Topic    │                                       │
│              │ Headers  │                                       │
│              └──────────┘                                       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

关键概念解析:

Producer(生产者):消息的发送方

Consumer(消费者):消息的接收方

Queue(队列):存储消息的缓冲区

Exchange(交换器):接收生产者消息并路由到队列

Binding(绑定):定义交换器与队列的关联规则

Routing Key(路由键):决定消息去向的标识

Virtual Host(虚拟主机):资源隔离单元

2.2 生产级部署与环境治理
2.2.1 基础设施层监控
部署中间件前,必须先建立完善的资源监控体系。监控的核心目标是追踪承载服务的实体环境健康度,包括:

计算资源:CPU使用率与负载情况

内存资源:内存消耗与交换情况

存储资源:磁盘容量与I/O性能

网络资源:带宽利用率与连接状态

2.2.2 RabbitMQ 生产级安装(CentOS)
在生产环境部署RabbitMQ时,需进行系统层面的调优:

# 1. 系统参数调整
echo "vm.max_map_count=655360" >> /etc/sysctl.conf
echo "fs.file-max=200000" >> /etc/sysctl.conf
sysctl -p

# 2. 文件描述符限制
echo "rabbitmq soft nofile 65536" >> /etc/security/limits.conf
echo "rabbitmq hard nofile 65536" >> /etc/security/limits.conf

# 3. 内核参数优化
cat >> /etc/sysctl.conf << EOF
# 网络优化
net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_reuse = 1
# 内存优化
vm.swappiness = 10
vm.dirty_ratio = 15
EOF

2.2.3 核心配置参数解析
RabbitMQ从3.7版本开始采用sysctl风格的配置文件,替代了传统的Erlang语法格式:

# /etc/rabbitmq/rabbitmq.conf

# ========== 网络监听配置 ==========
# AMQP 0-9-1 协议监听端口
listeners.tcp.default = 5672
# 指定监听IP(生产环境避免0.0.0.0)
listeners.tcp.local = 192.168.1.10:5672

# ========== 管理插件配置 ==========
# Web管理界面端口
management.listener.port = 15672
# 限制管理界面访问IP
management.listener.ip = 127.0.0.1

# ========== 内存控制 ==========
# 内存高水位线:当内存占用超过系统总内存的40%时触发流控
vm_memory_high_watermark.relative = 0.4
# 内存达到阈值时的强制GC
vm_memory_high_watermark_paging_ratio = 0.5

# ========== 磁盘控制 ==========
# 磁盘空闲下限(绝对值模式)
disk_free_limit.absolute = 2GB
# 或使用相对值模式(系统总内存的倍数)
# disk_free_limit.relative = 2.0

# ========== 连接管理 ==========
# 最大连接数
channel_max = 2047
# 心跳超时(秒)
heartbeat = 60

# ========== 持久化优化 ==========
# 队列索引类型(rabbit、msg_store、disc)
queue_index_embed_msgs_below = 4096
# 消息持久化写入方式
lazy_queue = false

配置解析:

内存高水位线:当RabbitMQ内存占用超过阈值,将触发流控机制,阻塞消息发布者。建议设置在40%-60%,过高增加OOM风险,过低影响吞吐量

磁盘空闲限制:当可用空间低于阈值时,RabbitMQ将拒绝新的消息写入。该值应结合磁盘监控与消息留存策略动态调整

监听配置:生产环境应避免绑定0.0.0.0这种通配地址,指定具体内网IP可减少攻击面

2.3 高可用架构设计
2.3.1 集群部署模式
在Kubernetes环境中部署有状态中间件,推荐使用StatefulSet:

# rabbitmq-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rabbitmq
spec:
  serviceName: rabbitmq
  replicas: 3
  selector:
    matchLabels:
      app: rabbitmq
  template:
    metadata:
      labels:
        app: rabbitmq
    spec:
      # Pod反亲和性:强制Pod分散在不同节点
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values: [rabbitmq]
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: rabbitmq
        image: rabbitmq:3.12-management
        env:
        - name: RABBITMQ_ERLANG_COOKIE
          valueFrom:
            secretKeyRef:
              name: rabbitmq-secret
              key: cookie
        - name: RABBITMQ_NODENAME
          value: "rabbit@$(POD_NAME).rabbitmq.$(NAMESPACE).svc.cluster.local"
        ports:
        - containerPort: 5672
          name: amqp
        - containerPort: 15672
          name: http
        volumeMounts:
        - name: data
          mountPath: /var/lib/rabbitmq
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
          limits:
            cpu: "2"
            memory: "4Gi"
        readinessProbe:
          exec:
            command: ["rabbitmq-diagnostics", "ping"]
          initialDelaySeconds: 20
          periodSeconds: 10
        livenessProbe:
          exec:
            command: ["rabbitmq-diagnostics", "status"]
          initialDelaySeconds: 60
          periodSeconds: 30
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "fast-ssd"
      resources:
        requests:
          storage: 100Gi

关键配置解析:

podAntiAffinity:强制Pod分散在不同物理节点,避免单点故障

volumeClaimTemplates:为每个Pod动态创建持久化存储卷

readinessProbe:通过rabbitmq-diagnostics ping检查服务可用性

Erlang Cookie:集群节点间通信的密钥,需通过Secret统一管理

2.3.2 镜像队列与仲裁队列

# 设置镜像队列策略(所有队列镜像到所有节点)
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all","ha-sync-mode":"automatic"}'

# 设置仲裁队列策略(Quorum Queues - 推荐用于高可靠场景)
rabbitmqctl set_policy quorum-policy "^queues\." '{"queue-type":"quorum"}' --priority 1

# 查看队列同步状态
rabbitmqctl list_queues name slave_pids synchronised_slave_pids

镜像队列 vs 仲裁队列:
image.png
2.3.3 多区域高可用
对于跨AZ(可用区)部署,需要更精细的设计:

┌─────────────────────────────────────────────────────────────────┐
│                    跨AZ高可用部署架构                             │
│                                                                 │
│   Region A (主)              Region B (备)      Region C (备)    │
│   ┌─────────────────┐        ┌─────────────────┐               │
│   │ RabbitMQ Node 1 │◄──────►│ RabbitMQ Node 2 │◄──────►       │
│   │  (Leader)       │  Raft  │  (Follower)     │  Raft         │
│   └─────────────────┘        └─────────────────┘               │
│           │                          │                          │
│           ▼                          ▼                          │
│   ┌─────────────────┐        ┌─────────────────┐               │
│   │ Load Balancer   │        │ Load Balancer   │               │
│   │   (内网VIP)      │        │   (内网VIP)      │               │
│   └─────────────────┘        └─────────────────┘               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.4 消息可靠性与幂等性设计
2.4.1 消息不丢失的三段式保障
消息从生产到消费会经过三个环节,每个环节都可能丢失消息:

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   生产端      │ ─► │  消息队列    │ ─► │   消费端      │
│  生产者确认   │    │   持久化     │    │  消费者确认   │
└──────────────┘    └──────────────┘    └──────────────┘
  1. 生产端可靠性配置
    ```
    import pika
    import uuid

class ReliableProducer:
"""可靠消息生产者"""

def __init__(self, host='localhost'):
    self.connection = pika.BlockingConnection(
        pika.ConnectionParameters(
            host=host,
            heartbeat=60,
            blocked_connection_timeout=300
        )
    )
    self.channel = self.connection.channel()
    # 设置确认模式
    self.channel.confirm_delivery()

def publish_with_confirm(self, exchange, routing_key, message, max_retries=3):
    """带生产者确认的消息发送"""
    for attempt in range(max_retries):
        try:
            # 设置消息持久化属性
            properties = pika.BasicProperties(
                delivery_mode=2,  # 消息持久化
                message_id=str(uuid.uuid4()),
                timestamp=int(time.time()),
                content_type='application/json'
            )

            # 发送并等待确认
            self.channel.basic_publish(
                exchange=exchange,
                routing_key=routing_key,
                body=json.dumps(message),
                properties=properties,
                mandatory=True  # 要求路由必须成功
            )

            # 等待Broker确认
            self.channel.wait_for_confirms(timeout=5)
            return True

        except pika.exceptions.UnroutableError:
            # 路由失败处理
            self._handle_unroutable(message)
            return False

        except pika.exceptions.NackError:
            # 消息被拒绝
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)  # 指数退避
                continue
            raise

        except Exception as e:
            print(f"发送失败: {e}")
            if attempt < max_retries - 1:
                time.sleep(1)
                continue
            raise

    return False

def _handle_unroutable(self, message):
    """处理不可路由的消息"""
    # 记录到死信队列或日志
    logging.error(f"Unroutable message: {message}")
2. 消费端可靠性配置

class ReliableConsumer:
"""可靠消息消费者 - 手动确认模式"""

def __init__(self, host='localhost', queue='task_queue'):
    self.connection = pika.BlockingConnection(
        pika.ConnectionParameters(host=host)
    )
    self.channel = self.connection.channel()

    # 设置QoS(服务质量)
    self.channel.basic_qos(prefetch_count=1)  # 每次只取一条消息

    self.queue = queue

def start_consuming(self, callback):
    """开始消费,使用手动确认"""
    self.channel.basic_consume(
        queue=self.queue,
        on_message_callback=self._wrap_callback(callback),
        auto_ack=False  # 手动确认,关键配置
    )
    self.channel.start_consuming()

def _wrap_callback(self, user_callback):
    def wrapper(ch, method, properties, body):
        try:
            # 执行业务逻辑
            result = user_callback(json.loads(body), properties)

            if result:
                # 成功处理,发送确认
                ch.basic_ack(delivery_tag=method.delivery_tag)
            else:
                # 处理失败,拒绝并重新入队
                ch.basic_nack(
                    delivery_tag=method.delivery_tag,
                    requeue=True  # 重新入队
                )

        except Exception as e:
            # 异常情况:记录日志,拒绝并重新入队
            logging.exception(f"处理消息失败: {e}")
            ch.basic_nack(
                delivery_tag=method.delivery_tag,
                requeue=True
            )

    return wrapper
3. 队列持久化配置

声明持久化队列

channel.queue_declare(
queue='task_queue',
durable=True, # 队列持久化
arguments={
'x-max-priority': 10, # 支持优先级
'x-message-ttl': 86400000, # 消息TTL(24小时)
'x-dead-letter-exchange': 'dlx.exchange', # 死信交换器
'x-dead-letter-routing-key': 'dead.letter'
}
)

2.4.2 幂等性设计:防止消息重复消费

import redis
from functools import wraps

class IdempotentProcessor:
"""幂等性处理器 - 基于Redis实现"""

def __init__(self, redis_client):
    self.redis = redis_client

def process(self, message_id, handler, ttl=86400):
    """
    幂等处理
    message_id: 消息唯一标识
    handler: 实际业务处理函数
    ttl: 幂等记录过期时间(秒)
    """
    # 使用SET NX实现分布式锁 + 幂等检查
    key = f"msg:processed:{message_id}"

    # 原子操作:只有当key不存在时才设置
    if self.redis.setnx(key, "1"):
        # 第一次处理
        try:
            result = handler()
            self.redis.expire(key, ttl)  # 设置过期时间
            return result
        except Exception as e:
            # 处理失败,删除幂等标记,允许重试
            self.redis.delete(key)
            raise
    else:
        # 重复消息,直接返回
        logging.info(f"Duplicate message detected: {message_id}")
        return None

使用装饰器更优雅

def idempotent(message_id_extractor=lambda props, body: props.message_id):
"""幂等性装饰器"""
def decorator(func):
@wraps(func)
def wrapper(body, properties, args, *kwargs):
msg_id = message_id_extractor(properties, body)
processor = IdempotentProcessor(redis_client)

        def handler():
            return func(body, properties, *args, **kwargs)

        return processor.process(msg_id, handler)
    return wrapper
return decorator

使用示例

@idempotent(lambda props, body: f"{props.message_id}:{body.get('order_id')}")
def handle_order_message(body, properties):
"""处理订单消息"""

# 业务逻辑,只会执行一次
order_id = body['order_id']
# 更新订单状态...
return True
**2.5 监控与告警体系**
2.5.1 分层监控架构
构建消息中间件的监控体系,需要从三个层次进行观测:

第一层:基础设施层监控

CPU使用率与负载

内存消耗与交换情况

磁盘容量与I/O性能

网络吞吐量与连接状态

第二层:服务核心层监控
监控指标体系应包括:

RabbitMQ核心监控指标

metrics:

可用性指标

  • rabbitmq_cluster_health
  • rabbitmq_node_health
  • rabbitmq_running

    队列指标

  • rabbitmq_queue_messages_ready # 待消费消息数
  • rabbitmq_queue_messages_unacked # 未确认消息数
  • rabbitmq_queue_messages_total # 总消息数
  • rabbitmq_queue_consumers # 消费者数量

    连接指标

  • rabbitmq_connections_total
  • rabbitmq_channels_total

    性能指标

  • rabbitmq_message_deliver_rate
  • rabbitmq_message_publish_rate
  • rabbitmq_message_ack_rate

    资源指标

  • rabbitmq_memory_used_bytes
  • rabbitmq_disk_free_bytes
  • rabbitmq_fd_used
    ```
    第三层:应用与业务语义层监控

这一层旨在建立技术指标与业务价值的桥梁,需要:

在关键业务消息中嵌入追踪标识

监控端到端处理延迟是否满足SLA

跟踪核心业务主题的消息积压量

定义并计算与业务成果直接相关的衍生指标

2.5.2 Prometheus + Grafana 集成

# prometheus.yml - 采集配置
scrape_configs:
  - job_name: 'rabbitmq'
    static_configs:
      - targets: ['rabbitmq-exporter:9419']
    metrics_path: '/metrics'
    scrape_interval: 15s

    metric_relabel_configs:
      # 过滤无用标签,减少存储压力
      - source_labels: [__name__]
        regex: 'rabbitmq_(queue|node|connection).*'
        action: keep

# alerting_rules.yml - 告警规则
groups:
  - name: rabbitmq_alerts
    interval: 30s
    rules:
      - alert: RabbitMQHighMemoryUsage
        expr: rabbitmq_memory_used_bytes / rabbitmq_memory_limit_bytes > 0.9
        for: 5m
        labels:
          severity: critical
          component: rabbitmq
        annotations:
          summary: "RabbitMQ内存使用率过高"
          description: "节点 {
  { $labels.node }} 内存使用率 {
  { $value | humanizePercentage }}"

      - alert: RabbitMQHighDiskUsage
        expr: rabbitmq_disk_free_bytes < 1073741824  # <1GB
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "RabbitMQ磁盘空间不足"

      - alert: RabbitMQQueueBuilding
        expr: rabbitmq_queue_messages_ready > 10000
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "消息积压严重"
          description: "队列 {
  { $labels.queue }} 积压 {
  { $value }} 条消息"

      - alert: RabbitMQNoConsumers
        expr: rabbitmq_queue_messages_ready > 0 and rabbitmq_queue_consumers == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "队列没有消费者"

2.5.3 智能化告警策略
有效的告警策略需遵循以下原则:

精准性:每条告警明确描述异常实体、指标、当前值与阈值对比

分级处理:根据严重程度定义Critical/Warning/Info等级别

告警聚合:将同一时段、同一根因的告警合并

静默机制:为暂时性抖动设置合理的静默期
来源:
https://rvtst.cn/

相关文章
|
5天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
2549 8
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
13天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3432 12
|
15天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3507 25
|
9天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2629 5
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
7天前
|
人工智能 自然语言处理 供应链
|
7天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全+三种模式+记忆体系+实战工作流完整手册
Claude Code 是当前最流行的终端级 AI 编程助手,能够直接在命令行中完成代码生成、项目理解、文件修改、命令执行、错误修复等全流程开发工作。它不依赖图形界面、不占用额外资源,却能深度理解项目结构,自动生成规范代码,大幅提升研发效率。
1183 3
|
28天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23611 15
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」

热门文章

最新文章