您的位置:首页 > 运维架构 > 网站架构

Hadoop2.6.0学习笔记(三)HDFS架构

2015-11-25 21:18 851 查看
鲁春利的工作笔记,谁说程序员不能有文艺范?
HDFS Architecture见:
http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html
或下载的tar包解压后的
hadoop-2.6.0/share/doc/hadoop/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html

Hadoop分布式文件系统(Hadoop Distributed File System,简称HDFS)是一个分布式的文件系统,运行在廉价的硬件上。HDFS是高容错的,被设计成在低成本硬件上部署,为应用数据提供高吞吐量的访问,适用于具有大规模数据集的应用程序。

说明:分布式应用中数据是分散在不同的机器上的,而通过分布式的文件系统,提供了统一的数据访问方式,屏蔽了底层数据存储位置的差异。

HDFS的设想和目标
1、硬件故障
在集中式环境下,总是假定机器是能够稳定持续运行的;而分布式环境恰恰相反,它认为硬件错误是常态,而非异常情况。HDFS有成百上千的计算机节点组成,每个节点存储部分数据。大量的节点中,任意节点都有可能由于故障而无法提供服务,因此故障检测,快速、自动的故障恢复是HDFS设计的核心架构目标。

2、流式数据访问
运行于HDFS之上的应用程序需要以流式方式来进行数据集的读取。HDFS不是为了通用的目的而设计的,它主要被设计用来实现批量数据处理,而非交互式的数据运算;高吞吐量的数据处理,而非低延迟的数据计算。

3、大数据集
HDFS以支持大数据集合为目标,一个存储在上面的典型文件大小一般都在GB至TB,一个单一HDFS实例应该能支撑数以千万计的文件。

4、一致性模型
HDFS应用对文件要求的是write-one-read-many访问模型。一个文件经过创建、写,关闭之后就不需要改变。这一假设简化了数据一致性问题,使高吞吐量的数据访问成为可能。

5、由移动数据到移动计算的转移
将计算移动到数据附近,比之将数据移动到应用所在显然更好,HDFS提供给应用这样的接口。

6、跨异构硬件和软件平台的可移植性
HDFS被设计成可轻易从一个平台移动到另一个平台。

HDFS Architecture
HDFS采用主/从(master/slave)结构,一个HDFS集群由一个NameNode(简称NN)节点和一定数量的DataNode(简称DN)节点组成。
NN是HDFS集群的master server,是整个HDFS集群的核心,它管理HDFS集群的名称空间,并接收客户端的请求(具体请求还是由DN处理)。DN一般情况下每台slave机器会配置一个,管理slave机器上存储的数据。
当用户上报数据时,数据以数据块(Block)的形式存储在数据节点上,一个文件可能被分割为一个或者多个数据块。
NN执行文件系统的namespace操作,例如打开、关闭、重命名文件和目录,同时维护了block到DN的映射关系。DN在NN的指挥下进行block的创建、删除和复制,以及根据NN维护的block和DN的映射关系处理client的数据读写请求。



说明:
上述为单NN方式,NN存储的是元数据信息,一旦出故障,那么整个HDFS集群就挂了。
部署时一个主机可以同时配置NN和DN,也可以配置多个DN,但很少有人那么干。
数据块是有副本的,默认为3,存储为本机、同一机架内机器、其他机架内机器(机架感知)。
Client端的读写请求都要先和NN打招呼,然后再通过DN真正干活。

HDFS Namespace
HDFS支持传统的层次型文件组织,与大多数其他文件系统类似,用户可以创建目录,并在其间创建、删除、移动和重命名文件。HDFS不支持user quotas和访问权限,也不支持链接(link),不过当前的架构并不排除实现这些特性。Namenode维护文件系统的namespace,任何对文件系统namespace和文件属性的修改都将被Namenode记录下来。应用可以设置HDFS保存的文件的副本数目,文件副本的数目称为文件的 replication因子,这个信息也是由Namenode保存。
说明:
可以通过hdfs dfsadmin -setQuota可以对目录进行限额。
hdfs dfs -setrep可以动态调整副本数目。
hdfs上任何的操作都会记录在edits日志文件中,由参数dfs.namenode.edits.dir指定存放路径。

HDFS Data Replication
HDFS被设计成在一个大集群中可以跨机器地可靠地存储海量的文件。它将每个文件存储成block序列,除了最后一个block,所有的block都是同样的大小。文件的所有block为了容错都会被复制。每个文件的block大小和replication因子都是可配置的。Replication因子可以在文件创建的时候配置,以后也可以改变。
HDFS中的文件是write-one,并且严格要求在任何时候只有一个writer。Namenode全权管理block的复制,它周期性地从集群中的每个Datanode接收心跳包和一个Blockreport。心跳包的接收表示该Datanode节点正常工作,而Blockreport包括了该Datanode上所有的block组成的列表。



1、副本存放
默认情况下,replication因子是3,HDFS的存放策略是第一个副本存放在client连接到的DN节点,一个副本放在同一机架上的另一个节点,最后一个副本放在不同机架上的一个节点。
说明:
HDFS的机架感知不是自适应的,需要管理人员进行配置。
2、副本选择
为了降低整体的带宽消耗和读延时,HDFS会尽量让reader读最近的副本。
3、安全模式
Namenode启动时会进入一个称为Safemode的特殊状态,处在这个状态的Namenode是不会进行数据块的复制的。
Namenode从所有的Datanode接收心跳包和Blockreport。Blockreport包括了某个Datanode所有的数据块列表。
每个block都有指定的最小数目的副本(dfs.namenode.replication.min),当Namenode确认了某个数据块副本的最小数目,那么该block被认为是安全的。
如果一定百分比(dfs.namenode.safemode.threshold-pct)的数据块检测确认是安全的,那么Namenode将退出Safemode状态,接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些block复制到其他Datanode。

文件系统元数据的持久化
NN存储HDFS Namespace的元数据,任何对文件元数据的修改操作,NN都使用一个称为Editlog的事务日志记录下来。例如,在HDFS中创建一个文件,NN会在Editlog中插入一条记录来表示;同样,修改文件的replication因子也将往Editlog中插入一条记录。NN在本地OS的文件系统上存储Editlog文件,整个文件系统的namespace,包括block到文件的映射、文件的属性,都存储在称为FsImage的文件中,这个文件也是存放在NN所在的文件系统上。
NN在内存中保存者整个文件系统namespace和文件Blockmap的映射,一个4G内存的NN足够支持海量的文件和目录。当NN启动时,它从硬盘读取Editlog和FsImage,讲所有Editlog中的事务作用于FsImage文件,并将新版本的FsImage从内存中flush到硬盘上,然后再truncate这旧的Editlog,因为这个旧的Editlog已经被作用到FsImage上了,该过程称为checkpoint。
DN讲文件保存在本地的文件系统上,但是它并知道关于文件的任何信息。DN不会在一个目录中存放所有文件,相反,它用启发式的方法来确定每个目录中的最佳文件数目,并且在适当的时候创建子目录。当一个DN启动时,它扫描本地文件系统,对这些本地文件产生相应的一个所有HDFS数据块的列表,然后发送报告到DN,这个报告就是BlockReport。

通信协议
所有的HDFS通信协议都是构建于TCP/IP协议之上。客户端通过一个可配置的端口与NN通信,通过ClientProtocol与NN通信;而DN使用DatanodeProtocol与NN通信。ClientProtocol与DatanodeProtocol协议都是基于RPC协议进行的封装。在HDFS的设计中,NN不会主动发起RPC,而只是被动响应DN和Client端的请求。

健壮性
HDFS的主要目标就是实现在失败情况下数据存储可靠性,常见的三种失败为:NN failure、DN failure和网络分割(network partition)。
(1)硬盘数据错误、心跳检测和重新复制
DN定期向NN发送心跳信息,但是网络切割可能导致部分DN失去与NN的连接。NN通过心跳包的缺失检测到这一情况,将这些DN标记为dead,不会再将新的IO请求发给它们。HDFS将无法再访问处于dead状态的DN上存储的数据,因此一些block的副本数将低于配置的阀值。NN不断跟踪需要复制的数据块,并在任何需要的时候启动复制。在下述情况下可能触发重新复制:DN失效、某个block损坏、DN节点磁盘错误或者副本因子增加。

(2)集群均衡
HDFS集群的自动均衡计划,即当DN节点的磁盘空间不足时自动将数据移动到其他节点,或者当某个文件的请求数突然增加时, 复制数据到集群中的其他节点已满足应用需求,但该机制暂未实现。

(3)数据完整性
由于客户端访问时,由于存储设备故障、网络故障或者软件BUG,都有可能导致数据块损坏,HDFS实现了数据内容校验和,当读取数据时会自动检验数据块的完整性,若存在问题,会尝试从其他DN读取数据。

(4)元数据磁盘错误
FsImage和Editlog是HDFS的核心数据结构,它们的损坏将导致整个HDFS集群不可使用。因此,NN可以配置为FsImage和Editlog存储多个副本(dfs.namenode.name.dir配置以逗号分割的多个路径),所有的操作都会对多个副本同步更新。

说明:
NN在HDFS集群中存在单独故障(SPOF)问题。当NN节点失败时,如果没有配置HA则必须进行人工处理,或者讲NN配置为HA模式。

(5)快照
HDFS does not currently support snapshots but will in a future release.

NameNode NN节点数据在本地存储的位置由hdfs-site.xml文件中参数${dfs.namenode.name.dir}指定。
<property>
<name>dfs.namenode.name.dir</name>
<value>/usr/local/hadoop2.6.0/data/dfs/name</value>
</property>
查看${dfs.namenode.name.dir}目录:
[hadoop@nnode name]$ pwd
/usr/local/hadoop2.6.0/data/dfs/name
[hadoop@nnode name]$ ls
current
[hadoop@nnode name]$
在第一次部署好Hadoop集群之后,需要在NN节点上格式化磁盘

$HADOOP_HOME/bin/hdfs namenode
-format

格式化完成后会在${dfs.namenode.name.dir}/current目录下生成如下目录结构:
current目录下有四类文件:
事务日志记录文件(edits);
文件系统映像(fsimage);
当前文件系统映像应用过的事务号(seen_txid);
VERSION文件。
[hadoop@nnode current]$ ll -h
-rw-rw-r-- 1 hadoop hadoop   42 Nov 21 17:21 edits_0000000000000035252-0000000000000035253
-rw-rw-r-- 1 hadoop hadoop   42 Nov 21 17:23 edits_0000000000000035254-0000000000000035255
-rw-rw-r-- 1 hadoop hadoop   42 Nov 21 17:25 edits_0000000000000035256-0000000000000035257
-rw-rw-r-- 1 hadoop hadoop   42 Nov 21 17:27 edits_0000000000000035258-0000000000000035259
-rw-rw-r-- 1 hadoop hadoop   42 Nov 21 17:28 edits_0000000000000035260-0000000000000035261
-rw-rw-r-- 1 hadoop hadoop 231K Nov 21 22:29 fsimage_0000000000000035842
-rw-rw-r-- 1 hadoop hadoop   62 Nov 21 22:29 fsimage_0000000000000035842.md5
-rw-rw-r-- 1 hadoop hadoop 231K Nov 21 23:29 fsimage_0000000000000035930
-rw-rw-r-- 1 hadoop hadoop   62 Nov 21 23:29 fsimage_0000000000000035930.md5
-rw-rw-r-- 1 hadoop hadoop    6 Nov 21 17:27 seen_txid
-rw-rw-r-- 1 hadoop hadoop  204 Nov 21 23:29 VERSION
VERSION文件是属性文件:
[hadoop@nnode current]$ cat VERSION
#Sat Nov 21 23:29:03 CST 2015
# 文件系统唯一标识,首次format时设置,DN注册到NN之前是不知道该值的,可以区分新建的DN
namespaceID=339614018
# Cluster标识,DN与这里的需要一致
clusterID=CID-61347f43-0510-4b07-ad99-956472c0e49f
# NN存储的创建时间,当NN升级后,该值会更新
cTime=0
# 存储类型(DATA_NOME/NAME_NODE)
storageType=NAME_NODE
# block pool标识,后续再介绍(192.168.1.117是原来配置的IP地址,后台改成192.168.137.117了)
blockpoolID=BP-892593412-192.168.1.117-1431598212853
# 用一个负整数来表示HDFS永久数据结构的版本号
layoutVersion=-60
[hadoop@nnode current]$
seen_txid是记录事务ID的文件,format之后是0,表示NN里面edit-*文件的尾数,事务最后一次被应用到fsimage的id。
-rw-rw-r-- 1 hadoop hadoop      42 Nov 21 17:27 edits_0000000000000035258-0000000000000035259
-rw-rw-r-- 1 hadoop hadoop      42 Nov 21 17:28 edits_0000000000000035260-0000000000000035261
-rw-rw-r-- 1 hadoop hadoop  236143 Nov 21 22:29 fsimage_0000000000000035842
-rw-rw-r-- 1 hadoop hadoop      62 Nov 21 22:29 fsimage_0000000000000035842.md5
-rw-rw-r-- 1 hadoop hadoop  236027 Nov 21 23:29 fsimage_0000000000000035930
-rw-rw-r-- 1 hadoop hadoop      62 Nov 21 23:29 fsimage_0000000000000035930.md5
-rw-rw-r-- 1 hadoop hadoop       6 Nov 21 17:27 seen_txid
-rw-rw-r-- 1 hadoop hadoop     204 Nov 21 23:29 VERSION
[hadoop@nnode current]$ cat seen_txid
35260
[hadoop@nnode current]$
edits文件为NN保存的事务日志文件,存储位置由${dfs.namenode.edits.dir}指定,默认取NN节点数据文件位置${dfs.namenode.name.dir}。
fsimage文件存储的是NN节点的元数据文件。
说明:

当namenode -format命令执行的时候,在namenode节点和datanode节点的VERSION中都会产生一个namespaceID值,并且这两个值必须相同。如果再次执行格式化,那么namenode会产生一个新的namespaceID,但是datanode不会产生新的值。

示例一:查看edits文件
bin/hdfs oev -i edits_0000000000000000057-0000000000000000186   -o edits.xml
示例二:查看fsimage文件

bin/hdfs oiv -p XML -i fsimage_0000000000000000055  -o fsimage.xml

DataNode DN节点数据的存储位置也是通过hdfs-site.xml文件进行配置:
<property>
<name>dfs.datanode.data.dir</name>
<value>/usr/local/hadoop2.6.0/data/dfs/data</value>
</property>
DN节点数据存储结构:
/usr/local/hadoop2.6.0/data/dfs/data
|---current
|------BP-892593412-192.168.1.117-1431598212853
|-------current
|---------------dfsUsed
|-------------------168801504 1448121566578
|---------------finalized
|-------------------subdir0
|-----------------------subdir0  subdir1  subdir10  subdir11  subdir2  ......  subdir9(目录)
|-------------------------  -rw-rw-r-- 1 hadoop hadoop 1377 Nov 21 16:53 blk_1073744377
|-------------------------  -rw-rw-r-- 1 hadoop hadoop   19 Nov 21 16:53 blk_1073744377_3560.meta
|-------------------------  -rw-rw-r-- 1 hadoop hadoop 1438 Nov 21 16:53 blk_1073744378
|-------------------------  -rw-rw-r-- 1 hadoop hadoop   19 Nov 21 16:53 blk_1073744378_3561.meta
|-------------------------  -rw-rw-r-- 1 hadoop hadoop 1671 Nov 21 16:53 blk_1073744379
|-------------------------  -rw-rw-r-- 1 hadoop hadoop   23 Nov 21 16:53 blk_1073744379_3562.meta
|---------------rbw(空目录)
|---------------VERSION
|-------------------#Sat Nov 28 12:03:36 CST 2015
|-------------------namespaceID=339614018
|-------------------cTime=0
|-------------------blockpoolID=BP-892593412-192.168.1.117-1431598212853
|-------------------layoutVersion=-56
|-----------dncp_block_verification.log.curr
|-----------dncp_block_verification.log.prev
|-----------tmp(空目录)----------------
|-------VERSION
|-----------#Sat Nov 28 12:03:36 CST 2015
|-----------storageID=DS-e1bf6500-fc2f-4e73-bfe7-5712c9818965
|-----------clusterID=CID-61347f43-0510-4b07-ad99-956472c0e49f
|-----------cTime=0
|-----------datanodeUuid=33c2f4cb-cd26-4530-9d9b-40d0b748f8b8
|-----------storageType=DATA_NODE
|-----------layoutVersion=-56
|---in_use.lock
|-------14187(对应的DataNode进程的进程号,可通过ps -ef|grep DataNode查看)


通过hdfs命令上传一个文件到hdfs:
[hadoop@dnode1 subdir0]$ ll -h ~/httpdomainscan_192.168.1.101_0_20130913160407.hsl
-rwxrwxr-x 1 hadoop hadoop 180M Nov 28 12:06 /home/hadoop/httpdomainscan_192.168.1.101_0_20130913160407.hsl


在DN节点目录current/finalized/subdir0/subdir14下能看到新创建了两个bock块:
-rw-rw-r-- 1 hadoop hadoop 128M Nov 28 12:12 blk_1073745442
-rw-rw-r-- 1 hadoop hadoop 1.1M Nov 28 12:12 blk_1073745442_4628.meta
-rw-rw-r-- 1 hadoop hadoop  52M Nov 28 12:12 blk_1073745443
-rw-rw-r-- 1 hadoop hadoop 411K Nov 28 12:12 blk_1073745443_4629.meta
说明:
HDFS中block块的大小固定为128M,但是当一个数据文件的大小不足一个块大小时,按实际大小分配空间。
我的HDFS集群有两个DN节点,副本的参数配置的为2,因此在主机dnode1和dnode2的subdir14目录下都新创建了两个节点。

NN节点edits文件
# 此时多了一个edits_inprogress_0000000000000036000的文件
-rw-rw-r-- 1 hadoop hadoop   42 Nov 21 17:28 edits_0000000000000035260-0000000000000035261
-rw-rw-r-- 1 hadoop hadoop 1.0M Nov 28 13:31 edits_inprogress_0000000000000036000
-rw-rw-r-- 1 hadoop hadoop 231K Nov 21 22:29 fsimage_0000000000000035842
-rw-rw-r-- 1 hadoop hadoop   62 Nov 21 22:29 fsimage_0000000000000035842.md5
-rw-rw-r-- 1 hadoop hadoop 231K Nov 21 23:29 fsimage_0000000000000035930
-rw-rw-r-- 1 hadoop hadoop   62 Nov 21 23:29 fsimage_0000000000000035930.md5
-rw-rw-r-- 1 hadoop hadoop    6 Nov 21 17:27 seen_txid
-rw-rw-r-- 1 hadoop hadoop  204 Nov 21 23:29 VERSION
再次查看:
# 多了两个事务日志,且seen_txid也更新了(36002)
-rw-rw-r-- 1 hadoop hadoop      42 Nov 21 17:28 edits_0000000000000035260-0000000000000035261
-rw-rw-r-- 1 hadoop hadoop      42 Nov 28 13:55 edits_0000000000000036000-0000000000000036001
-rw-rw-r-- 1 hadoop hadoop      42 Nov 28 13:56 edits_0000000000000036002-0000000000000036003
-rw-rw-r-- 1 hadoop hadoop  236143 Nov 21 22:29 fsimage_0000000000000035842
-rw-rw-r-- 1 hadoop hadoop      62 Nov 21 22:29 fsimage_0000000000000035842.md5
-rw-rw-r-- 1 hadoop hadoop  236027 Nov 21 23:29 fsimage_0000000000000035930
-rw-rw-r-- 1 hadoop hadoop      62 Nov 21 23:29 fsimage_0000000000000035930.md5
-rw-rw-r-- 1 hadoop hadoop       6 Nov 28 13:55 seen_txid
-rw-rw-r-- 1 hadoop hadoop     204 Nov 21 23:29 VERSION


查看DN节点元数据信息:
hdfs oiv -p XML -i fsimage_0000000000000035842 -o fsimage.xml
下载到本地并打开:



到DN节点查找ID为1073741829的数据块文件:
# cd current/finalized/subdir0
[hadoop@dnode1 subdir0]$ find . -name "*1073741829*.meta"
./subdir0/blk_1073741829_1008.meta

[hadoop@dnode1 subdir0]$ cd subdir0
[hadoop@dnode1 subdir0]$ ll|grep 1073741829
-rw-rw-r-- 1 hadoop hadoop       63 May 27  2015 blk_1073741829
-rw-rw-r-- 1 hadoop hadoop       11 May 27  2015 blk_1073741829_1008.meta
[hadoop@dnode1 subdir0]$ cat blk_1073741829
hello world!
lucl123456\r\nceshi\r\n123456\r\n
ceshi
123456

[hadoop@dnode1 subdir0]$ hdfs dfs -cat lucl.txt
hello world!
lucl123456\r\nceshi\r\n123456\r\n
ceshi
123456
[hadoop@dnode1 subdir0]$

备注:上传了一个hsl文件,但是从edits中未看到日志记录,另外就是fsimage一直修改时间一直不变。
间隔一段时间后再查看current目录:

-rw-rw-r-- 1 hadoop hadoop      42 Nov 28 19:38 edits_0000000000000036294-0000000000000036295
-rw-rw-r-- 1 hadoop hadoop      42 Nov 28 19:40 edits_0000000000000036296-0000000000000036297
-rw-rw-r-- 1 hadoop hadoop 1048576 Nov 28 19:40 edits_inprogress_0000000000000036298
-rw-rw-r-- 1 hadoop hadoop  235504 Nov 28 18:08 fsimage_0000000000000036205
-rw-rw-r-- 1 hadoop hadoop      62 Nov 28 18:08 fsimage_0000000000000036205.md5
-rw-rw-r-- 1 hadoop hadoop  235504 Nov 28 19:08 fsimage_0000000000000036263
-rw-rw-r-- 1 hadoop hadoop      62 Nov 28 19:08 fsimage_0000000000000036263.md5
-rw-rw-r-- 1 hadoop hadoop       6 Nov 28 19:40 seen_txid
-rw-rw-r-- 1 hadoop hadoop     204 Nov 21 23:29 VERSION
查看edits文件:
<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
<EDITS_VERSION>-60</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>36029</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_TIMES</OPCODE>
<DATA>
<TXID>36030</TXID>
<LENGTH>0</LENGTH>
<PATH>/user/hadoop/lucl.txt</PATH>
<MTIME>-1</MTIME>
<ATIME>1448694798698</ATIME>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_END_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>36031</TXID>
</DATA>
</RECORD>
</EDITS>
查看fsimage文件:
<inode>
<id>20980</id>
<type>FILE</type>
<name>httpdomainscan_192.168.1.101_0_20130913160407.hsl</name>
<replication>2</replication>
<mtime>1448683960850</mtime>
<atime>1448683943208</atime>
<perferredBlockSize>134217728</perferredBlockSize>
<permission>hadoop:hadoop:rw-r--r--</permission>
<blocks>
<block>
<id>1073745442</id>
<genstamp>4628</genstamp>
<numBytes>134217728</numBytes>
</block>
<block>
<id>1073745443</id>
<genstamp>4629</genstamp>
<numBytes>53807068</numBytes>
</block>
</blocks>
</inode>
说明:通过fsimage能够了解到文件与数据块的关系,但是无法知道数据库与节点的关系。
org.apache.hadoop.hdfs.server.namenode.NameNode

* NameNode serves as both directory namespace manager and
* "inode table" for the Hadoop DFS.  There is a single NameNode
* running in any DFS deployment.  (Well, except when there
* is a second backup/failover NameNode, or when using federated NameNodes.)
*
* The NameNode controls two critical tables:
*   1)  filename->blocksequence (namespace)
*   2)  block->machinelist ("inodes")
*
* The first table is stored on disk and is very precious.
* The second table is rebuilt every time the NameNode comes up.


启动过程会读取fsimage文件:



NN在启动时会去加载fsimage中的数据,构造元数据结构。

在启动的过程中会处于safemode模式,此时HDFS的数据是不看操作的,默认时间是30秒。




启动成功后sfaemode会被关闭




NN节点显示已启动





本文出自 “闷葫芦的世界” 博客,请务必保留此出处http://luchunli.blog.51cto.com/2368057/1716883
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: