Hadoop
分布式文件系統(tǒng):架構(gòu)和設(shè)計(jì)要點(diǎn)
原文:http://hadoop.apache.org/core/docs/current/hdfs_design.html
一、前提和設(shè)計(jì)目標(biāo)
1
、硬件錯(cuò)誤是常態(tài),而非異常情況,
HDFS
可能是有成百上千的
server
組成,任何一個(gè)組件都有可能一直失效,因此錯(cuò)誤檢測(cè)和快速、自動(dòng)的恢復(fù)是
HDFS
的核心架構(gòu)目標(biāo)。
2
、跑在
HDFS
上的應(yīng)用與一般的應(yīng)用不同,它們主要是以流式讀為主,做批量處理;比之關(guān)注數(shù)據(jù)訪問的低延遲問題,更關(guān)鍵的在于數(shù)據(jù)訪問的高吞吐量。
3
、
HDFS
以支持大數(shù)據(jù)集合為目標(biāo),一個(gè)存儲(chǔ)在上面的典型文件大小一般都在千兆至
T
字節(jié),一個(gè)單一
HDFS
實(shí)例應(yīng)該能支撐數(shù)以千萬(wàn)計(jì)的文件。
4
、
HDFS
應(yīng)用對(duì)文件要求的是
write-one-read-many
訪問模型。一個(gè)文件經(jīng)過創(chuàng)建、寫,關(guān)閉之后就不需要改變。這一假設(shè)簡(jiǎn)化了數(shù)據(jù)一致性問題,使高吞吐量的數(shù)據(jù)訪問成為可能。典型的如
MapReduce
框架,或者一個(gè)
web crawler
應(yīng)用都很適合這個(gè)模型。
5
、移動(dòng)計(jì)算的代價(jià)比之移動(dòng)數(shù)據(jù)的代價(jià)低。一個(gè)應(yīng)用請(qǐng)求的計(jì)算,離它操作的數(shù)據(jù)越近就越高效,這在數(shù)據(jù)達(dá)到海量級(jí)別的時(shí)候更是如此。將計(jì)算移動(dòng)到數(shù)據(jù)附近,比之將數(shù)據(jù)移動(dòng)到應(yīng)用所在顯然更好,
HDFS
提供給應(yīng)用這樣的接口。
6
、在異構(gòu)的軟硬件平臺(tái)間的可移植性。
二、
Namenode
和
Datanode
??? HDFS
采用
master/slave
架構(gòu)。一個(gè)
HDFS
集群是有一個(gè)
Namenode
和一定數(shù)目的
Datanode
組成。
Namenode
是一個(gè)中心服務(wù)器,負(fù)責(zé)管理文件系統(tǒng)的
namespace
和客戶端對(duì)文件的訪問。
Datanode
在集群中一般是一個(gè)節(jié)點(diǎn)一個(gè),負(fù)責(zé)管理節(jié)點(diǎn)上它們附帶的存儲(chǔ)。在內(nèi)部,一個(gè)文件其實(shí)分成一個(gè)或多個(gè)
block
,這些
block
存儲(chǔ)在
Datanode
集合里。
Namenode
執(zhí)行文件系統(tǒng)的
namespace
操作,例如打開、關(guān)閉、重命名文件和目錄,同時(shí)決定
block
到具體
Datanode
節(jié)點(diǎn)的映射。
Datanode
在
Namenode
的指揮下進(jìn)行
block
的創(chuàng)建、刪除和復(fù)制。
Namenode
和
Datanode
都是設(shè)計(jì)成可以跑在普通的廉價(jià)的運(yùn)行
linux
的機(jī)器上。
HDFS
采用
java
語(yǔ)言開發(fā),因此可以部署在很大范圍的機(jī)器上。一個(gè)典型的部署場(chǎng)景是一臺(tái)機(jī)器跑一個(gè)單獨(dú)的
Namenode
節(jié)點(diǎn),集群中的其他機(jī)器各跑一個(gè)
Datanode
實(shí)例。這個(gè)架構(gòu)并不排除一臺(tái)機(jī)器上跑多個(gè)
Datanode
,不過這比較少見。
單一節(jié)點(diǎn)的
Namenode
大大簡(jiǎn)化了系統(tǒng)的架構(gòu)。
Namenode
負(fù)責(zé)保管和管理所有的
HDFS
元數(shù)據(jù),因而用戶數(shù)據(jù)就不需要通過
Namenode
(也就是說文件數(shù)據(jù)的讀寫是直接在
Datanode
上)。
三、文件系統(tǒng)的
namespace
?? HDFS
支持傳統(tǒng)的層次型文件組織,與大多數(shù)其他文件系統(tǒng)類似,用戶可以創(chuàng)建目錄,并在其間創(chuàng)建、刪除、移動(dòng)和重命名文件。
HDFS
不支持
user quotas
和訪問權(quán)限,也不支持鏈接(
link)
,不過當(dāng)前的架構(gòu)并不排除實(shí)現(xiàn)這些特性。
Namenode
維護(hù)文件系統(tǒng)的
namespace
,任何對(duì)文件系統(tǒng)
namespace
和文件屬性的修改都將被
Namenode
記錄下來。應(yīng)用可以設(shè)置
HDFS
保存的文件的副本數(shù)目,文件副本的數(shù)目稱為文件的
replication
因子,這個(gè)信息也是由
Namenode
保存。
四、數(shù)據(jù)復(fù)制
??? HDFS
被設(shè)計(jì)成在一個(gè)大集群中可以跨機(jī)器地可靠地存儲(chǔ)海量的文件。它將每個(gè)文件存儲(chǔ)成
block
序列,除了最后一個(gè)
block
,所有的
block
都是同樣的大小。文件的所有
block
為了容錯(cuò)都會(huì)被復(fù)制。每個(gè)文件的
block
大小和
replication
因子都是可配置的。
Replication
因子可以在文件創(chuàng)建的時(shí)候配置,以后也可以改變。
HDFS
中的文件是
write-one
,并且嚴(yán)格要求在任何時(shí)候只有一個(gè)
writer
。
Namenode
全權(quán)管理
block
的復(fù)制,它周期性地從集群中的每個(gè)
Datanode
接收心跳包和一個(gè)
Blockreport
。心跳包的接收表示該
Datanode
節(jié)點(diǎn)正常工作,而
Blockreport
包括了該
Datanode
上所有的
block
組成的列表。
1
、副本的存放,副本的存放是
HDFS
可靠性和性能的關(guān)鍵。
HDFS
采用一種稱為
rack-aware
的策略來改進(jìn)數(shù)據(jù)的可靠性、有效性和網(wǎng)絡(luò)帶寬的利用。這個(gè)策略實(shí)現(xiàn)的短期目標(biāo)是驗(yàn)證在生產(chǎn)環(huán)境下的表現(xiàn),觀察它的行為,構(gòu)建測(cè)試和研究的基礎(chǔ),以便實(shí)現(xiàn)更先進(jìn)的策略。龐大的
HDFS
實(shí)例一般運(yùn)行在多個(gè)機(jī)架的計(jì)算機(jī)形成的集群上,不同機(jī)架間的兩臺(tái)機(jī)器的通訊需要通過交換機(jī),顯然通常情況下,同一個(gè)機(jī)架內(nèi)的兩個(gè)節(jié)點(diǎn)間的帶寬會(huì)比不同機(jī)架間的兩臺(tái)機(jī)器的帶寬大。
???
通過一個(gè)稱為
Rack Awareness
的過程,
Namenode
決定了每個(gè)
Datanode
所屬的
rack id
。一個(gè)簡(jiǎn)單但沒有優(yōu)化的策略就是將副本存放在單獨(dú)的機(jī)架上。這樣可以防止整個(gè)機(jī)架(非副本存放)失效的情況,并且允許讀數(shù)據(jù)的時(shí)候可以從多個(gè)機(jī)架讀取。這個(gè)簡(jiǎn)單策略設(shè)置可以將副本分布在集群中,有利于組件失敗情況下的負(fù)載均衡。但是,這個(gè)簡(jiǎn)單策略加大了寫的代價(jià),因?yàn)橐粋€(gè)寫操作需要傳輸
block
到多個(gè)機(jī)架。
???
在大多數(shù)情況下,
replication
因子是
3
,
HDFS
的存放策略是將一個(gè)副本存放在本地機(jī)架上的節(jié)點(diǎn),一個(gè)副本放在同一機(jī)架上的另一個(gè)節(jié)點(diǎn),最后一個(gè)副本放在不同機(jī)架上的一個(gè)節(jié)點(diǎn)。機(jī)架的錯(cuò)誤遠(yuǎn)遠(yuǎn)比節(jié)點(diǎn)的錯(cuò)誤少,這個(gè)策略不會(huì)影響到數(shù)據(jù)的可靠性和有效性。三分之一的副本在一個(gè)節(jié)點(diǎn)上,三分之二在一個(gè)機(jī)架上,其他保存在剩下的機(jī)架中,這一策略改進(jìn)了寫的性能。
2
、副本的選擇,為了降低整體的帶寬消耗和讀延時(shí),
HDFS
會(huì)盡量讓
reader
讀最近的副本。如果在
reader
的同一個(gè)機(jī)架上有一個(gè)副本,那么就讀該副本。如果一個(gè)
HDFS
集群跨越多個(gè)數(shù)據(jù)中心,那么
reader
也將首先嘗試讀本地?cái)?shù)據(jù)中心的副本。
3
、
SafeMode
??? Namenode
啟動(dòng)后會(huì)進(jìn)入一個(gè)稱為
SafeMode
的特殊狀態(tài),處在這個(gè)狀態(tài)的
Namenode
是不會(huì)進(jìn)行數(shù)據(jù)塊的復(fù)制的。
Namenode
從所有的
Datanode
接收心跳包和
Blockreport
。
Blockreport
包括了某個(gè)
Datanode
所有的數(shù)據(jù)塊列表。每個(gè)
block
都有指定的最小數(shù)目的副本。當(dāng)
Namenode
檢測(cè)確認(rèn)某個(gè)
Datanode
的數(shù)據(jù)塊副本的最小數(shù)目,那么該
Datanode
就會(huì)被認(rèn)為是安全的;如果一定百分比(這個(gè)參數(shù)可配置)的數(shù)據(jù)塊檢測(cè)確認(rèn)是安全的,那么
Namenode
將退出
SafeMode
狀態(tài),接下來它會(huì)確定還有哪些數(shù)據(jù)塊的副本沒有達(dá)到指定數(shù)目,并將這些
block
復(fù)制到其他
Datanode
。
五、文件系統(tǒng)元數(shù)據(jù)的持久化
??? Namenode
存儲(chǔ)
HDFS
的元數(shù)據(jù)。對(duì)于任何對(duì)文件元數(shù)據(jù)產(chǎn)生修改的操作,
Namenode
都使用一個(gè)稱為
Editlog
的事務(wù)日志記錄下來。例如,在
HDFS
中創(chuàng)建一個(gè)文件,
Namenode
就會(huì)在
Editlog
中插入一條記錄來表示;同樣,修改文件的
replication
因子也將往
Editlog
插入一條記錄。
Namenode
在本地
OS
的文件系統(tǒng)中存儲(chǔ)這個(gè)
Editlog
。整個(gè)文件系統(tǒng)的
namespace
,包括
block
到文件的映射、文件的屬性,都存儲(chǔ)在稱為
FsImage
的文件中,這個(gè)文件也是放在
Namenode
所在系統(tǒng)的文件系統(tǒng)上。
??? Namenode
在內(nèi)存中保存著整個(gè)文件系統(tǒng)
namespace
和文件
Blockmap
的映像。這個(gè)關(guān)鍵的元數(shù)據(jù)設(shè)計(jì)得很緊湊,因而一個(gè)帶有
4G
內(nèi)存的
Namenode
足夠支撐海量的文件和目錄。當(dāng)
Namenode
啟動(dòng)時(shí),它從硬盤中讀取
Editlog
和
FsImage
,將所有
Editlog
中的事務(wù)作用(
apply)
在內(nèi)存中的
FsImage
,并將這個(gè)新版本的
FsImage
從內(nèi)存中
flush
到硬盤上
,
然后再
truncate
這個(gè)舊的
Editlog
,因?yàn)檫@個(gè)舊的
Editlog
的事務(wù)都已經(jīng)作用在
FsImage
上了。這個(gè)過程稱為
checkpoint
。在當(dāng)前實(shí)現(xiàn)中,
checkpoint
只發(fā)生在
Namenode
啟動(dòng)時(shí),在不久的將來我們將實(shí)現(xiàn)支持周期性的
checkpoint
。
??? Datanode
并不知道關(guān)于文件的任何東西,除了將文件中的數(shù)據(jù)保存在本地的文件系統(tǒng)上。它把每個(gè)
HDFS
數(shù)據(jù)塊存儲(chǔ)在本地文件系統(tǒng)上隔離的文件中。
Datanode
并不在同一個(gè)目錄創(chuàng)建所有的文件,相反,它用啟發(fā)式地方法來確定每個(gè)目錄的最佳文件數(shù)目,并且在適當(dāng)?shù)臅r(shí)候創(chuàng)建子目錄。在同一個(gè)目錄創(chuàng)建所有的文件不是最優(yōu)的選擇,因?yàn)楸镜匚募到y(tǒng)可能無法高效地在單一目錄中支持大量的文件。當(dāng)一個(gè)
Datanode
啟動(dòng)時(shí),它掃描本地文件系統(tǒng),對(duì)這些本地文件產(chǎn)生相應(yīng)的一個(gè)所有
HDFS
數(shù)據(jù)塊的列表,然后發(fā)送報(bào)告到
Namenode
,這個(gè)報(bào)告就是
Blockreport
。
六、通訊協(xié)議
???
所有的
HDFS
通訊協(xié)議都是構(gòu)建在
TCP/IP
協(xié)議上??蛻舳送ㄟ^一個(gè)可配置的端口連接到
Namenode
,通過
ClientProtocol
與
Namenode
交互。而
Datanode
是使用
DatanodeProtocol
與
Namenode
交互。從
ClientProtocol
和
Datanodeprotocol
抽象出一個(gè)遠(yuǎn)程調(diào)用
(RPC
),在設(shè)計(jì)上,
Namenode
不會(huì)主動(dòng)發(fā)起
RPC
,而是是響應(yīng)來自客戶端和
Datanode
的
RPC
請(qǐng)求。
七、健壯性
??? HDFS
的主要目標(biāo)就是實(shí)現(xiàn)在失敗情況下的數(shù)據(jù)存儲(chǔ)可靠性。常見的三種失?。?
Namenode failures, Datanode failures
和網(wǎng)絡(luò)分割(
network partitions)
。
1
、硬盤數(shù)據(jù)錯(cuò)誤、心跳檢測(cè)和重新復(fù)制
???
每個(gè)
Datanode
節(jié)點(diǎn)都向
Namenode
周期性地發(fā)送心跳包。網(wǎng)絡(luò)切割可能導(dǎo)致一部分
Datanode
跟
Namenode
失去聯(lián)系。
Namenode
通過心跳包的缺失檢測(cè)到這一情況,并將這些
Datanode
標(biāo)記為
dead
,不會(huì)將新的
IO
請(qǐng)求發(fā)給它們。寄存在
dead Datanode
上的任何數(shù)據(jù)將不再有效。
Datanode
的死亡可能引起一些
block
的副本數(shù)目低于指定值,
Namenode
不斷地跟蹤需要復(fù)制的
block
,在任何需要的情況下啟動(dòng)復(fù)制。在下列情況可能需要重新復(fù)制:某個(gè)
Datanode
節(jié)點(diǎn)失效,某個(gè)副本遭到損壞,
Datanode
上的硬盤錯(cuò)誤,或者文件的
replication
因子增大。
2
、集群均衡
?? HDFS
支持?jǐn)?shù)據(jù)的均衡計(jì)劃,如果某個(gè)
Datanode
節(jié)點(diǎn)上的空閑空間低于特定的臨界點(diǎn),那么就會(huì)啟動(dòng)一個(gè)計(jì)劃自動(dòng)地將數(shù)據(jù)從一個(gè)
Datanode
搬移到空閑的
Datanode
。當(dāng)對(duì)某個(gè)文件的請(qǐng)求突然增加,那么也可能啟動(dòng)一個(gè)計(jì)劃創(chuàng)建該文件新的副本,并分布到集群中以滿足應(yīng)用的要求。這些均衡計(jì)劃目前還沒有實(shí)現(xiàn)。
3
、數(shù)據(jù)完整性
?
從某個(gè)
Datanode
獲取的數(shù)據(jù)塊有可能是損壞的,這個(gè)損壞可能是由于
Datanode
的存儲(chǔ)設(shè)備錯(cuò)誤、網(wǎng)絡(luò)錯(cuò)誤或者軟件
bug
造成的。
HDFS
客戶端軟件實(shí)現(xiàn)了
HDFS
文件內(nèi)容的校驗(yàn)和。當(dāng)某個(gè)客戶端創(chuàng)建一個(gè)新的
HDFS
文件,會(huì)計(jì)算這個(gè)文件每個(gè)
block
的校驗(yàn)和,并作為一個(gè)單獨(dú)的隱藏文件保存這些校驗(yàn)和在同一個(gè)
HDFS namespace
下。當(dāng)客戶端檢索文件內(nèi)容,它會(huì)確認(rèn)從
Datanode
獲取的數(shù)據(jù)跟相應(yīng)的校驗(yàn)和文件中的校驗(yàn)和是否匹配,如果不匹配,客戶端可以選擇從其他
Datanode
獲取該
block
的副本。
4
、元數(shù)據(jù)磁盤錯(cuò)誤
??? FsImage
和
Editlog
是
HDFS
的核心數(shù)據(jù)結(jié)構(gòu)。這些文件如果損壞了,整個(gè)
HDFS
實(shí)例都將失效。因而,
Namenode
可以配置成支持維護(hù)多個(gè)
FsImage
和
Editlog
的拷貝。任何對(duì)
FsImage
或者
Editlog
的修改,都將同步到它們的副本上。這個(gè)同步操作可能會(huì)降低
Namenode
每秒能支持處理的
namespace
事務(wù)。這個(gè)代價(jià)是可以接受的,因?yàn)?
HDFS
是數(shù)據(jù)密集的,而非元數(shù)據(jù)密集。當(dāng)
Namenode
重啟的時(shí)候,它總是選取最近的一致的
FsImage
和
Editlog
使用。
?? Namenode
在
HDFS
是單點(diǎn)存在,如果
Namenode
所在的機(jī)器錯(cuò)誤,手工的干預(yù)是必須的。目前,在另一臺(tái)機(jī)器上重啟因故障而停止服務(wù)的
Namenode
這個(gè)功能還沒實(shí)現(xiàn)。
5
、快照
??
快照支持某個(gè)時(shí)間的數(shù)據(jù)拷貝,當(dāng)
HDFS
數(shù)據(jù)損壞的時(shí)候,可以恢復(fù)到過去一個(gè)已知正確的時(shí)間點(diǎn)。
HDFS
目前還不支持快照功能。
八、數(shù)據(jù)組織
1
、數(shù)據(jù)塊
???
兼容
HDFS
的應(yīng)用都是處理大數(shù)據(jù)集合的。這些應(yīng)用都是寫數(shù)據(jù)一次,讀卻是一次到多次,并且讀的速度要滿足流式讀。
HDFS
支持文件的
write- once-read-many
語(yǔ)義。一個(gè)典型的
block
大小是
64MB
,因而,文件總是按照
64M
切分成
chunk
,每個(gè)
chunk
存儲(chǔ)于不同的
Datanode
2
、步驟
???
某個(gè)客戶端創(chuàng)建文件的請(qǐng)求其實(shí)并沒有立即發(fā)給
Namenode
,事實(shí)上,
HDFS
客戶端會(huì)將文件數(shù)據(jù)緩存到本地的一個(gè)臨時(shí)文件。應(yīng)用的寫被透明地重定向到這個(gè)臨時(shí)文件。當(dāng)這個(gè)臨時(shí)文件累積的數(shù)據(jù)超過一個(gè)
block
的大?。J(rèn)
64M)
,客戶端才會(huì)聯(lián)系
Namenode
。
Namenode
將文件名插入文件系統(tǒng)的層次結(jié)構(gòu)中,并且分配一個(gè)數(shù)據(jù)塊給它,然后返回
Datanode
的標(biāo)識(shí)符和目標(biāo)數(shù)據(jù)塊給客戶端??蛻舳藢⒈镜嘏R時(shí)文件
flush
到指定的
Datanode
上。當(dāng)文件關(guān)閉時(shí),在臨時(shí)文件中剩余的沒有
flush
的數(shù)據(jù)也會(huì)傳輸?shù)街付ǖ?
Datanode
,然后客戶端告訴
Namenode
文件已經(jīng)關(guān)閉。此時(shí)
Namenode
才將文件創(chuàng)建操作提交到持久存儲(chǔ)。如果
Namenode
在文件關(guān)閉前掛了,該文件將丟失。
??
上述方法是對(duì)通過對(duì)
HDFS
上運(yùn)行的目標(biāo)應(yīng)用認(rèn)真考慮的結(jié)果。如果不采用客戶端緩存,由于網(wǎng)絡(luò)速度和網(wǎng)絡(luò)堵塞會(huì)對(duì)吞估量造成比較大的影響。
3
、流水線復(fù)制
???
當(dāng)某個(gè)客戶端向
HDFS
文件寫數(shù)據(jù)的時(shí)候,一開始是寫入本地臨時(shí)文件,假設(shè)該文件的
replication
因子設(shè)置為
3
,那么客戶端會(huì)從
Namenode
獲取一張
Datanode
列表來存放副本。然后客戶端開始向第一個(gè)
Datanode
傳輸數(shù)據(jù),第一個(gè)
Datanode
一小部分一小部分(
4kb)
地接收數(shù)據(jù),將每個(gè)部分寫入本地倉(cāng)庫(kù),并且同時(shí)傳輸該部分到第二個(gè)
Datanode
節(jié)點(diǎn)。第二個(gè)
Datanode
也是這樣,邊收邊傳,一小部分一小部分地收,存儲(chǔ)在本地倉(cāng)庫(kù),同時(shí)傳給第三個(gè)
Datanode
,第三個(gè)
Datanode
就僅僅是接收并存儲(chǔ)了。這就是流水線式的復(fù)制。
九、可訪問性
??? HDFS
給應(yīng)用提供了多種訪問方式,可以通過
DFSShell
通過命令行與
HDFS
數(shù)據(jù)進(jìn)行交互,可以通過
java API
調(diào)用,也可以通過
C
語(yǔ)言的封裝
API
訪問,并且提供了瀏覽器訪問的方式。正在開發(fā)通過
WebDav
協(xié)議訪問的方式。具體使用參考文檔。
十、空間的回收
1
、文件的刪除和恢復(fù)
???
用戶或者應(yīng)用刪除某個(gè)文件,這個(gè)文件并沒有立刻從
HDFS
中刪除。相反,
HDFS
將這個(gè)文件重命名,并轉(zhuǎn)移到
/trash
目錄。當(dāng)文件還在
/trash
目錄時(shí),該文件可以被迅速地恢復(fù)。文件在
/trash
中保存的時(shí)間是可配置的,當(dāng)超過這個(gè)時(shí)間,
Namenode
就會(huì)將該文件從
namespace
中刪除。文件的刪除,也將釋放關(guān)聯(lián)該文件的數(shù)據(jù)塊。注意到,在文件被用戶刪除和
HDFS
空閑空間的增加之間會(huì)有一個(gè)等待時(shí)間延遲。
???
當(dāng)被刪除的文件還保留在
/trash
目錄中的時(shí)候,如果用戶想恢復(fù)這個(gè)文件,可以檢索瀏覽
/trash
目錄并檢索該文件。
/trash
目錄僅僅保存被刪除文件的最近一次拷貝。
/trash
目錄與其他文件目錄沒有什么不同,除了一點(diǎn):
HDFS
在該目錄上應(yīng)用了一個(gè)特殊的策略來自動(dòng)刪除文件,目前的默認(rèn)策略是刪除保留超過
6
小時(shí)的文件,這個(gè)策略以后會(huì)定義成可配置的接口。
2
、
Replication
因子的減小
???
當(dāng)某個(gè)文件的
replication
因子減小,
Namenode
會(huì)選擇要?jiǎng)h除的過剩的副本。下次心跳檢測(cè)就將該信息傳遞給
Datanode
,
Datanode
就會(huì)移除相應(yīng)的
block
并釋放空間,同樣,在調(diào)用
setReplication
方法和集群中的空閑空間增加之間會(huì)有一個(gè)時(shí)間延遲。
參考資料:
HDFS Java API: http://hadoop.apache.org/core/docs/current/api/
HDFS source code: http://hadoop.apache.org/core/version_control.html
???
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
