国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

怎么把網(wǎng)站放到空間嗎教育培訓(xùn)機構(gòu)平臺

怎么把網(wǎng)站放到空間嗎,教育培訓(xùn)機構(gòu)平臺,廈門網(wǎng)站建設(shè)案例,物流企業(yè)網(wǎng)站建設(shè)步驟HDFS分布式文件系統(tǒng) 1.目標 理解分布式思想學(xué)會使用HDFS的常用命令掌握如何使用java api操作HDFS能獨立描述HDFS三大組件namenode、secondarynamenode、datanode的作用理解并獨立描述HDFS讀寫流程HDFS如何解決大量小文件存儲問題 2. HDFS 2.1 HDFS是什么 HDFS是Hadoop中的一…

HDFS分布式文件系統(tǒng)

1.目標

  1. 理解分布式思想
  2. 學(xué)會使用HDFS的常用命令
  3. 掌握如何使用java api操作HDFS
  4. 能獨立描述HDFS三大組件namenode、secondarynamenode、datanode的作用
  5. 理解并獨立描述HDFS讀寫流程
  6. HDFS如何解決大量小文件存儲問題

2. HDFS

2.1 HDFS是什么
  • HDFS是Hadoop中的一個存儲子模塊

  • HDFS (全稱Hadoop Distributed File System),即hadoop的分布式文件系統(tǒng)

  • File System文件系統(tǒng)

    • 操作系統(tǒng)中負責(zé)管理文件、存儲文件信息的軟件;

    • 具體地說,它負責(zé)為用戶創(chuàng)建文件,存入、讀取、修改、轉(zhuǎn)儲、刪除文件等等操作

    • 比如windows下的文件系統(tǒng)

      請?zhí)砑訄D片描述

  • 分布式文件系統(tǒng)(distributed filesystem)

    • 當(dāng)數(shù)據(jù)集大小超出一臺計算機的存儲能力時,就有必要將它拆分成若干部分,然后分散到不同的計算機中存儲。

    • 管理網(wǎng)絡(luò)中跨多臺計算機存儲的文件系統(tǒng)稱之為分布式文件系統(tǒng)

      請?zhí)砑訄D片描述

2.2 HDFS特點

2.2.1 優(yōu)點:

  • 適合存儲大文件,能用來存儲管理PB級的數(shù)據(jù);不適合存儲小文件
  • 存儲非結(jié)構(gòu)化數(shù)據(jù)
  • 流式的訪問數(shù)據(jù),一次寫入、多次讀寫
  • 運行于廉價的商用機器集群上,成本低
  • 高容錯:故障時能繼續(xù)運行且不讓用戶察覺到明顯的中斷
  • 容量可擴展

2.2.2 局限性

  • 不適合處理低延遲數(shù)據(jù)訪問
    • DFS是為了處理大型數(shù)據(jù)集分析任務(wù)的,主要是為達到高的數(shù)據(jù)吞吐量而設(shè)計的
    • 對于低延時的訪問需求,HBase是更好的選擇
  • 無法高效存儲大量的小文件
    • 小文件會給Hadoop的擴展性和性能帶來嚴重問題(How?)
    • 利用SequenceFile、MapFile等方式歸檔小文件(How?)
  • 不支持多用戶寫入及任意修改文件
    • 文件有一個寫入者,只能執(zhí)行追加操作
    • 不支持多個用戶對同一文件的寫操作,以及在文件任意位置進行修改,但支持追加
2.3 小結(jié)
  • HDFS是Hadoop中的分布式文件系統(tǒng)
  • HDFS高容錯
  • 可擴展
  • HDFS適合存儲大文件,不適合存儲小文件
  • 不適合處理低延時的數(shù)據(jù)方問

3. HDFS初體驗

3.1 HDFS命令(20分鐘)

若熟悉基本的linux命令,HDFS學(xué)起來so easy

  • HDFS命令與linux 命令的相似性

  • 參考課件《HDFS命令》

3.2 WEB UI界面

注意:

若在windows下,能夠訪問node01:50070,需要配置C:\Windows\System32\drivers\etc\hosts文件,末尾添加如下三行內(nèi)容

192.168.51.100 node01
192.168.51.110 node02
192.168.51.120 node03

  • 訪問HDFS的web界面,瀏覽器訪問
node01:50070

在這里插入圖片描述

3.3 HDFS編程
  • HDFS java API編程

    • 如何建MAVEN工程:①pom.xml文件;②建包、建類;

    • 如何編寫HDFS讀寫代碼

    • 如何運行代碼:

      • 方式①本地運行(代碼右鍵->run);

      • 方式②打包運行:

      • 如何打包?兩種方式;

      • 方式一(得獨立安裝maven):

        mvn clean package -DskipTests # 在工程目錄下執(zhí)行
        
      • 方式二:利用IDEA打包

      • 運行jar包

        [hadoop@node01 ~]$ hadoop jar com.kaikeba.hadoop-1.0-SNAPSHOT.jar com.kaikeba.hadoop.hdfs.CopyFileFromLocal /kkb/install/hadoop-2.6.0-cdh5.14.2/README.txt /README.txt
        
  • 如何查看官方API文檔
    網(wǎng)址

  • HDFS代碼

    向HDFS上傳文件

    package com.kaikeba.hadoop.hdfs;import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;import java.io.*;
    import java.net.URI;/*** 將本地文件系統(tǒng)的文件通過java-API寫入到HDFS文件*/
    public class CopyFileFromLocal {/*** @param args* args0 windows本地磁盤文件C:/test.txt 或虛擬機本地磁盤文件/kkb/install/hadoop-2.6.0-cdh5.14.2/README.txt* args1 hdfs上文件hdfs://node01:8020/test.txt*/public static void main(String[] args){//本地磁盤路徑String source = args[0];//先確保/data目錄存在String destination = args[1];//HDFS的路徑InputStream in = null;try {in = new BufferedInputStream(new FileInputStream(source));//HDFS讀寫的配置文件Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(destination),conf);//調(diào)用Filesystem的create方法返回的是FSDataOutputStream對象//該對象不允許在文件中定位,因為HDFS只允許一個已打開的文件順序?qū)懭牖蜃芳?/span>OutputStream out = fs.create(new Path(destination));IOUtils.copyBytes(in, out, 4096, true);} catch (FileNotFoundException e) {System.out.println("exception");e.printStackTrace();} catch (IOException e) {System.out.println("exception1");e.printStackTrace();}}
    }
    

    從HDFS下載文件

    package com.kaikeba.hadoop.hdfs;import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.fs.FSDataInputStream;
    import org.apache.hadoop.fs.FileSystem;
    import org.apache.hadoop.fs.Path;
    import org.apache.hadoop.io.IOUtils;import java.io.BufferedOutputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.URI;/*** 從HDFS讀取文件* 打包運行jar包 [bruce@node01 Desktop]$ hadoop jar com.kaikeba.hadoop-1.0-SNAPSHOT.jar  com.kaikeba.hadoop.hdfs.ReadFileFromHDFS*/
    public class ReadFileFromHDFS {/*** @param args* args0 hdfs上文件hdfs://node01:8020/test.txt* args1 windows本地磁盤文件C:/01 HK/高級03班/test01.txt或虛擬機本地磁盤文件*/public static void main(String[] args) {try {//源文件String srcFile = args[0];Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(srcFile),conf);FSDataInputStream hdfsInStream = fs.open(new Path(srcFile));//本地文件BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(args[1]));IOUtils.copyBytes(hdfsInStream, outputStream, 4096, true);} catch (IOException e) {e.printStackTrace();}}
    }
    
3.4 小結(jié)
  • 學(xué)習(xí)HDFS命令,學(xué)會借助help命令

  • 根據(jù)HDFS與linux命令的相似性,舉一反三

  • HDFS API編程時,要學(xué)會查看官方API文檔(不管什么編程都要會查看官方API文檔啊~~~)

4. 核心概念block!!!!

4.1 數(shù)據(jù)塊block

4.1.1 HDFS block塊

  • 向HDFS上傳文件,是按照128M為單位,切分成一個個block,分散的存儲在集群的不同數(shù)據(jù)節(jié)點datanode上

  • 問:HDFS中一個44M大小的block塊會不會占據(jù)128M的空間?

    • 不會
    • 小于128M大小的塊不會占據(jù)128M空間,此例占據(jù)44M
  • 問:這樣存儲有沒有問題?

    • hadoop集群搭建在廉價的商用服務(wù)器上,所以服務(wù)器有出問題的幾率

    在這里插入圖片描述

4.2 block副本
  • 回答上一個問題;因為HDFS是用普通的商用服務(wù)器搭建起來的;所以有節(jié)點出問題的可能性;

  • 那么如果每個block只有一份的話,當(dāng)block所在的節(jié)點宕機后,此block將無法訪問,進而導(dǎo)致文件無法完整讀取

  • 為保正數(shù)據(jù)的可用及容錯,HDFS設(shè)計成每個block共有三份,即三個副本

  • 如何設(shè)置副本數(shù)?

    • replication = 3

    • hdfs-site.xml

    <property><name>dfs.replication</name><value>3</value>
    </property>
    

在這里插入圖片描述

4.3 機架存儲策略
  • 實際機房中,會有機架rack,每個機架上若干服務(wù)器

在這里插入圖片描述

  • 每個block有三個副本;以block1為例
    • 第一副本:在本機器(rack1機架中的datanode1)的HDFS目錄下存儲block1的第一個副本。
    • 第二副本:在不同Rack(如rack2)的某個DataNode(datanode4)上存儲block1的第二個副本。
    • 第三副本:在datanode4所在機架rack2下,找一臺其它的datanode節(jié)點(如datanode5),存儲block1的第三個副本。
    • 能有多副本:隨機節(jié)點

了解下服務(wù)器參數(shù):https://item.jd.com/4564487.html

機架:https://item.jd.com/16829137698.html

4.4 block的一些操作
  • 設(shè)置文件副本數(shù),有什么用?

    • 數(shù)據(jù)分塊存儲和副本的存放,是保證可靠性和高性能的關(guān)鍵

    • 方式一:使用命令設(shè)置文件副本數(shù);動態(tài)生效,不需要重啟hadoop集群

      hadoop fs -setrep -R 4 /path
      
    • 方式二:修改配置文件hdfs-site.xml,需要 重啟hadoop集群才能生效

      <property><name>dfs.replication</name><value>4</value>
      </property>
      
  • HDFS提供了fsck命令,用于檢查HDFS上文件和目錄的健康狀態(tài)、獲取文件的block信息和位置信息

[hadoop@node01 ~]$ hdfs fsck

在這里插入圖片描述

  • 查看文件中損壞的塊
[hadoop@node01 ~]$ hdfs fsck /tmall-201412-1w.csv -list-corruptfileblocks

在這里插入圖片描述

  • 刪除損壞的文件
[hadoop@node01 ~]$ hdfs fsck  /tmall-201412-1w.csv -delete
  • 查看文件的塊基本信息
hdfs fsck /02-041-0029.mp4 -files -blocks -locations

在這里插入圖片描述

4.5 小結(jié)
  • HDFS上的文件分塊存儲
  • 默認每個塊block有3個副本
  • 考慮機架存儲策略
  • 關(guān)于block的一些常用命令:hdfs fsck 這個有時候會用到清理一些損壞的文件

5. HDFS架構(gòu)(重點 40分鐘)

在這里插入圖片描述

  • 大多數(shù)分布式大數(shù)據(jù)框架都是主從架構(gòu)
  • HDFS也是主從架構(gòu)Master|Slave或稱為管理節(jié)點|工作節(jié)點
    • 主叫NameNode,中文稱“名稱節(jié)點”
    • 從叫DataNode,中文稱“數(shù)據(jù)節(jié)點”
5.1 NameNode

5.1.1 文件系統(tǒng)

  • file system文件系統(tǒng):操作系統(tǒng)中負責(zé)管理文件、存儲文件信息的軟件
    • 具體地說,它負責(zé)為用戶創(chuàng)建文件,存入、讀取、修改、轉(zhuǎn)儲、刪除文件等
  • 讀文件 =>>找到文件 =>> 在哪 + 叫啥?
  • 元數(shù)據(jù)
    • 關(guān)于文件或目錄的描述信息,如文件所在路徑、文件名稱、文件類型等等,這些信息稱為文件的元數(shù)據(jù)metadata
    • 注意:元數(shù)據(jù)的概念在其他的大數(shù)據(jù)中也屢有提及
  • 命名空間
    • 文件系統(tǒng)中,為了便于管理存儲介質(zhì)上的內(nèi)容,給每個目錄、目錄中的文件、子目錄都起了名字,這樣形成的層級結(jié)構(gòu),稱之為命名空間
    • 同一個目錄中,不能有同名的文件或目錄
    • 用處:這樣通過目錄+文件名稱的方式能夠唯一的定位一個文件
      在這里插入圖片描述

5.1.2 HDFS-NameNode

  • HDFS本質(zhì)上也是文件系統(tǒng)filesystem,所以它也有元數(shù)據(jù)metadata;
  • HDFS元數(shù)據(jù)metadata保存在NameNode內(nèi)存
  • NameNode作用
    • HDFS的主節(jié)點
    • 負責(zé)管理文件系統(tǒng)的命名空間,將HDFS的元數(shù)據(jù)存儲在NameNode節(jié)點的內(nèi)存中
    • 負責(zé)響應(yīng)客戶端對文件的讀寫請求
  • HDFS元數(shù)據(jù)
    • 文件目錄樹、所有的文件(目錄)名稱、文件屬性(生成時間、副本、權(quán)限)、每個文件的塊列表、每個block塊所在的datanode列表

在這里插入圖片描述

  • 每個文件、目錄、block占用大概150Byte字節(jié)的元數(shù)據(jù);所以HDFS適合存儲大文件,不適合存儲小文件

  • HDFS元數(shù)據(jù)信息以兩種形式保存:①編輯日志edits log②命名空間鏡像文件fsimage

    • edits log:
      • HDFS編輯日志文件 ,保存客戶端對HDFS的所有更改記錄,如增、刪、重命名文件(目錄),這些操作會修改HDFS目錄樹;
      • NameNode會在編輯日志edit日志中記錄下來;
    • fsimage:
      • HDFS元數(shù)據(jù)鏡像文件 ,即將namenode內(nèi)存中的元數(shù)據(jù)落入磁盤生成的文件;
      • 保存了文件系統(tǒng)目錄樹信息以及文件、塊、datanode的映射關(guān)系,如下圖

在這里插入圖片描述

說明:

①為hdfs-site.xml中屬性dfs.namenode.edits.dir的值決定;用于namenode保存edits.log文件

②為hdfs-site.xml中屬性dfs.namenode.name.dir的值決定;用于namenode保存fsimage文件

5.2 DataNode
  • DataNode數(shù)據(jù)節(jié)點的作用
    • 存儲block以及block元數(shù)據(jù)到datanode本地磁盤;
    • 此處的元數(shù)據(jù)包括數(shù)據(jù)塊的長度、塊數(shù)據(jù)的校驗和、時間戳
5.3 SecondaryNameNode
  • 為什么引入SecondaryNameNode

    • 為什么元數(shù)據(jù)存儲在NameNode在內(nèi)存中?這樣做有什么問題?如何解決?

      • HDFS編輯日志文件 editlog:在NameNode節(jié)點中的編輯日志editlog中,記錄下來客戶端對HDFS的所有更改的記錄,如增、刪、重命名文件(目錄);每次更改對應(yīng)一個事務(wù),每個事務(wù)有一個事務(wù)編號;事務(wù)編號遞增

      • 作用:一旦系統(tǒng)出故障,可以根據(jù)editlog恢復(fù)元數(shù)據(jù);

    • 但editlog日志大小會隨著時間變的越來越大,導(dǎo)致系統(tǒng)重啟,根據(jù)日志恢復(fù)元數(shù)據(jù)的時間會越來越長;

    • 為了避免這種情況,引入檢查點機制checkpoint,命名空間鏡像fsimage就是HDFS元數(shù)據(jù)的持久性檢查點,即將內(nèi)存中的元數(shù)據(jù)落磁盤生成的文件;

    • 此時,namenode如果重啟,可以將磁盤中的fsimage文件讀入內(nèi)容,將元數(shù)據(jù)恢復(fù)到某一個檢查點,然后再執(zhí)行檢查點之后記錄的編輯日志editlog,最后完全恢復(fù)元數(shù)據(jù)。

    • 但是依然,隨著時間的推移,editlog記錄的日志會變多,那么當(dāng)namenode重啟,恢復(fù)元數(shù)據(jù)過程中,會花越來越長的時間執(zhí)行editlog中的每一個日志;而在namenode元數(shù)據(jù)恢復(fù)期間,HDFS不可用。

    • 為了解決此問題,引入secondarynamenode輔助namenode,用來合并fsimage及editlog

在這里插入圖片描述

  • SecondaryNameNode定期做checkpoint檢查點操作

    • 創(chuàng)建檢查點checkpoint的兩大條件:
      • SecondaryNameNode每隔1小時創(chuàng)建一個檢查點

      • 另外,Secondary NameNode每1分鐘檢查一次,從上一檢查點開始,edits日志文件中是否已包括100萬個事務(wù),如果是,也會創(chuàng)建檢查點

      • checkpoint相關(guān)屬性(hdfs-site.xml)

    屬性解釋
    dfs.namenode.checkpoint.period3600秒(即1小時)The number of seconds between two periodic checkpoints.
    dfs.namenode.checkpoint.txns1000000The Secondary NameNode or CheckpointNode will create a checkpoint of the namespace every ‘dfs.namenode.checkpoint.txns’ transactions, regardless of whether ‘dfs.namenode.checkpoint.period’ has expired.
    dfs.namenode.checkpoint.check.period60(1分鐘)The SecondaryNameNode and CheckpointNode will poll the NameNode every ‘dfs.namenode.checkpoint.check.period’ seconds to query the number of uncheckpointed transactions.
    • Secondary NameNode首先請求原NameNode進行edits的滾動,這樣新的編輯操作就能夠進入新的文件中

    • Secondary NameNode通過HTTP GET方式讀取原NameNode中的fsimage及edits

    • Secondary NameNode讀取fsimage到內(nèi)存中,然后執(zhí)行edits中的每個操作,并創(chuàng)建一個新的統(tǒng)一的fsimage文件,有ckpt后綴

    • Secondary NameNode通過HTTP PUT方式將新的fsimage發(fā)送到原NameNode

    • 原NameNode用新的fsimage替換舊的fsimage,同時系統(tǒng)會更新fsimage文件到記錄檢查點的時間。

    • 這個過程結(jié)束后,NameNode就有了最新的fsimage文件和更小的edits文件

  • SecondaryNameNode一般部署在另外一臺節(jié)點上

    • 因為它需要占用大量的CPU時間
    • 并需要與namenode一樣多的內(nèi)存,來執(zhí)行合并操作
  • 如何查看edits日志文件

    hdfs oev -i edits_0000000000000000256-0000000000000000363 -o /home/hadoop/edit1.xml
    
  • 如何查看fsimage文件

    hdfs oiv -p XML -i fsimage_0000000000000092691 -o fsimage.xml  
    
5.4 心跳機制

在這里插入圖片描述

工作原理:

  1. NameNode啟動的時候,會開一個ipc server在那里
  2. DataNode啟動后向NameNode注冊,每隔3秒鐘向NameNode發(fā)送一個“心跳heartbeat
  3. 心跳返回結(jié)果帶有NameNode給該DataNode的命令,如復(fù)制塊數(shù)據(jù)到另一DataNode,或刪除某個數(shù)據(jù)塊
  4. 如果超過10分鐘NameNode沒有收到某個DataNode 的心跳,則認為該DataNode節(jié)點不可用
  5. DataNode周期性(6小時)的向NameNode上報當(dāng)前DataNode上的塊狀態(tài)報告BlockReport;塊狀態(tài)報告包含了一個該 Datanode上所有數(shù)據(jù)塊的列表

心跳的作用:

  1. 通過周期心跳,NameNode可以向DataNode返回指令

  2. 可以判斷DataNode是否在線

  3. 通過BlockReport,NameNode能夠知道各DataNode的存儲情況,如磁盤利用率、塊列表;跟負載均衡有關(guān)

  4. hadoop集群剛開始啟動時,99.9%的block沒有達到最小副本數(shù)(dfs.namenode.replication.min默認值為1),集群處于安全模式,涉及BlockReport;

相關(guān)配置項

  • hdfs-default.xml
屬性解釋
dfs.heartbeat.interval3Determines datanode heartbeat interval in seconds. 心跳間隔
dfs.blockreport.intervalMsec21600000 (6小時)Determines block reporting interval in milliseconds. 上傳塊報告時間間隔
  • 查看hdfs-default.xml默認配置文件

在這里插入圖片描述

5.5 負載均衡 start-balancer
  • 什么原因會有可能造成不均衡?

    • 機器與機器之間磁盤利用率不平衡是HDFS集群非常容易出現(xiàn)的情況
    • 尤其是在DataNode節(jié)點出現(xiàn)故障或在現(xiàn)有的集群上增添新的DataNode的時候
  • 為什么需要均衡?

    • 防止熱點出現(xiàn),提升集群存儲資源利用率
    • 從存儲與計算兩方面提高集群性能
  • 如何手動負載均衡?下邊命令無需重啟hadoop

$HADOOP_HOME/sbin/start-balancer.sh -t 5%	# 磁盤利用率最高的節(jié)點若比最少的節(jié)點,大于5%,觸發(fā)均衡
  • 停止負載均衡
$HADOOP_HOME/sbin/stop-balancer.sh
5.6 小結(jié)
  • NameNode負責(zé)存儲HDFS集群的元數(shù)據(jù),存在內(nèi)存中
  • DataNode負責(zé)存儲block塊及塊的元數(shù)據(jù)
  • SecondaryNameNode主要負責(zé)對HDFS元數(shù)據(jù)做checkpoint操作
  • 集群的心跳機制,讓集群中各節(jié)點形成一個整體;主節(jié)點知道從節(jié)點的死活
  • 節(jié)點的上下線,導(dǎo)致存儲的不均衡,可以手動觸發(fā)負載均衡

6. HDFS讀寫流程(重點 30分鐘)

在這里插入圖片描述

6.1 數(shù)據(jù)寫流程

在這里插入圖片描述

在這里插入圖片描述

6.1.1 詳細流程

  • 創(chuàng)建文件:

    • HDFS客戶端向HDFS寫數(shù)據(jù),先調(diào)用DistributedFileSystem.create()方法,在HDFS創(chuàng)建新的空文件
    • RPC(ClientProtocol.create())遠程過程調(diào)用NameNode(NameNodeRpcServer)的create(),首先在HDFS目錄樹指定路徑添加新文件
    • 然后將創(chuàng)建新文件的操作記錄在editslog中
    • NameNode.create方法執(zhí)行完后,DistributedFileSystem.create()返回FSDataOutputStream,它本質(zhì)是封裝了一個DFSOutputStream對象
  • 建立數(shù)據(jù)流管道:

    • 客戶端調(diào)用DFSOutputStream.write()寫數(shù)據(jù)
    • DFSOutputStream調(diào)用ClientProtocol.addBlock(),首先向NameNode申請一個空的數(shù)據(jù)塊
    • addBlock()返回LocatedBlock對象,對象包含當(dāng)前數(shù)據(jù)塊的所有datanode的位置信息
    • 根據(jù)位置信息,建立數(shù)據(jù)流管道
  • 向數(shù)據(jù)流管道pipeline中寫當(dāng)前塊的數(shù)據(jù):

    • 客戶端向流管道中寫數(shù)據(jù),先將數(shù)據(jù)寫入一個檢驗塊chunk中,大小512Byte,寫滿后,計算chunk的檢驗和checksum值(4Byte)
    • 然后將chunk數(shù)據(jù)本身加上checksum,形成一個帶checksum值的chunk(516Byte)
    • 保存到一個更大一些的結(jié)構(gòu)packet數(shù)據(jù)包中,packet為64kB大小
  • packet寫滿后,先被寫入一個dataQueue隊列中

    • packet被從隊列中取出,向pipeline中寫入,先寫入datanode1,再從datanoe1傳到datanode2,再從datanode2傳到datanode3中
  • 一個packet數(shù)據(jù)取完后,后被放入到ackQueue中等待pipeline關(guān)于該packet的ack的反饋

    • 每個packet都會有ack確認包,逆pipeline(dn3 -> dn2 -> dn1)傳回輸出流
  • 若packet的ack是SUCCESS成功的,則從ackQueue中,將packet刪除;否則,將packet從ackQueue中取出,重新放入dataQueue,重新發(fā)送

    • 如果當(dāng)前塊寫完后,文件還有其它塊要寫,那么再調(diào)用addBlock方法(流程同上
  • 文件最后一個block塊數(shù)據(jù)寫完后,會再發(fā)送一個空的packet,表示當(dāng)前block寫完了,然后關(guān)閉pipeline

    • 所有塊寫完,close()關(guān)閉流
  • ClientProtocol.complete()通知namenode當(dāng)前文件所有塊寫完了

6.1.2 容錯

  • 在寫的過程中,pipeline中的datanode出現(xiàn)故障(如網(wǎng)絡(luò)不通),輸出流如何恢復(fù)
    • 輸出流中ackQueue緩存的所有packet會被重新加入dataQueue
    • 輸出流調(diào)用ClientProtocol.updateBlockForPipeline(),為block申請一個新的時間戳,namenode會記錄新時間戳
    • 確保故障datanode即使恢復(fù),但由于其上的block時間戳與namenode記錄的新的時間戳不一致,故障datanode上的block進而被刪除
    • 故障的datanode從pipeline中刪除
    • 輸出流調(diào)用ClientProtocol.getAdditionalDatanode()通知namenode分配新的datanode到數(shù)據(jù)流pipeline中,并使用新的時間戳建立pipeline
    • 新添加到pipeline中的datanode,目前還沒有存儲這個新的block,HDFS客戶端通過DataTransferProtocol通知pipeline中的一個datanode復(fù)制這個block到新的datanode中
    • pipeline重建后,輸出流調(diào)用ClientProtocol.updatePipeline(),更新namenode中的元數(shù)據(jù)
    • 故障恢復(fù)完畢,完成后續(xù)的寫入流程
6.2 數(shù)據(jù)讀流程

6.2.1 基本流程

在這里插入圖片描述

  • 1、client端讀取HDFS文件,client調(diào)用文件系統(tǒng)對象DistributedFileSystem的open方法
  • 2、返回FSDataInputStream對象(對DFSInputStream的包裝)
  • 3、構(gòu)造DFSInputStream對象時,調(diào)用namenode的getBlockLocations方法,獲得file的開始若干block(如blk1, blk2, blk3, blk4)的存儲datanode(以下簡稱dn)列表;針對每個block的dn列表,會根據(jù)網(wǎng)絡(luò)拓撲做排序,離client近的排在前;
  • 4、調(diào)用DFSInputStream的read方法,先讀取blk1的數(shù)據(jù),與client最近的datanode建立連接,讀取數(shù)據(jù)
  • 5、讀取完后,關(guān)閉與dn建立的流
  • 6、讀取下一個block,如blk2的數(shù)據(jù)(重復(fù)步驟4、5、6)
  • 7、這一批block讀取完后,再讀取下一批block的數(shù)據(jù)(重復(fù)3、4、5、6、7)
  • 8、完成文件數(shù)據(jù)讀取后,調(diào)用FSDataInputStream的close方法

6.2.2 容錯

  • 情況一:讀取block過程中,client與datanode通信中斷

    • client與存儲此block的第二個datandoe建立連接,讀取數(shù)據(jù)
    • 記錄此有問題的datanode,不會再從它上讀取數(shù)據(jù)
  • 情況二:client讀取block,發(fā)現(xiàn)block數(shù)據(jù)有問題

    • client讀取block數(shù)據(jù)時,同時會讀取到block的校驗和,若client針對讀取過來的block數(shù)據(jù),計算檢驗和,其值與讀取過來的校驗和不一樣,說明block數(shù)據(jù)損壞
    • client從存儲此block副本的其它datanode上讀取block數(shù)據(jù)(也會計算校驗和)
    • 同時,client會告知namenode此情況;

7. Hadoop HA高可用

7.1 HDFS高可用原理

在這里插入圖片描述

  • 對于HDFS ,NN存儲元數(shù)據(jù)在內(nèi)存中,并負責(zé)管理文件系統(tǒng)的命名空間和客戶端對HDFS的讀寫請求。但是,如果只存在一個NN,一旦發(fā)生“單點故障”,會使整個系統(tǒng)失效。
  • 雖然有個SNN,但是它并不是NN的熱備份
  • 因為SNN無法提供“熱備份”功能,在NN故障時,無法立即切換到SNN對外提供服務(wù),即HDFS處于停服狀態(tài)。
  • HDFS2.x采用了HA(High Availability高可用)架構(gòu)。
    • 在HA集群中,可設(shè)置兩個NN,一個處于“活躍(Active)”狀態(tài),另一個處于“待命(Standby)”狀態(tài)。
    • 由zookeeper確保一主一備(講zookeeper時具體展開)
    • 處于Active狀態(tài)的NN負責(zé)響應(yīng)所有客戶端的請求,處于Standby狀態(tài)的NN作為熱備份節(jié)點,保證與active的NN的元數(shù)據(jù)同步
    • Active節(jié)點發(fā)生故障時,zookeeper集群會發(fā)現(xiàn)此情況,通知Standby節(jié)點立即切換到活躍狀態(tài)對外提供服務(wù)
    • 確保集群一直處于可用狀態(tài)
  • 如何熱備份元數(shù)據(jù):
    • Standby NN是Active NN的“熱備份”,因此Active NN的狀態(tài)信息必須實時同步到StandbyNN。
    • 可借助一個共享存儲系統(tǒng)來實現(xiàn)狀態(tài)同步,如NFS(NetworkFile System)、QJM(Quorum Journal Manager)或者Zookeeper。
    • Active NN將更新數(shù)據(jù)寫入到共享存儲系統(tǒng),Standby NN一直監(jiān)聽該系統(tǒng),一旦發(fā)現(xiàn)有新的數(shù)據(jù)寫入,就立即從公共存儲系統(tǒng)中讀取這些數(shù)據(jù)并加載到Standby NN自己內(nèi)存中,從而保證元數(shù)據(jù)與Active NN狀態(tài)一致。
  • 塊報告:
    • NN保存了數(shù)據(jù)塊到實際存儲位置的映射信息,為了實現(xiàn)故障時的快速切換,必須保證StandbyNN中也包含最新的塊映射信息
    • 因此需要給所有DN配置Active和Standby兩個NN的地址,把塊的位置和心跳信息同時發(fā)送到兩個NN上。

8. Hadoop聯(lián)邦

8.1 為什么需要聯(lián)邦
  • 雖然HDFS HA解決了“單點故障”問題,但HDFS在擴展性、整體性能和隔離性方面仍有問題
    • 系統(tǒng)擴展性方面,元數(shù)據(jù)存儲在NN內(nèi)存中,受限于內(nèi)存上限(每個文件、目錄、block占用約150字節(jié))
    • 整體性能方面,吞吐量受單個NN的影響
    • 隔離性方面,一個程序可能會影響其他程序的運行,如果一個程序消耗過多資源會導(dǎo)致其他程序無法順利運行
    • HDFS HA本質(zhì)上還是單名稱節(jié)點
8.2 聯(lián)邦 (多個命名空間)

在這里插入圖片描述

  • HDFS聯(lián)邦可以解決以上三個問題
    • HDFS聯(lián)邦中,設(shè)計了多個命名空間;每個命名空間有一個NN或一主一備兩個NN,使得HDFS的命名服務(wù)能夠水平擴展
    • 這些NN分別進行各自命名空間namespace和塊的管理,相互獨立,不需要彼此協(xié)調(diào)
    • 每個DN要向集群中所有的NN注冊,并周期性的向所有NN發(fā)送心跳信息和塊信息,報告自己的狀態(tài)
    • HDFS聯(lián)邦每個相互獨立的NN對應(yīng)一個獨立的命名空間
    • 每一個命名空間管理屬于自己的一組塊,這些屬于同一命名空間的塊對應(yīng)一個“塊池”的概念。
    • 每個DN會為所有塊池提供塊的存儲,塊池中的各個塊實際上是存儲在不同DN中的
8.3 擴展

聯(lián)邦-官網(wǎng)

9. 文件壓縮

9.1 壓縮算法
  • 文件壓縮好處:

    • 減少數(shù)據(jù)所占用的磁盤空間
    • 加快數(shù)據(jù)在磁盤、網(wǎng)絡(luò)上的IO
  • 常用壓縮格式

    壓縮格式UNIX工具算 法文件擴展名可分割
    DEFLATEDEFLATE.deflateNo
    gzipgzipDEFLATE.gzNo
    zipzipDEFLATE.zipYES
    bzipbzip2bzip2.bz2YES
    LZOlzopLZO.lzoNo
    SnappySnappy.snappyNo
  • Hadoop的壓縮實現(xiàn)類;均實現(xiàn)CompressionCodec接口

    壓縮格式對應(yīng)的編碼/解碼器
    DEFLATEorg.apache.hadoop.io.compress.DefaultCodec
    gziporg.apache.hadoop.io.compress.GzipCodec
    bzip2org.apache.hadoop.io.compress.BZip2Codec
    LZOcom.hadoop.compression.lzo.LzopCodec
    Snappyorg.apache.hadoop.io.compress.SnappyCodec
  • 查看集群是否支持本地壓縮(所有節(jié)點都要確認)

    [hadoop@node01 ~]$ hadoop checknative
    

    在這里插入圖片描述

9.2 編程實踐
  • 編程:上傳壓縮過的文件到HDFS

    • 對CopyFileFromLocal代碼做修改,向文件壓縮后,再上傳到HDFS
    • 代碼
package com.kaikeba.hadoop.compress;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.compress.BZip2Codec;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.CompressionOutputStream;
import org.apache.hadoop.util.ReflectionUtils;import java.io.*;
import java.net.URI;/**** 將本地文件系統(tǒng)的文件通過java-API寫入到HDFS文件,并且寫入時使用壓縮*/
public class CopyFileFromLocal {/**** @param args 兩個參數(shù) C:\test\01_018分鐘.mp4 hdfs://node01:8020/copyFromLocal/01_018分鐘.bz2* @throws ClassNotFoundException*/public static void main(String[] args) throws ClassNotFoundException {//壓縮相關(guān)//壓縮類//HDFS讀寫的配置文件Configuration conf = new Configuration();BZip2Codec codec = new BZip2Codec();codec.setConf(conf);String source = args[0]; //linux或windows中的文件路徑,demo存在一定數(shù)據(jù)String destination="hdfs://node01:8020/copyFromLocal/01_018分鐘.bz2";//HDFS的路徑InputStream in = null;try {in = new BufferedInputStream(new FileInputStream(source));FileSystem fs = FileSystem.get(URI.create(destination),conf);//調(diào)用Filesystem的create方法返回的是FSDataOutputStream對象//該對象不允許在文件中定位,因為HDFS只允許一個已打開的文件順序?qū)懭牖蜃芳?/span>OutputStream out = fs.create(new Path(destination));//對輸出流的數(shù)據(jù)壓縮CompressionOutputStream compressedOut = codec.createOutputStream(out);//流拷貝IOUtils.copyBytes(in, compressedOut, 4096, true);} catch (FileNotFoundException e) {System.out.println("exception");e.printStackTrace();} catch (IOException e) {System.out.println("exception1");e.printStackTrace();}}
}
  • 擴展閱讀
    • 《Hadoop權(quán)威指南》 5.2章節(jié) 壓縮
    • HDFS文件壓縮

10. 小文件治理

10.1 HDFS不適合存儲小文件
  • NameNode存儲著文件系統(tǒng)的元數(shù)據(jù),每個文件、目錄、塊大概有150字節(jié)的元數(shù)據(jù);
  • NN內(nèi)存有限,因此HDFS存儲文件數(shù)量的也有上限,如果小文件過多則會造成NN的壓力過大
  • 且HDFS能存儲的數(shù)據(jù)總量也會變小
10.2 HAR文件方案(10分鐘)
  • 此方案本質(zhì)啟動mr程序,所以需要啟動yarn

在這里插入圖片描述

用法:hadoop archive -archiveName .har -p [-r ]*

在這里插入圖片描述
在這里插入圖片描述

# 創(chuàng)建archive文件;/testhar有兩個子目錄th1、th2;兩個子目錄中有若干文件
hadoop archive -archiveName test.har -p /testhar -r 3 th1 th2 /outhar # 原文件還存在,需手動刪除# 查看archive文件
hdfs dfs -ls -R har:///outhar/test.har# 解壓archive文件
# 方式一
hdfs dfs -cp har:///outhar/test.har/th1 hdfs:/unarchivef1 # 順序解壓
hadoop fs -ls /unarchivef1	
# 方式二
hadoop distcp har:///outhar/test.har/th1 hdfs:/unarchivef2 # 并行解壓,效率高,啟動MR
10.3 Sequence Files方案 !!!

在這里插入圖片描述

  • SequenceFile文件,主要由一條條record記錄組成;
  • 具體結(jié)構(gòu)(如上圖):
    • 一個SequenceFile首先有一個4字節(jié)的header(文件版本號)
    • 接著是若干record記錄
    • 每個record是鍵值對形式的;鍵值類型是可序列化類型,如IntWritable、Text
    • 記錄間會隨機的插入一些同步點sync marker,用于方便定位到記錄邊界
  • SequenceFile文件可以作為小文件的存儲容器;
    • 每條record保存一個小文件的內(nèi)容
    • 小文件名作為當(dāng)前record的鍵;
    • 小文件的內(nèi)容作為當(dāng)前record的值;
    • 如10000個100KB的小文件,可以編寫程序?qū)⑦@些文件放到一個SequenceFile文件。
  • 一個SequenceFile是可分割的,所以MapReduce可將文件切分成塊,每一塊獨立操作。
  • 不像HAR,SequenceFile支持壓縮。記錄的結(jié)構(gòu)取決于是否啟動壓縮
    • 支持兩類壓縮:
      • 不壓縮NONE,如上圖
      • 壓縮RECORD,如上圖
      • 壓縮BLOCK,如下圖,①一次性壓縮多條記錄;②每一個新塊Block開始處都需要插入同步點
    • 在大多數(shù)情況下,以block(注意:指的是SequenceFile中的block)為單位進行壓縮是最好的選擇
    • 因為一個block包含多條記錄,利用record間的相似性進行壓縮,壓縮效率更高
    • 把已有的數(shù)據(jù)轉(zhuǎn)存為SequenceFile比較慢。比起先寫小文件,再將小文件寫入SequenceFile,一個更好的選擇是直接將數(shù)據(jù)寫入一個SequenceFile文件,省去小文件作為中間媒介.

在這里插入圖片描述

  • 向SequenceFile寫入數(shù)據(jù)
package com.kaikeba.hadoop.sequencefile;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.compress.BZip2Codec;import java.io.IOException;
import java.net.URI;public class SequenceFileWriteNewVersion {//模擬數(shù)據(jù)源;數(shù)組中一個元素表示一個文件的內(nèi)容private static final String[] DATA = {"The Apache Hadoop software library is a framework that allows for the distributed processing of large data sets across clusters of computers using simple programming models.","It is designed to scale up from single servers to thousands of machines, each offering local computation and storage.","Rather than rely on hardware to deliver high-availability, the library itself is designed to detect and handle failures at the application layer","o delivering a highly-available service on top of a cluster of computers, each of which may be prone to failures.","Hadoop Common: The common utilities that support the other Hadoop modules."};public static void main(String[] args) throws IOException {//輸出路徑:要生成的SequenceFile文件名String uri = "hdfs://node01:8020/writeSequenceFile";Configuration conf = new Configuration();FileSystem fs = FileSystem.get(URI.create(uri), conf);//向HDFS上的此SequenceFile文件寫數(shù)據(jù)Path path = new Path(uri);//因為SequenceFile每個record是鍵值對的//指定key類型IntWritable key = new IntWritable(); //key數(shù)字 -> int -> IntWritable//指定value類型Text value = new Text();//value -> String -> Text//創(chuàng)建向SequenceFile文件寫入數(shù)據(jù)時的一些選項//要寫入的SequenceFile的路徑SequenceFile.Writer.Option pathOption       = SequenceFile.Writer.file(path);//record的key類型選項SequenceFile.Writer.Option keyOption        = SequenceFile.Writer.keyClass(IntWritable.class);//record的value類型選項SequenceFile.Writer.Option valueOption      = SequenceFile.Writer.valueClass(Text.class);//SequenceFile壓縮方式:NONE | RECORD | BLOCK三選一//方案一:RECORD、不指定壓縮算法
//        SequenceFile.Writer.Option compressOption   = SequenceFile.Writer.compression(SequenceFile.CompressionType.RECORD);
//        SequenceFile.Writer writer = SequenceFile.createWriter(conf, pathOption, keyOption, valueOption, compressOption);//方案二:BLOCK、不指定壓縮算法
//        SequenceFile.Writer.Option compressOption   = SequenceFile.Writer.compression(SequenceFile.CompressionType.BLOCK);
//        SequenceFile.Writer writer = SequenceFile.createWriter(conf, pathOption, keyOption, valueOption, compressOption);//方案三:使用BLOCK、壓縮算法BZip2Codec;壓縮耗時間//再加壓縮算法BZip2Codec codec = new BZip2Codec();codec.setConf(conf);SequenceFile.Writer.Option compressAlgorithm = SequenceFile.Writer.compression(SequenceFile.CompressionType.RECORD, codec);//創(chuàng)建寫數(shù)據(jù)的Writer實例SequenceFile.Writer writer = SequenceFile.createWriter(conf, pathOption, keyOption, valueOption, compressAlgorithm);for (int i = 0; i < 100000; i++) {//分別設(shè)置key、value值key.set(100000 - i);value.set(DATA[i % DATA.length]); //%取模 3 % 3 = 0;System.out.printf("[%s]\t%s\t%s\n", writer.getLength(), key, value);//在SequenceFile末尾追加內(nèi)容writer.append(key, value);}//關(guān)閉流IOUtils.closeStream(writer);}
}
  • 命令查看SequenceFile內(nèi)容
 hadoop fs -text /writeSequenceFile
  • 讀取SequenceFile文件
package com.kaikeba.hadoop.sequencefile;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.ReflectionUtils;import java.io.IOException;public class SequenceFileReadNewVersion {public static void main(String[] args) throws IOException {//要讀的SequenceFileString uri = "hdfs://node01:8020/writeSequenceFile";Configuration conf = new Configuration();Path path = new Path(uri);//Reader對象SequenceFile.Reader reader = null;try {//讀取SequenceFile的Reader的路徑選項SequenceFile.Reader.Option pathOption = SequenceFile.Reader.file(path);//實例化Reader對象reader = new SequenceFile.Reader(conf, pathOption);//根據(jù)反射,求出key類型對象Writable key = (Writable)ReflectionUtils.newInstance(reader.getKeyClass(), conf);//根據(jù)反射,求出value類型對象Writable value = (Writable)ReflectionUtils.newInstance(reader.getValueClass(), conf);long position = reader.getPosition();System.out.println(position);while (reader.next(key, value)) {String syncSeen = reader.syncSeen() ? "*" : "";System.out.printf("[%s%s]\t%s\t%s\n", position, syncSeen, key, value);//移動到下一個record開頭的位置position = reader.getPosition(); // beginning of next record}} finally {IOUtils.closeStream(reader);}}
}

11. 文件快照(10分鐘)

11.1 什么是快照
  • 快照比較常見的應(yīng)用場景是數(shù)據(jù)備份,以防一些用戶錯誤或災(zāi)難恢復(fù)
  • 快照snapshots是HDFS文件系統(tǒng)的,只讀的、某時間點的拷貝
  • 可以針對某個目錄,或者整個文件系統(tǒng)做快照
  • 創(chuàng)建快照時,block塊并不會被拷貝。快照文件中只是記錄了block列表和文件大小,不會做任何數(shù)據(jù)拷貝
11.2 快照操作
  • 允許快照

    允許一個快照目錄被創(chuàng)建。如果這個操作成功完成,這個目錄就變成snapshottable

    用法:hdfs dfsadmin -allowSnapshot

    hdfs dfsadmin -allowSnapshot /wordcount
    
  • 禁用快照

    用法:hdfs dfsadmin -disallowSnapshot

    hdfs dfsadmin -disallowSnapshot /wordcount
    
  • 創(chuàng)建快照(snapshotDir必須是snapshottable)

    用法:hdfs dfs -createSnapshot []

    #注意:先將/wordcount目錄變成允許快照的
    hdfs dfs -createSnapshot /wordcount wcSnapshot
    
  • 查看快照

    hdfs dfs -ls /wordcount/.snapshot
    

在這里插入圖片描述

  • 重命名快照

    這個操作需要擁有snapshottabl目錄所有者權(quán)限

    用法:hdfs dfs -renameSnapshot

    hdfs dfs -renameSnapshot /wordcount wcSnapshot newWCSnapshot
    
  • 用快照恢復(fù)誤刪除數(shù)據(jù)

    HFDS的/wordcount目錄,文件列表如下

    在這里插入圖片描述

    誤刪除/wordcount/edit.xml文件

    hadoop fs -rm /wordcount/edit.xml
    

    在這里插入圖片描述

    恢復(fù)數(shù)據(jù)

    hadoop fs -cp /wordcount/.snapshot/newWCSnapshot/edit.xml /wordcount
    
  • 刪除快照

    這個操作需要擁有snapshottabl目錄所有者權(quán)限

    用法:hdfs dfs -deleteSnapshot

    hdfs dfs -deleteSnapshot /wordcount newWCSnapshot
    

拓展總結(jié)

  1. HDFS存儲地位

  2. block塊為什么設(shè)置的比較大(面試)

  • 磁盤基礎(chǔ)知識
    • 盤片platter、磁頭head、磁道track、扇區(qū)sector、柱面cylinder
    • 為了最小化尋址開銷;從磁盤傳輸數(shù)據(jù)的時間明顯大于定位這個塊開始位置所需的時間
  • 問:塊的大小是不是設(shè)置的越大越好呢?
    在這里插入圖片描述
  1. 擴展閱讀:《HDFS新特性》

  2. 參考書籍:《Hadoop權(quán)威指南 第4版》

  3. 總結(jié): 在這里插入圖片描述

http://aloenet.com.cn/news/32873.html

相關(guān)文章:

  • 公眾號的微網(wǎng)站開發(fā)營銷型網(wǎng)站建設(shè)排名
  • 南京代做網(wǎng)站濟南百度競價代運營
  • c 做網(wǎng)站如何調(diào)用dll免費源碼網(wǎng)站
  • 公司怎么建立自己網(wǎng)站百度推廣價格價目表
  • php app網(wǎng)站建設(shè)武漢seo管理
  • 藍色大氣網(wǎng)站欣賞視頻推廣平臺
  • 手機企業(yè)網(wǎng)站制作企業(yè)網(wǎng)頁設(shè)計公司
  • 網(wǎng)站建設(shè)夢幻創(chuàng)意百度文庫官網(wǎng)
  • php做的網(wǎng)站安全嗎今天的新聞頭條
  • 什么公司在百度做網(wǎng)站常州seo關(guān)鍵詞排名
  • 做網(wǎng)站實習(xí)日志寧波seo怎么做引流推廣
  • 陽泉購物網(wǎng)站開發(fā)設(shè)計市場營銷策劃
  • 網(wǎng)站網(wǎng)絡(luò)廣告如何建設(shè)自助建站免費搭建個人網(wǎng)站
  • 織夢網(wǎng)站后臺關(guān)鍵詞推廣優(yōu)化app
  • 婚禮顧問網(wǎng)站介紹模版有哪些營銷推廣方式
  • 用php做動態(tài)網(wǎng)站嗎企業(yè)中層管理人員培訓(xùn)課程
  • 手機網(wǎng)站內(nèi)容模塊如何進行網(wǎng)站宣傳推廣
  • 58網(wǎng)站怎么做優(yōu)化迅雷磁力鏈bt磁力種子
  • 合肥疫情風(fēng)險等級思億歐seo靠譜嗎
  • 天津企業(yè)網(wǎng)站建站做一個公司網(wǎng)站大概要多少錢
  • 用自己電腦做網(wǎng)站的空間百度自媒體注冊入口
  • 南寧seo費用服務(wù)短視頻seo系統(tǒng)
  • 黨政機關(guān)如何建設(shè)網(wǎng)站企業(yè)推廣網(wǎng)絡(luò)營銷外包服務(wù)
  • 做網(wǎng)站如何與美工配合日本比分預(yù)測
  • 網(wǎng)站開發(fā)速成班網(wǎng)絡(luò)軟文怎么寫
  • 天津建設(shè)工程信息網(wǎng) 官網(wǎng)首頁seo排名點擊器曝光行者seo
  • 鄂州做網(wǎng)站公司推廣營銷軟件app
  • 建設(shè)銀行梅州分行網(wǎng)站廈門seo怎么做
  • 武漢 網(wǎng)站制作案例北京建站
  • 平頂山網(wǎng)站建設(shè)費用競價排名是什么