李翔-大数据技术

Big data technology!

第11章 Spark的部署与使用

Spark的部署与使用


1.Spark基础

1.1 什么是 Spark?

1. 基本概念

  • 定义: Spark 是为大数据设计的分布式计算框架,能够在分布式环境中高效处理数据。与 Hadoop 集成: 可替代 MapReduce

  • 计算模型: 通过 RDD(内存中弹性分布式数据集)Spark 将数据分成多个分区,分布在集群节点上并行处理。

2. 什么是弹性?

  • 简单理解: 弹性是指系统在面对变化或问题时仍能维持高效运行的能力。在 Spark 中,即使计算过程中部分节点出错或任务失败,系统可以通过历史操作记录自动恢复并完成任务。

  • 在 RDD 中的弹性:即容错性: 如果在数据处理过程中某个分区的数据丢失,Spark 会根据 RDD 的血缘关系(操作历史记录),重新计算丢失的数据分区,而不需要重新运行整个任务。

3. RDD 的功能

  • RDD 会将大数据集划分成多个分区,每个分区分布到不同的计算节点上进行并行处理。这种方式可以充分利用集群的计算资源,大大加快数据处理速度。

4. 举例

例子:统计单词出现次数

你有一本包含大量文本的电子书文件,想统计每个单词的出现次数。

传统方法:

  1. 将文件逐行读入内存。

  2. 对每一行进行单词分割,逐一统计。

  3. 如果文件特别大,处理速度会很慢,甚至内存不够用。

使用 RDD 的方法:

  1. 将文件加载为 RDD:Spark 会将电子书文件分成多个分区,每个分区存储一部分数据。

  2. 转换操作:

    • 对每行文本进行单词分割(flatMap 操作)。

    • 为每个单词标记 1map 操作)。

    • 将相同单词的计数相加(reduceByKey 操作)。

  3. 行动操作:

    • 使用 collectsave 将结果保存或打印。

5. 数据处理特点

  • 数据拆分: Spark 会把大数据集分成多个分区,并在多个计算节点上并行处理这些分区数据。

  • 结果合并: 处理完每个分区的数据后,Spark 会把结果合并成一个完整的结果。

  • 存储交互: Spark 只在需要读取数据和保存最终结果时与存储系统交互,其他时间在内存中处理数据。

6. 核心优势

  • 速度: Spark 的处理速度比 Hadoop MapReduce 快很多,最多可达 100 倍。

  • 内存计算: Spark 大部分时间在内存中处理数据,减少了读写磁盘的时间,所以速度很快。

  • 批处理与流处理: Spark 不仅可以处理已经存储的数据,还能处理实时产生的数据。


总结

Spark 是一个高速、灵活且易于使用的大数据处理平台,能够处理各种类型的数据和任务。它是当今大数据领域的关键技术之一。

许多大公司已经在使用 Spark 作为大数据的计算框架,包括 eBay、Yahoo、BAT、网易、京东、华为等。同时,Spark 也得到了 IBM 和 Intel 等顶级 IT 厂商的支持。


1.2 Apache Spark其核心功能和组件

1. Spark 的核心部分 - Spark Core

  • Spark Core 是整个 Spark 平台的基础,Spark 的“心脏”。作用如下:

  • 任务调度:负责将数据处理任务分配到集群中的不同节点上

  • 内存管理:提供内存计算的支持,避免频繁读写磁盘,从而提升性能

  • 错误恢复:   通过血缘关系,Spark Core 能在任务失败时重新计算丢失的数据分区,确保计算任务的可靠性。

  • 分布式计算:Spark Core 支持将数据划分为多个分区,并在多个计算节点上并行处理。

  • 数据存取:支持从多种存储系统中读取数据,比如 HDFS、本地文件系统

2. Spark 的功能模块

在 Spark Core 之上,Spark 提供了几个重要的功能模块,每个模块都有特定的用途:

1)Spark SQL:

  • 功能: 使用 SQL 语言来查询和操作数据。

  • 作用: 使用 Spark SQL 处理大数据,就像在传统数据库中运行查询一样。

2)Spark Streaming:

  • 功能: 用于处理实时数据流。

  • 作用: 它可以处理像传感器数据、网站点击流等实时生成的数据,并进行实时分析。

3)MLlib (机器学习库):

  • 功能: 提供了常用的机器学习算法。

  • 作用: MLlib 可以实现大数据上进行机器学习,比如分类、回归、聚类等任务。

4)GraphX:  

  • 功能: 用于处理图形数据和图计算。[ɡræf ˈeks]

  • 作用: 适合分析复杂的网络关系,比如社交网络中的好友关系,交通网络中的路径优化等。

3. 集群管理器

Spark 可以在不同的集群环境中运行,集群管理器帮助 Spark 管理计算资源和任务调度:

  • 本地运行模式: Spark 可以在一台机器上运行,适合开发和测试。

  • 独立运行模式: Spark 可以独立组成一个集群,并自己管理资源和任务。

  • YARN模式: 这是 Hadoop 的资源管理器,Spark 可以与 Hadoop 集成,使用 YARN 来管理集群资源。

4. 数据存储层

  • 底层数据存储: Spark 可以从多种数据源读取和写入数据,比如 HDFS、HBase、Kafka、Hive、Mysql、csv/json、Nosql等数据类型。这些存储层为 Spark 提供了数据的存储和读取支持。

总结

通过这张图,你可以看到 Spark 是一个强大的大数据处理平台,它的核心部分是 Spark Core,上面集成了多种功能模块(如 SQL 查询、实时数据处理、机器学习、图计算等)。Spark 可以在多种集群环境中运行,并支持从多种数据存储系统中读取数据,这使得它非常灵活且易于使用。

这个图展示了 Spark 如何通过不同的功能模块和集群管理器,来处理和分析大规模数据的能力。无论是静态数据还是实时数据,Spark 都能轻松应对。


1.3 Spark基本工作原理

RDD 是 Spark 中的数据抽象模型。 Spark 会把一个大的 RDD 自动拆成多个分区,并分布到不同的节点上并行处理。 数据优先在内存中迭代计算,非常快速;如果某个节点出现故障,Spark 会根据血缘关系自动重算丢失的分区,不需要人工干预。所以 Spark 的特点就是:快、稳、强。



1.4 Spark 运行模式及集群角色

1.4.1 Spark运行模式

Spark 本身不负责资源管理,它只负责“计算”。 真正管理资源和调度任务的是 Spark集群管理器

Spark 可以运行在不同的集群环境中:


① 本地运行模式(Local)

  • 一台机器上运行 Spark

  • 不需要集群,无需额外安装

  • 适合 开发、调试、课堂实验

示例启动:

master = local[*]

特点:最简单,不能体现分布式


② 独立集群模式(Standalone)

  • Spark 自己组成一个小集群

  • 自己管理资源和任务调度

  • 不依赖其他框架

适合:

  • 教学实验

  • 小规模集群

特点:简单易用,但生产环境使用较少


③ YARN 模式(推荐)

  • 使用 Hadoop 的 YARN 来管理资源和调度任务

  • Spark 与 Hadoop 深度整合

  • 执行任务调度、资源分配、监控

特点:企业生产环境最常用


⭐ 选择建议(课堂重点)

模式优点适用场景
本地模式最简单,无需集群开发、测试、入门
独立模式Spark 自己就是集群小实验环境
YARN 模式与 Hadoop 深度集成,是主流企业生产、实训平台

结论

Spark 可以运行在本地、独立集群或 YARN 上。 本地模式用于开发调试,独立模式用于实验环境,而 YARN 模式是企业生产环境的主流选择。


2. 安装 Spark

2.1 软件准备

2.2 Spark的三种部署方式

(1)Local 模式

  • Spark 在 单机 上运行,所有组件(Driver、Executor)都在同一台机器上。

  • 适合 学习、开发、调试 和处理 小规模数据

(2)Standalone模式

  • 使用 Spark 自带的集群管理器部署的 独立集群模式,不依赖 Hadoop/YARN 等外部资源调度系统

  • Master节点:负责资源管理和任务调度。Worker节点(Slave):负责实际的任务执行。

(3)Yarn模式

  • Spark 部署在 Hadoop 集群上,由 YARN 负责资源管理与调度。

  • 常用于企业级生产环境,支持两种模式:

    • Client 模式:Driver 运行在提交任务的那台机器上。如果机器掉线,任务失败。

      Cluster 模式:Driver 运行在集群中某个节点上,由 YARN 负责管理。适合大规模生产作业。

Driver程序:它是Spark应用程序的“大脑”,负责管理和协调整个任务的执行。通常,Driver程序通常是用户编写的Spark应用程序的main方法所在的进程。

总结:

Spark 在 YARN 模式下的运行流程是:客户端提交 → YARN 分配资源 → 启动 App Master → 启动容器执行任务 → Node Manager 管理执行状态。

  • 其中,Resource Manager 负责“分资源”App Master 负责“调度任务”Node Manager 负责“执行与报告”

  • 每个任务(Task)都在 YARN 分配的 Container 中运行,实现资源隔离与任务并发执行


2.3 spark安装

2.3.1 搭建Standalone模式

2.3.2 搭建Spark on YARN模式

1. 导入情境

在 Hadoop 集群中,如果我们想运行 Spark 任务,是否还需要单独搭建 Spark 集群呢? 其实不必,Spark 可以直接连接到 YARN,由 YARN 负责资源管理和任务调度。

所以:

Spark 不需要在所有节点安装,只要 master 有 Spark,就能通过 YARN 来调度整个集群执行任务。

YARN 负责:

  • 分配资源

  • 启动 Executor

  • 监控任务

Spark 负责:

  • 执行计算

  • 生成 RDD/DataFrame 结果


2. 知识讲解

Spark on YARN 的本质总结

👉 Spark on YARN = Spark 做计算,YARN 管资源和调度

具体来说:

✔️ 资源与节点管理

  • ResourceManager:负责整个集群资源调度、任务分配

  • NodeManager:负责运行任务的节点管理(启动/监控容器)

✔️ Spark 运行组件放进Yarn启动的容器

  • Driver:负责整个任务的“指挥调度”

    • 客户端机器(Client 模式)

    • YARN 容器内部(Cluster 模式)

    • 负责:划分任务、管理执行、收集结果

    • 在 YARN 模式下,Driver 可以运行在:

  • Executor:负责具体计算任务

    • 由 YARN 启动多个容器

    • 接受 Driver 的指令执行计算

    • 一个应用通常有多个 Executor 并行工作


总结

Spark 只负责算(Driver+Executor), YARN 负责管(ResourceManager+NodeManager)



Spark on YARN 安装和配置

1. 环境准备
  • Hadoop 3.x 完全分布式

  • YARN 正常运行

  • HDFS 正常运行

  • 节点:master + slave1 + slave2

  • 下载 Spark 3.1.1-bin-hadoop3.2.tgz 安装包。

spark-3.1.1-bin-hadoop3.2 为 Spark 3.1.1 的预编译二进制版本,内置了与 Hadoop 3.2 兼容的依赖库,可直接连接 Hadoop 3.1.3 集群,无需额外添加 Hadoop JAR 包。


2. 安装Spark

Spark on YARN 模式下,只需在 Hadoop 集群的一个节点(如 master)部署 Spark 作为客户端即可,不需要在所有节点安装 Spark。

# 在 master 节点操作
cd /opt/software/
tar -zxvf spark-3.1.1-bin-hadoop3.2.tgz -C /opt/apps/

# 重命名
cd /opt/apps
mv spark-3.1.1-bin-hadoop3.2 spark


3. 配置spark环境变量
# 编辑 /etc/profile

# 在末尾添加以下内容
# spark 安装路径
export SPARK_HOME=/opt/apps/spark
export PATH=$PATH:$SPARK_HOME/bin

保存并退出,使环境变量生效:

source /etc/profile

查看PATH环境变量

echo $PATH


4. 配置spark-env.sh

目的:让 Spark 找到 Hadoop 和 YARN

进入 Spark 配置目录并创建配置文件:

cd /opt/apps/spark/conf/
# 复制并重命名
cp spark-env.sh.template spark-env.sh
# 双击编辑 spark-env.sh

配置以下内容

# JDK 安装路径
export JAVA_HOME=/opt/apps/jdk

# 设置 Hadoop 配置文件目录
# 作用:让 Spark 能找到 Hadoop 的核心配置(HDFS、YARN 等)
export HADOOP_CONF_DIR=/opt/apps/hadoop/etc/hadoop

# 设置 YARN 配置文件目录的环境变量
# 作用:让 Spark 能找到 Hadoop/YARN 的配置文件(如 yarn-site.xml)
export YARN_CONF_DIR=/opt/hadoop/etc/hadoop

注意:在 YARN 模式下,资源与调度由 YARN 负责,原先在Standalone模式配置参数可删除或注释掉:

  • SPARK_MASTER_HOSTSPARK_MASTER_PORT(Standalone 模式 Master 通信参数)

  • SPARK_WORKER_CORESSPARK_WORKER_MEMORY(Standalone 模式 Worker 资源限制)

  • SPARK_MASTER_WEBUI_PORT(Standalone 模式 Master Web UI 端口)


5. 配置 Spark 的运行模式(YARN)

Master主机上修改yarn-site.xml文件

# 在master节点上操作
cd /opt/apps/hadoop/etc/hadoop/
# 编辑
vi yarn-site.xml

添加以下内容(禁用资源检查,防止 YARN 杀掉超内存的 Spark 容器)

    <!-- 禁用 NodeManager 的物理内存检查(pmem) -->
   <!-- 如果容器使用的物理内存超过分配值,默认会被杀掉 -->
   <property>
       <name>yarn.nodemanager.pmem-check-enabled</name>
       <value>false</value>
   </property>

   <!-- 禁用 NodeManager 的虚拟内存检查(vmem) -->
   <!-- 如果容器使用的虚拟内存超过分配值,默认会被杀掉 -->
   <property>
       <name>yarn.nodemanager.vmem-check-enabled</name>
       <value>false</value>
   </property>

如图:

image-20250805115040942


6.分发 yarn-site.xml

master分发 yarn-site.xmlslave1/slave2

scp /opt/apps/hadoop/etc/hadoop/yarn-site.xml slave1:/opt/apps/hadoop/etc/hadoop

scp /opt/apps/hadoop/etc/hadoop/yarn-site.xml slave2:/opt/apps/hadoop/etc/hadoop

到此,Spark on yarn安装完毕


7. Spark on YARN模式的提交任务的两种方式

一、核心概念

Spark 在 YARN 下提交任务有两种模式:

模式Driver 在哪?通俗理解
Client 模式执行 spark-submit 的电脑大脑在自己电脑上
Cluster 模式YARN 集群中的一个节点大脑搬进集群里

Driver = 大脑 负责调度任务、收集结果。

📌 总结:两种模式唯一的区别就是 Driver 放在哪


二. 工作原理与流程

1)Client 模式

  • Driver 位置:Driver 运行在 提交任务的计算机(即运行 spark-submit 命令的机器)上。

  • 适用场景:适合开发、调试和小规模的数据分析任务。


2)Cluster 模式

  • Driver 位置:Driver 运行在 YARN 集群中的容器内,而不是提交任务的机器上。

  • 适用场景:适合生产环境、大规模数据处理和批量作业。


Client模式 vs Cluster模式的核心区别

本质区别:Driver程序运行的位置不同。Client 模式适合开发,Cluster 模式适合生产。

对比项Client 模式Cluster 模式
Driver 位置提交任务的电脑集群中的容器
是否依赖客户端✔ 是❌ 否
日志查看方式本地终端实时输出到 YARN/Spark UI 查
适用场景开发调试生产环境
稳定性


3. 实验

  • 启动Hadoop集群

# 在master启动
start-dfs.sh
# 在slave1启动
start-yarn.sh


实验1: 官方示例程序 SparkPi

实验任务:运行的是 Spark 的官方示例程序 SparkPi ,用来计算圆周率 π

client模式运行

实验目的

  1. 掌握 spark-submit 提交任务的基本用法。

  2. 理解 client 模式下 Driver 程序运行位置及输出方式。

  3. 熟悉 Spark 官方示例程序的运行流程与结果查看方法。

模式特点

  1. Driver 运行在客户端的 spark-submit 进程中。

  2. 应用程序运行结果会直接显示在客户端终端。

实验步骤

# 在master节点运行,通过 spark-submit 提交一个任务到 Spark on YARN 集群中运行
# 运行的是 Spark 的官方示例程序 SparkPi ,用来计算圆周率 π。
spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode client \
/opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar \
10

# 或者简化命令
spark-submit --master yarn \
--class org.apache.spark.examples.SparkPi \
$SPARK_HOME/examples/jars/spark-examples_2.12-3.1.1.jar

解释

  • spark-submit:  Spark 提供的命令行工具,用于提交 Spark 应用程序到集群中运行。

  • --class 指定了应用程序的主类。

  • --master 指定了集群管理器为yarn,表示任务会运行在一个已有的 Hadoop YARN 集群中。

  • --deploy-mode 指定 Driver 程序运行的位置。client模式Spark驱动程序将在提交应用程序的机器上运行,                                                             通常是用户的本地机器。

  • 如果未指定 --deploy-mode,Spark 默认为 client 模式

  • JAR 包是 Spark 官方提供的 spark-examples 包,内含多个示例程序(如 SparkPi)。

  • 10:让 Spark 同时跑 10 个计算任务来估圆周率,最后把结果求平均,就得到一个更接近真实值的π,任务越多,结果越准确。

image-20230115220933329


Spark 运行时日志很多,如果只想看计算结果,可以用 grep 过滤关键信息。

# 在执行时会输出非常多的运行信息,输出结果不容易找到,可以通过 grep 命令进行过滤
spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode client \
/opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar \
10 \
2>&1 | grep "Pi is"

解释:

2>&1

  • 1 → 标准输出(正常信息)

  • 2 → 标准错误(警告、错误)

  • 2>&1 → 把标准错误合并到标准输出中,这样可以一起处理。

|(管道符)

  • 把前面命令的输出,传给后面的命令作为输入。

grep "Pi is"

  • 从输出中只保留包含 "Pi is" 的行(SparkPi 程序会打印结果类似 Pi is roughly 3.1415926)。


减少 Spark 日志输出的方法(修改日志级别)

# 进入 Spark 配置目录
cd $SPARK_HOME/conf

# 如果 log4j.properties 文件不存在,先复制模板文件
cp log4j.properties.template log4j.properties

# 编辑配置文件
vi log4j.properties

# 修改下面的内容,把INFO替换为ERROR
log4j.rootCategory=ERROR, console
......

注意:如果在 Cluster 模式下运行,日志过少可能导致看不到任务 ID,不便于跟踪任务状态,所以不建议生产环境直接改成 ERROR


cluster模式运行

实验目的

  1. 掌握 spark-submitcluster 模式下的提交方法。

  2. 理解 cluster 模式下 Driver 程序运行的位置和特点。

  3. 学会通过 YARN Web UI 或日志文件查看任务的运行结果。

模式特点

  1. Driver 程序运行在 YARN 集群的容器中,由 YARN 管理,客户端机器只负责提交任务,不直接参与执行。

  2. 应用程序结果不会直接显示在客户端,只能在:

    • YARN Web UI 查看执行情况与结果

    • 任务日志文件 中查看运行详情

# 方法一:基础版命令
spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \
/opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar \
10

说明

  • --class → 指定 SparkPi 主类(官方示例类)

  • --master yarn → 指定使用 YARN 资源管理

  • --deploy-mode cluster → Driver 在集群运行

  • 10 → SparkPi 的并行度


# 方法二:资源指定版命令
spark-submit \
 --class org.apache.spark.examples.SparkPi \
 --master yarn \
 --deploy-mode cluster \
 --num-executors 3 \
 --executor-memory 4g \
 --executor-cores 2 \
 --driver-memory 2g \
 /opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar

说明

  • --num-executors → Executor 数量(3 个)

  • --executor-memory → 每个 Executor 分配 4 GB 内存

  • --executor-cores → 每个 Executor 使用 2 个 CPU 核心

  • --driver-memory → Driver 分配 2 GB 内存


查看运行结果

image-20230115225707114


http: //slave1:8088/proxy/application_1673791169680_0003/

  • http://slave1:8088: 这是 YARN ResourceManager 的 Web UI 地址,提供对 YARN 集群的监控和管理功能。Spark 作业作为 YARN 应用的一部分,运行在 YARN 集群上,因此所有提交到 YARN 的 Spark 任务都会在这个页面中显示。

  • /proxy/application_1673791169680_0003/: 这个链接指向的是该 Spark 应用程序的详细页面,用户可以通过这个链接查看 Spark 任务的执行状态、日志、资源使用等信息


image-20230115225415792


image-20230115225454617

image-20241129143409110

image-20230115225604391


实验2: 官方示例 JavaWordCount 应用程序

实验任务:通过 Spark 提交官方示例 JavaWordCount 应用程序,统计 HDFS 文件中每个单词的出现次数。

实验目的

  1. 掌握使用 spark-submit 提交 Spark 应用程序到 YARN 集群的方法。

  2. 学会运行 Spark 官方示例 JavaWordCount 程序,对 HDFS 文件进行单词统计。

  3. 理解 Spark 在分布式环境下的数据读取分词处理结果输出流程。

  4. 提升对 Spark 应用程序执行过程的整体认识,为后续编写自定义数据分析程序打下基础。

实验步骤

1. 准备输入文件

在 HDFS 上创建输入文件:

# 在 HDFS 上创建目录 /spark/wordcount(如果不存在则自动创建)
hdfs dfs -mkdir -p /spark/wordcount

# 在本地创建一个名为 input.txt 的文本文件,包含三行示例数据
# -e 选项:支持转义字符(\n 表示换行)
echo -e "Spark is fast\nSpark is great\nHadoop and Spark" > input.txt

# 将本地的 input.txt 上传到 HDFS 的 /spark/wordcount 目录
hdfs dfs -put input.txt /spark/wordcount

input.txt文件内容:

Spark is fast
Spark is great
Hadoop and Spark

2. 使用 client 模式提交

实验任务:在 master 节点使用 spark-submit 提交 JavaWordCount 程序(client 模式),从 HDFS 路径 hdfs://master:9000/spark/wordcount 读取数据,在 YARN 集群中统计每个单词出现次数,Driver 在客户端运行,Executor 在集群执行。

master 节点 上运行以下命令:

# 在master节点上运行以下命令:
spark-submit \
--class org.apache.spark.examples.JavaWordCount \
--master yarn \
--deploy-mode client \
/opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar \
hdfs://master:9000/spark/wordcount

参数说明:

  • spark-submit : 使用 spark-submit 提交一个 Spark 应用程序到集群

  • --class org.apache.spark.examples.JavaWordCount : 指定 Spark 应用程序的主类,即包含 main 方法的类,这里是 JavaWordCount 示例程序

  • --master yarn : 指定集群管理模式,这里使用 YARN 集群管理器

  • --deploy-mode client : 指定应用程序的部署模式,client 模式表示驱动程序在客户端机器上运行

  • /opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar : 指定包含 Spark 示例程序的 JAR 文件路径

  • hdfs://master:9000/spark/wordcount : 指定输入数据的路径,这里是 HDFS 中的路径


运行结果:

image-20241130115607793


3. 使用 cluster 模式提交

# 在master节点上运行以下命令:
spark-submit \
--class org.apache.spark.examples.JavaWordCount \
--master yarn \
--deploy-mode cluster \
/opt/apps/spark/examples/jars/spark-examples_2.12-3.1.1.jar \
hdfs://master:9000/spark/wordcount

参数说明:

  • --deploy-mode cluster:Driver 程序运行在 YARN 集群内部的容器中,客户端不参与任务执行。


Cluster 模式查看结果

查看任务日志: 在 cluster 模式下,结果不会直接输出到客户端终端。需要通过 YARN 日志查看:

image-20241130120441454

image-20250805125123077

image-20241130120539794



两种模式对比

模式Driver 位置适用场景优点查看结果方式
Client 模式Driver 运行在客户端上开发、调试任务实时查看日志和结果,适合调试小规模任务直接在提交终端查看输出
Cluster 模式Driver 运行在 YARN 容器内生产环境、长期运行任务任务独立于客户端,更高容错性通过 YARN WebUI查看结果



发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3

版权:李翔
备案/许可证编号为:新ICP备2024006115号-1