Hadoop 3.0 EC技術


Hadoop 3.0 EC技術

EC的設計目標

  • Hadoop默認的3副本方案需要額外的200%的存儲空間、和網絡IO開銷
  • 而一些較低I/O的warn和cold數據,副本數據的訪問是比較少的(hot數據副本會被用於計算)
  • EC可以提供同級別的容錯能力,存儲空間要少得多(官方宣傳不到50%),使用了EC,副本始終為1

EC背景

EC在RAID應用

  • EC在RAID也有應用,RAID通過EC將文件划分為更小的單位,例如:可以按照bit、byte或者block來划分。
  • 然后將這些條紋單元存儲在不同的磁盤中

條紋單元:官方稱之為Stripe Unit,我把它隱喻為斑馬身上的黑白條紋,就稱每個文件經過EC處理后的就是一個個的條紋單元。

image-20210116102333723

EC編碼奇偶校驗單元

image-20210116113700640

根據剩余條紋單元和奇偶校驗單元恢復數據。

image-20210116104607373

EC與HDFS

一個具有6個塊,3副本會消耗6 x 3 = 18個塊存儲空間。而EC只需要 6個Block,再加上3個奇偶校驗,僅需要6 + 3 = 9個塊。節省了一半的存儲空間。

EC在Hadoop架構的調整

使用EC有幾個重要優勢:

  1. Online-EC,在寫入數據的時候就是以EC方式寫入的,而不是先存完數據再開始進行EC編碼處理(offline-EC)。
  2. Online-EC將一個小文件分發到多個DataNode,而不是將多個文件放到一個編碼組中。這樣,刪除數據、Qutoa、數據遷移是更容易的。

NameNode元數據存儲

基於EC的文件存儲與Hadoop經典分塊存儲方式做了調整。

image-20210116123542149

基於條紋的HDFS存儲邏輯上是由Block Group(塊組組成),每個Block Group包含了一定數量的Internal Block(后續我們稱為EC Block)。如果一個文件有很多的EC Block,會占用NameNode較大的內存空間。HDFS引入了新的分層Block命名協議,通過Block的ID可以推斷出Block Group的ID,NameNode是基於Block Group而不是EC Block級別管理。

image-20210116174434234

Client

客戶端讀取、寫入HDFS也做了調整,當以Online-EC寫入一個文件時,是以並行方式來處理Block Group中的Internal Block。

  • 當寫入文件時,數據流通過DFSStripedOutputStream實現,會管理一組數據流,每個DataNode節點都對應一個數據流,並將Block Group的一個Internal Block存儲。這些流操作都是異步進行的。還有一個Coordinator,負責一個文件的所有Block Group操作,包括:結束當前的Block Group、分配新的Block Group等。
  • 當讀取文件時,數據流通過DFSStripedInputStream實現,它將請求的文件轉換為存儲在DataNode的Internal Block,然后進行並行讀取,出現故障時,發出奇偶校驗數據請求來進行解碼恢復Internal Block。

DataNode

DataNode上運行一個ErasureCodingWorker(ECWorker)任務,專門用於失敗的EC Block進行后台數據恢復。一旦NameNode檢測到失敗的EC Block,NameNode會選擇一個DataNode進行數據恢復。

  • 先從錯誤數據所在的Block Group數據節點中讀取正常的EC Block作為輸入,基於EC策略,通過最小的EC Block進行數據恢復。
  • 從輸入的EC Block以及奇偶校驗碼塊進行解碼數據恢復,生成正常的EC Block。
  • EC解碼完成后,將恢復的EC Block傳輸到對應的DataNode中。

EC存儲方案

EC編碼和解碼

EC編解碼器是對EC Block上的條紋單元進行處理。編碼器將EC Block中的多個條紋單元作為輸入,並輸出許多奇偶校驗單元。這個過程稱為編碼。條紋單元和奇偶校驗單元稱為EC編碼組。

image-20210118000628107

解碼的過程就是恢復數據的過程,可以通過剩余的條紋單元和奇偶校驗單元來恢復數據。

image-20210118000824836

容錯性和存儲效率

在比較不同的存儲方案時,需要考慮兩個重要因素:

  • 數據的容錯性(最多可允許同時出現多少故障來衡量,容錯性越大越好)
  • 存儲效率(邏輯大小除以物理數據存儲大小,存儲效率也是越大越好)

HDFS中副本方案的容錯性為:有N個副本,就可以容忍N-1同時發生故障。存儲效率為:1/N。

下面這張表格,是針對不同的存儲方案的數據容錯性和存儲效率。

image-20210118001007851

可以看出來,XOR只能容忍一個數據塊出現故障,而RS-6-3、RS-10-4允許3個、4個數據塊同時出現故障。但XOR的存儲效率是最高的、其次是RS-10-4、再下來是RS-6-3。而3副本的存儲效率是33%。

連續存儲還是條紋單元存儲

image-20210118001303227

這張圖對比了連續存儲和條紋存儲方案在HDFS的示意圖。可以明顯的看到,條紋存儲方案,將一個Block繼續分解為一個個的條紋單元。並在一組DataNode的block中,循環寫入條紋單元。基於連續存儲或者條紋存儲,都是支持EC的。EC的方式存儲效率比較高,但增加了復雜度、以及較高消耗的故障恢復。條紋存儲方案比連續存儲更好的I/O吞吐量。但與傳統的MapReduce本地數據讀取相悖,因為數據都是跨網絡存儲的。讀取數據需要更多的網絡I/O開銷。

連續存儲

連續存儲容易實現,讀寫的方式與副本方式非常類似。但只有文件很大的場景適用。例如:使用RS-10-4,一個128M的文件仍然要寫入4個128M的就校驗塊。存儲開銷為400%。這種方式,客戶端需要有GB級別的緩存來計算奇偶校驗單元。

條紋存儲

條紋存儲對小文件是友好的,可以節省很多空間。條紋單元大小通常是(64KB或者1MB)。客戶端只需要有幾MB的緩存就可以用於計算奇偶校驗單元。但這種方案,需要跨網絡I/O,性能會因此下降。要提升處理效率,需要將數據轉換為連續存儲,但這就需要重寫整個文件了。

所以文件大小決定了使用哪種方式更合適。Cloudera做了一些調研,發現其實HDFS中小文件(少於一個EC Block Group)的使用率占整個集群的36%-97%。小文件的處理更重要。所以HDFS EC使用的是條紋存儲的EC存儲方案。

image-20210118003442718

EC策略關鍵屬性

為了適應不同的業務需求,在HDFS中可以針對文件、目錄配置不同的副本和EC策略。EC策略實現了如何對文件進行編碼/解碼方式。每個策略包含以下屬性:

  • EC schema:EC schema包含了EC Group中的EC Block數量以及奇偶校驗Block的數量,例如:6+3,以及編解碼器算法,例如:Reed-Solomon(索羅蒙算法)、XOR(異或算法)。
  • 條紋單元大小(EC Block):條紋單元的大小決定了條紋單元的讀取、寫入速度、Buffer的大小、以及編碼的效率。

EC策略命名

EC策略命名策略:EC編碼器-EC Block數量-奇偶校驗Block數量-條紋單元大小。Hadoop中內置了5種策略:

  • RS-3-2-1024K
  • RS-6-3-1024K
  • RS-10-4-1024K
  • RS-LEGACY-6-3-1024K
  • XOR-2-1-1024K

同時,默認的副本策略也是支持的。副本策略設置在目錄上,這樣可以前置目錄使用3副本方案,指定該目錄不繼承EC編碼策略。這樣,目錄中是可以切換副本存儲方式的。

online-EC

Replication存儲方式是始終啟用的,默認啟用的EC策略是:RS-6-3-1024K。與Replication存儲方式一樣,如果父目錄設置了EC策略,子文件/目錄會繼承父目錄的EC策略。

目錄級別的EC策略僅會影響在目錄中創建的新文件,這也意味着就的文件不會重新進行EC編碼,HDFS是使用online-EC,文件一旦創建,可以查詢它的EC策略,但不能再更改

如果將已經進行EC編碼的文件移動到其他EC策略的目錄,文件的EC編碼也不會改變。如果想要將文件轉換為其他的EC策略,需要重寫數據。可以通過distcp來移動數據,而不是mv。

自定義EC策略

HDFS允許用戶基於XML自己來定義EC策略。例如:

<?xml version="1.0"?>
<configuration>
<!-- The version of EC policy XML file format, it must be an integer -->
<layoutversion>1</layoutversion>
<schemas>
  <!-- schema id is only used to reference internally in this document -->
  <schema id="XORk2m1">
    <!-- The combination of codec, k, m and options as the schema ID, defines
     a unique schema, for example 'xor-2-1'. schema ID is case insensitive -->
    <!-- codec with this specific name should exist already in this system -->
    <codec>xor</codec>
    <k>2</k>
    <m>1</m>
    <options> </options>
  </schema>
  <schema id="RSk12m4">
    <codec>RS</codec>
    <k>12</k>
    <m>4</m>
    <options> </options>
  </schema>
  <schema id="RS-legacyk12m4">
    <codec>RS-legacy</codec>
    <k>12</k>
    <m>4</m>
    <options> </options>
  </schema>
</schemas>
    
<policies>
  <policy>
    <!-- the combination of schema ID and cellsize(in unit k) defines a unique
     policy, for example 'xor-2-1-256k', case insensitive -->
    <!-- schema is referred by its id -->
    <schema>XORk2m1</schema>
    <!-- cellsize must be an positive integer multiple of 1024(1k) -->
    <!-- maximum cellsize is defined by 'dfs.namenode.ec.policies.max.cellsize' property -->
    <cellsize>131072</cellsize>
  </policy>
  <policy>
    <schema>RS-legacyk12m4</schema>
    <cellsize>262144</cellsize>
  </policy>
</policies>
</configuration>

配置文件很容易理解,主要包含兩個部分組成:

  1. EC Schema:編碼器、k(EC Block數量)、m(奇偶校驗Block數量)
  2. Policy:綁定schema、以及指定條紋單元大小

RS-legacy:遺留的,基於純Java語言實現的EC編解碼器

而HDFS默認的RS和XOR編解碼器是基於Native實現的。

XOR算法與RS算法

XOR算法

XOR(異或)算法是最簡單的EC實現,可以從任意數量的數據生成1個奇偶校驗位。例如:1 ⊕ 0 ⊕ 1 ⊕ 1 = 1。但針對任意數量的條紋單元僅生成一個奇偶校驗位。HDFS中如果出現多個故障,這種恢復方式是不夠的。XOR的容錯能力為1,存儲效率為75%。

image-20210118003810646

如果某一個X、Y對丟失,可以通過奇偶檢驗位進行異或來恢復。

Reed-Solomon算法

RS算法克服了XOR算法的限制,基於線性代數運算來生成多個奇偶校驗位,可以容忍多個失敗。RS 算法使用生成矩陣(GT,Generator Matrix)與 m 個數據單元相乘,以獲得具有 m 個數據單元(data cells)和 n 個奇偶校驗單元(parity cells)的 extended codewords。RS算法的容錯能力最高為n。存儲效率為 m / m + n。例如:RS-6-3為67%的存儲效率,而:RS-3-2為60%的存儲效率。

image-20210118003934883

上圖可以看到,RS是使用復雜的線性代碼運算來生成多個奇偶校驗單元,可以容忍每個組出現多個故障。一般生產環境都是使用RS算法。RS-k-m是將k個條紋單元與生成矩陣Gt相乘,生成具有k個條紋單元和m個奇偶校驗單元。只要k + m個單元的k個可用,就可以通過剩余的條紋單元乘以Gt的倒數恢復存儲失敗。可以容忍m個數據單元的故障。

部署HDFS EC

集群配置要求

  • EC對Hadoop集群的CPU、網絡有額外的要求。EC編碼、解碼會消耗HDFS客戶端、DataNode更多的CPU資源
  • EC要求集群中的DataNode最起碼和EC條紋寬度(條紋寬度 = EC Block數量 + 奇偶校驗Block數量)是一樣的。也就是,如果我們用使用RS-6-3策略,至少需要9台DataNode。
  • EC Block文件也是分布在整個機架上,以實現機架級別的容錯。在讀寫EC Block文件時,也需要保證機架的帶寬。如果要實現機架級別的容錯,需要擁有一定數量的機架容錯。每個機架所存放的EC Block不能超過就校驗塊的數量。機架數量計算公式為:(EC Block數量 + 奇偶校驗塊數量)/ 奇偶校驗塊數量,然后四舍五入。例如:針對RS-6-3如果要實現機架級別的容錯,至少需要(6 + 3)/ 3 = 3個機架。如果機架數小於這個數,將無法保證機架級別的容錯。如果有進行機架級別停機維護需求,官方建議提供6 + 3以上個機架。

EC配置

默認,除了dfs.namenode.ec.system.default.policy指定的默認策略,其他的內置的EC策略都是禁用的。我們可以根據Hadoop集群的大小、以及所需的容錯屬性,通過hdfs ec -enablePolicy -policy 策略名稱來啟用EC策略。例如:如果有5個節點的集群,比較適合的就是RS-3-2-1024k,而RS-10-4-1024k策略就不合適了。

默認dfs.namenode.ec.system.default.policy為RS-6-3-1024k。

# 讀取EC Block(條紋文件)的超時時間,默認5000毫秒
dfs.datanode.ec.reconstruction.stripedread.timeout.millis
# 讀取EC Block的緩存大小,默認為64KB
dfs.datanode.ec.reconstruction.stripedread.buffer.size
# 用於DataNode重建EC Block的線程數量,默認為8個線程
dfs.datanode.ec.reconstruction.threads
# EC后台恢復任務數與復制Block的Xmits權重。NameNode基於這個Xmits值來調度任務到DataNode。默認為0.5,設置為0表示禁用EC恢復任務計算權重,始終都是1 Xmits。它的值為:讀取正常EC Block的數量、以及暑輸出新的EC Block的最大值。例如:如果讀取6個正常的EC Block,輸出到兩個EC Block,則Xmits值為:Max(6, 2) * 0.5 = 3。
dfs.datanode.ec.reconstruction.xmits.weight

EC命令

EC相關的操作,使用hdfs ec命令。

hdfs ec [generic options]
[-setPolicy -path <path> [-policy <policyName>] [-replicate]]
[-getPolicy -path <path>]
[-unsetPolicy -path <path>]
[-listPolicies]
[-addPolicies -policyFile <file>]
[-listCodecs]
[-enablePolicy -policy <policyName>]
[-disablePolicy -policy <policyName>]
[-verifyClusterSetup -policy <policyName>...<policyName>]
[-help [cmd ...]]

1、查看當前HDFS支持的ec策略

[root@node1 hadoop]# hdfs ec -listPolicies
Erasure Coding Policies:
ErasureCodingPolicy=[Name=RS-10-4-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=10, numParityUnits=4]], CellSize=1048576, Id=5], State=DISABLED
ErasureCodingPolicy=[Name=RS-3-2-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=3, numParityUnits=2]], CellSize=1048576, Id=2], State=DISABLED
ErasureCodingPolicy=[Name=RS-6-3-1024k, Schema=[ECSchema=[Codec=rs, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=1], State=ENABLED
ErasureCodingPolicy=[Name=RS-LEGACY-6-3-1024k, Schema=[ECSchema=[Codec=rs-legacy, numDataUnits=6, numParityUnits=3]], CellSize=1048576, Id=3], State=DISABLED
ErasureCodingPolicy=[Name=XOR-2-1-1024k, Schema=[ECSchema=[Codec=xor, numDataUnits=2, numParityUnits=1]], CellSize=1048576, Id=4], State=ENABLED

我們看到目前我的HDFS集群上面啟用了兩個策略:一個是RS-6-3-1024k、一個是XOR-2-1-1024k。

2、查看當前HDFS支持的編解碼器

[root@node1 hadoop]# hdfs ec -listCodecs
Erasure Coding Codecs: Codec [Coder List]
	RS [RS_NATIVE, RS_JAVA]
	RS-LEGACY [RS-LEGACY_JAVA]
	XOR [XOR_NATIVE, XOR_JAVA]

3、設置EC編碼策略。因為我的測試集群只有3個節點,所以只能使用XOR-2-1-1024k。先要將XOR-2-1-1024k啟用。

-- 創建用於存放冷數據的目錄
[root@node1 hadoop]# hdfs dfs -mkdir -p /workspace/feng/cold_data

-- 啟用XOR-2-1-1024 EC策略
[root@node1 hadoop]# hdfs ec -enablePolicy -policy XOR-2-1-1024k
Erasure coding policy XOR-2-1-1024k is enabled

-- 驗證當前集群是否支持所有啟用的或者指定的EC策略(這個命令應該是3.2.x添加的,我當前是3.1.4,還不支持這個命令)
-- hdfs ec -verifyClusterSetup -policy XOR-2-1-1024k

-- 設置冷數據EC存儲策略
[root@node1 hadoop]# hdfs ec -setPolicy -path /workspace/feng/cold_data -policy XOR-2-1-1024k
Set XOR-2-1-1024k erasure coding policy on /workspace/feng/cold_data

-- 查看冷數據目錄的存儲策略
[root@node1 hadoop]# hdfs ec -getPolicy -path /workspace/feng/cold_data
XOR-2-1-1024k

驗證測試

新上傳一個293M的文件到冷數據目錄

[root@node1 software]# hdfs dfs -put hadoop-3.1.4.tar.gz /workspace/feng/cold_data
2021-01-16 14:23:28,681 WARN erasurecode.ErasureCodeNative: ISA-L support is not available in your platform... using builtin-java codec where applicable

此處,Hadoop警告提示,當前我的操作系統平台,不支持ISA-L,默認RS、XOR使用的是Native方式進行編解碼,會基於Intel的ISA-L加速編解碼。

我們來查看下HDFS文件的Block的信息:

[root@node3 subdir2]# hdfs fsck /workspace/feng/cold_data/hadoop-3.1.4.tar.gz -files -blocks 

我們看到文件是以XOR-2-1-1024k進行EC編碼,並且有兩個Block。總共有兩個EC Block Group。

0. BP-538037512-192.168.88.100-1600884040401:blk_-9223372036854775232_2020 len=268435456 Live_repl=3
1. BP-538037512-192.168.88.100-1600884040401:blk_-9223372036854775216_2021 len=38145321 Live_repl=3

總共的EC Block Group = 306580777字節,與原始的數據文件相等。

Erasure Coded Block Groups:
 Total size:	306580777 B
 Total files:	1
 Total block groups (validated):	2 (avg. block group size 153290388 B)
 Minimally erasure-coded block groups:	2 (100.0 %)
 Over-erasure-coded block groups:	0 (0.0 %)
 Under-erasure-coded block groups:	0 (0.0 %)
 Unsatisfactory placement block groups:	0 (0.0 %)
 Average block group size:	3.0
 Missing block groups:		0
 Corrupt block groups:		0
 Missing internal blocks:	0 (0.0 %)
FSCK ended at Sat Jan 16 16:59:46 CST 2021 in 1 milliseconds

原始文件大小:

[root@node1 software]# ll hadoop-3.1.4.tar.gz 
-rw-r--r-- 1 root root 306580777 Sep 25 09:29 hadoop-3.1.4.tar.gz

我們可以觀察看到當前的Block Group大小為:256MB。而我的HDFS集群配置的dfs block size是:128MB。

<property>
    <name>dfs.blocksize</name>
    <value>134217728</value>
    <final>false</final>
    <source>hdfs-default.xml</source>
</property>

因為當前的Block size是128MB,而EC的策略是:XOR-2-1,也就是一個Block Group 2個Block,所以Block Group的大小就是256MB了。

使用distcp遷移數據

假設現在需要將一個3副本存儲方式的文件,遷移到配置了EC策略的目錄中。

-- 創建一個用於測試的數據目錄
hdfs dfs -mkdir /workspace/feng/test_data
-- 上傳一個測試文件
hdfs dfs -put hbase-logs.zip /workspace/feng/test_data

-- 啟動YARN
start-yarn.sh

-- 使用distcp移動到EC策略的目錄中(此處要跳過檢驗和,因為使用EC編碼肯定校驗失敗)
hadoop distcp -update -skipcrccheck /workspace/feng/test_data/hbase-logs.zip /workspace/feng/cold_data

可以對比下該文件的block數據:

3副本方式文件

[root@node1 hadoop]# hdfs fsck /workspace/feng/test_data/hbase-logs.zip  -files -blocks 
Connecting to namenode via http://node1:9870/fsck?ugi=root&files=1&blocks=1&path=%2Fworkspace%2Ffeng%2Ftest_data%2Fhbase-logs.zip
FSCK started by root (auth:SIMPLE) from /192.168.88.100 for path /workspace/feng/test_data/hbase-logs.zip at Sat Jan 16 19:43:39 CST 2021

/workspace/feng/test_data/hbase-logs.zip 6970734 bytes, replicated: replication=3, 1 block(s):  OK
0. BP-538037512-192.168.88.100-1600884040401:blk_1073742800_2023 len=6970734 Live_repl=3


Status: HEALTHY
 Number of data-nodes:	3
 Number of racks:		1
 Total dirs:			0
 Total symlinks:		0

Replicated Blocks:
 Total size:	6970734 B
 Total files:	1
 Total blocks (validated):	1 (avg. block size 6970734 B)
 Minimally replicated blocks:	1 (100.0 %)
 Over-replicated blocks:	0 (0.0 %)
 Under-replicated blocks:	0 (0.0 %)
 Mis-replicated blocks:		0 (0.0 %)
 Default replication factor:	3
 Average block replication:	3.0
 Missing blocks:		0
 Corrupt blocks:		0
 Missing replicas:		0 (0.0 %)

Erasure Coded Block Groups:
 Total size:	0 B
 Total files:	0
 Total block groups (validated):	0
 Minimally erasure-coded block groups:	0
 Over-erasure-coded block groups:	0
 Under-erasure-coded block groups:	0
 Unsatisfactory placement block groups:	0
 Average block group size:	0.0
 Missing block groups:		0
 Corrupt block groups:		0
 Missing internal blocks:	0
FSCK ended at Sat Jan 16 19:43:39 CST 2021 in 1 milliseconds


The filesystem under path '/workspace/feng/test_data/hbase-logs.zip' is HEALTHY

EC編碼后的文件

[root@node1 hadoop]# hdfs fsck /workspace/feng/cold_data/hbase-logs.zip  -files -blocks 
Connecting to namenode via http://node1:9870/fsck?ugi=root&files=1&blocks=1&path=%2Fworkspace%2Ffeng%2Fcold_data%2Fhbase-logs.zip
FSCK started by root (auth:SIMPLE) from /192.168.88.100 for path /workspace/feng/cold_data/hbase-logs.zip at Sat Jan 16 19:42:51 CST 2021

/workspace/feng/cold_data/hbase-logs.zip 6970734 bytes, erasure-coded: policy=XOR-2-1-1024k, 1 block(s):  OK
0. BP-538037512-192.168.88.100-1600884040401:blk_-9223372036854774560_2128 len=6970734 Live_repl=3

Status: HEALTHY
 Number of data-nodes:	3
 Number of racks:		1
 Total dirs:			0
 Total symlinks:		0

Replicated Blocks:
 Total size:	0 B
 Total files:	0
 Total blocks (validated):	0
 Minimally replicated blocks:	0
 Over-replicated blocks:	0
 Under-replicated blocks:	0
 Mis-replicated blocks:		0
 Default replication factor:	3
 Average block replication:	0.0
 Missing blocks:		0
 Corrupt blocks:		0
 Missing replicas:		0

Erasure Coded Block Groups:
 Total size:	6970734 B
 Total files:	1
 Total block groups (validated):	1 (avg. block group size 6970734 B)
 Minimally erasure-coded block groups:	1 (100.0 %)
 Over-erasure-coded block groups:	0 (0.0 %)
 Under-erasure-coded block groups:	0 (0.0 %)
 Unsatisfactory placement block groups:	0 (0.0 %)
 Average block group size:	3.0
 Missing block groups:		0
 Corrupt block groups:		0
 Missing internal blocks:	0 (0.0 %)
FSCK ended at Sat Jan 16 19:42:51 CST 2021 in 1 milliseconds

基於Hive使用EC

基於副本冗余方式和EC方式共存。

按時間分區設置EC

  • 對時間較早的分區(例如:半年前的數據),設置EC策略
  • 默認分區還使用副本冗余方式,這樣可以保證多個作業讀取數據時,可以獲取比較好的性能

按數據使用頻率設置EC

  • 一些只運行一兩次就不再使用的數倉低層數據,可以使用EC存儲。
  • 一些非共享的、ETL系統的數據可以設置EC,獲得更高的EC存儲。

參考文獻:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM