A、HDFSの概要
預金を下回らないの管轄下で、より多くの、オペレーティングシステムの範囲内のデータの量は、その後、より多くのディスク・オペレーティング・システムの管理に配信が、管理し、維持するために便利ではない、複数のマシンを管理するためのシステムのための緊急の必要性があります分散ファイルシステム管理でファイル。
複数のユーザーが複数のマシンとストレージスペース間でファイルを共有することを可能にする複数のホストファイルシステム上のファイル共有を可能にするネットワークです。
透水性。だから、そのアクションは、一般的には、ローカルディスクへのアクセスなどのネットワーク経由でファイルにアクセスし、ユーザーの視点でプログラムに実際にあります。
フォールトトレランス。そこにいくつかのシステムノードでダウンした場合でも、システム全体がまだ[]に実装されているデータ複製メカニズムを失うことなく動作し続けることができます。
多くの分散ファイル管理システム、HDFSただ一つ、不適切な小さなファイル。
HDFS構造
二、名前ノード
名前ノードの管理ノードは、ファイルシステム全体です。これは、ファイルシステム全体のファイル、ディレクトリツリー内のデータ・ブロック、メタ情報ファイル/ディレクトリ、および各ファイル対応のリストを保持します。ユーザの操作要求を受信します。
ドキュメントが含まれます:
fsimage:メタデータミラーファイル。メタデータ情報の名前ノード期間を格納するメモリ。
編集:操作ログファイルには、いくつかの名前ノードの後に新しいメタ情報ログを開始します。
fstime:保存時間最後のチェックポイント
これらのファイルは、Linuxのファイルシステムに保存されます。
dfs.namenode.name.dirのHDFS-site.xmlの性質
三、DataNode
ファイルストレージサービスは、実際のデータを提供します。
ファイルのブロック(ブロック):ストレージの最も基本的な単位。ファイルコンテンツのために、長さのファイルサイズがサイズで、オフセット0から開始し、ファイル、固定サイズ、ファイルが分割され、注文番号、前記各ブロックのブロックの良い分割。2.0後HDFSデフォルトブロックサイズは128メガバイトであり、256/128 = 2ブロックの合計256MBのファイル。
dfs.blocksizeでHDFS-site.xmlの性質
ファイルは、データブロックのサイズよりも小さい場合、それは通常のファイルシステムとは異なり、HDFSは、データのブロック全体は、ストレージスペースの複製を取りません。マルチレプリカ。デフォルトは3です。
dfs.replicationのHDFS-site.xmlの性質
四、クライアントがマルチコピーファイルのプロセスを読みます
ファイブ、HDFSのゴミ箱
そして、Linux(デスクトップ環境)ごみ箱に設計され、HDFSは、ユーザーごとにごみ箱に作成されますよう:/ユーザー/ユーザー名/.Trash/を、各ユーザはシェル削除ファイル/ディレクトリであり、fs.trash .intervalは、この期間内に回復手段であり、ファイルが実際にすぐにデータをオフに削除するのではなく、このディレクトリをゴミ箱に移動されます。実際に回復期間の後、HDFSは、実際にデータが削除されますまで待ちます。デフォルトの単位は分、1440分= 60 * 24、たった一日です。構成:各ノード(だけでなく、プライマリノード)で加え設定コアsite.xmlの、以下を追加
<プロパティ>
<名前> fs.trash.interval </名前>
<値> 1440 </ value>の
</プロパティ>
注:大きすぎるファイルを削除した場合、より多くのごみ箱のサイズよりも、失敗したを削除するよう求めるメッセージが表示されます
あなたは、パラメータを指定する必要があり-skipTrash
六、HDFS動作するJavaコード(またはIDEAのMyEclipseは、本明細書中に可能であるか、または日食使用しました)
1、Mavenのプロジェクトを作成します
2、保存、で依存性に関するこれらのいくつかの質問を追加する、のpom.xmlファイルを変更します。
1 <dependency> 2 <groupId>junit</groupId> 3 <artifactId>junit</artifactId> 4 <version>4.11</version> 5 <scope>test</scope> 6 </dependency> 7 8 <dependency> 9 <groupId>mysql</groupId> 10 <artifactId>mysql-connector-java</artifactId> 11 <version>5.1.17</version> 12 </dependency> 13 14 <dependency> 15 <groupId>org.apache.hadoop</groupId> 16 <artifactId>hadoop-common</artifactId> 17 <version>2.6.0</version> 18 </dependency> 19 20 <dependency> 21 <groupId>org.apache.hadoop</groupId> 22 <artifactId>hadoop-client</artifactId> 23 <version>2.6.0</version> 24 </dependency> 25 26 <dependency> 27 <groupId>org.apache.hadoop</groupId> 28 <artifactId>hadoop-hdfs</artifactId> 29 <version>2.6.0</version> 30 </dependency>
3、编写Java代码,连接到HDFS(我这里没有导包,注意不要导错包,Hadoop下的)
1 public class hdfsDemo2 { 2 public static void main(String[] args) throws Exception { 3 // 4 URI uri = new URI("hdfs://192.168.230.50:9000"); //输入你的namenode的节点信息 5 Configuration conf = new Configuration(); 6 FileSystem fs = FileSystem.get(uri, conf); 7 // method2(fs); 8 9 method1(fs); 10 }
4、简单的操作,对HDFS创建文件夹以及删除文件夹
1 import org.apache.hadoop.conf.Configuration; 2 import org.apache.hadoop.fs.FSDataInputStream; 3 import org.apache.hadoop.fs.FileSystem; 4 import org.apache.hadoop.fs.Path; 5 6 import java.io.*; 7 import java.net.URI; 8 9 public class hdfsDemo2 { 10 public static void main(String[] args) throws Exception { 11 // 12 URI uri = new URI("hdfs://192.168.230.50:9000"); 13 Configuration conf = new Configuration(); 14 FileSystem fs = FileSystem.get(uri, conf); 15 // method2(fs); 16 17 method1(fs); 18 } 19 20 21 22 private static void method2(FileSystem fs) throws IOException { 23 boolean b1 = fs.mkdirs(new Path("/data/")); 24 System.out.println(b1); 25 26 boolean b2 = fs.delete(new Path("/data/"),true); 27 System.out.println(b2); 28 } 29 30 31 32 private static void method1(FileSystem fs) throws IOException, UnsupportedEncodingException, FileNotFoundException { 33 //从hdfs上读取数据 34 FSDataInputStream in = fs.open(new Path("/usr/test/empldata.csv")); 35 BufferedReader br = new BufferedReader(new InputStreamReader(in, "utf-8")); 36 String line = null; 37 while((line=br.readLine())!=null){ 38 System.out.println(line); 39 } 40 in.close(); 41 42 //从本地上传到hdfs上面 43 /*FileInputStream fi = new FileInputStream("F:\\新桌面\\dianxin_data"); 44 FSDataOutputStream fo = fs.create(new Path("/usr/test/hdfstest.txt")); 45 IOUtils.copyBytes(fi, fo, 1024, true);*/ 46 } 47 }
七、将HDFS的文件读出到JVM,再存入到Mysql数据库中
1、先在数据库中建表并插入数据
1 DROP TABLE IF EXISTS `emp`; 2 CREATE TABLE `emp` ( 3 `EMPNO` int(4) NOT NULL, 4 `ENAME` varchar(10) DEFAULT NULL, 5 `JOB` varchar(9) DEFAULT NULL, 6 `MGR` varchar(10) DEFAULT NULL, 7 `HIREDATE` date DEFAULT NULL, 8 `SAL` int(7) DEFAULT NULL, 9 `COMM` int(7) DEFAULT NULL, 10 `DEPTNO` int(2) DEFAULT NULL, 11 PRIMARY KEY (`EMPNO`) 12 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 13 字段中文名字依次是:工号,姓名,工作岗位,部门经理,受雇日期,薪金,奖金,部门编号 14 insert into `emp`(`EMPNO`,`ENAME`,`JOB`,`MGR`,`HIREDATE`,`SAL`,`COMM`,`DEPTNO`) values 15 ('7369','SMITH','CLERK','7902','1980-12-17','800',null,'50'), 16 ('7499','ALLEN','SALESMAN','7698','1981-02-20','1600','300','50'), 17 ('7521','WARD','SALESMAN','7698','1981-02-22','1250','500','30'), 18 ('7566','JONES','MANAGER','7839','1981-04-02','2975',null,'20'), 19 ('7654','MARTIN','SALESMAN','7698','1981-09-28','1250','1400','30'), 20 ('7698','BLAKE','MANAGER','7839','1981-05-01','2850',null,'30'), 21 ('7782','CLARK','MANAGER','7839','1981-06-09','2450',null,'10'), 22 ('7788','SCOTT','ANALYST','7566','1987-04-19','3000',null,'20'), 23 ('7839','KING','PRESIDENT',null,'1981-11-17','5000',null,'10'), 24 ('7844','TURNER','SALESMAN','7698','1981-09-08','1500','0','30'), 25 ('7876','ADAMS','CLERK','7788','1987-05-23','1100',null,'20'), 26 ('7900','JAMES','CLERK','7698','1981-12-03','950',null,'30'), 27 ('7902','FORD','ANALYST','7566','1981-12-03','3000',null,'20'), 28 ('7934','MILLER','CLERK','7782','1982-01-23','1300',null,'10'); 29 30 DROP TABLE IF EXISTS `dept`; 31 CREATE TABLE `dept` ( 32 `DEPTNO` int(2) NOT NULL, 33 `DNAME` varchar(14) DEFAULT NULL, 34 `LOC` varchar(13) DEFAULT NULL, 35 PRIMARY KEY (`DEPTNO`) 36 ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 37 38 insert into `dept`(`DEPTNO`,`DNAME`,`LOC`) values 39 ('10','ACCOUNTING','NEW YORK'), 40 ('20','RESEARCH','DALLAS'), 41 ('30','SALES','CHICAGO'), 42 ('40','OPERATIONS','BOSTON');
2、我将要插入的数据:
1 7369,SMITH,CLERK,7902,1980-12-17,800,null,20 2 7499,ALLEN,SALESMAN,7698,1981-02-20,1600,300,30 3 7521,WARD,SALESMAN,7698,1981-02-22,1250,500,30 4 7566,JONES,MANAGER,7839,1981-04-02,2975,null,20), 5 7654,MARTIN,SALESMAN,7698,1981-09-28,1250,1400,30 6 7698,BLAKE,MANAGER,7839,1981-05-01,2850,null,30 7 7782,CLARK,MANAGER,7839,1981-06-09,2450,null,10 8 7788,SCOTT,ANALYST,7566,1987-04-19,3000,null,20 9 7839,KING,PRESIDENT,null,1981-11-17,5000,null,10 10 7844,TURNER,SALESMAN,7698,1981-09-08,1500,0,30 11 7876,ADAMS,CLERK,7788,1987-05-23,1100,null,20 12 7900,JAMES,CLERK,7698,1981-12-03,950,null,30 13 7902,FORD,ANALYST,7566,1981-12-03,3000,null,20 14 7934,MILLER,CLERK,7782,1982-01-23,1300,null,10
3、先将数据文件通过命令 hadoop fs -put 上传到HDFS中去。
4、编写Java代码
1 import org.apache.hadoop.conf.Configuration; 2 import org.apache.hadoop.fs.FSDataInputStream; 3 import org.apache.hadoop.fs.FileSystem; 4 import org.apache.hadoop.fs.Path; 5 6 import java.io.BufferedReader; 7 import java.io.InputStreamReader; 8 import java.net.URI; 9 import java.sql.Connection; 10 import java.sql.DriverManager; 11 import java.sql.Statement; 12 13 public class hdfsDemo { 14 public static void main(String[] args) throws Exception{ 15 16 //hdfs的配置 17 URI uri = new URI("hdfs://192.168.230.50:9000"); 18 Configuration conf = new Configuration(); 19 FileSystem fs = FileSystem.get(uri,conf); 20 21 //mysql的配置 22 Class.forName("com.mysql.jdbc.Driver"); 23 Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.230.50:3306/test", "root", "123456"); 24 System.out.println(conn); 25 Statement st = conn.createStatement(); 26 27 FSDataInputStream fdis = fs.open(new Path("/usr/test/empldata.csv")); 28 BufferedReader br = new BufferedReader(new InputStreamReader(fdis)); 29 String line = null; 30 while((line = br.readLine())!=null){ 31 String[] split = line.split(","); 32 String EMPNO = split[0]; 33 String ENAME = split[1]; 34 String JOB = split[2]; 35 String MGR = split[3]; 36 String HIREDATE = split[4]; 37 String SAL = split[5]; 38 String COMM = split[6]; 39 String DEPTNO = split[7]; 40 41 String sql = "insert into test.emp(EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values " + 42 "("+"'"+EMPNO+"'"+","+"'"+ENAME+"'"+","+"'"+JOB+"'"+","+"'"+MGR+"'"+","+"'"+HIREDATE+"'"+","+"'"+SAL+"'"+","+"'"+COMM+"'"+","+"'"+DEPTNO+"'"+")"; 43 System.out.println(sql); 44 st.execute(sql); 45 } 46 47 48 fdis.close(); 49 conn.close(); 50 51 52 53 } 54 }
八、数据存储->读文件(重要!!!)
读文件流程分析:
1.首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例
2.DistributedFileSystem通过rpc获得文件的第一个block的locations,同一block按照副本数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面.
3.前两步会返回一个FSDataInputStream对象,该对象会被封装成DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode并连接。
4.数据从datanode源源不断的流向客户端。
5.如果第一块的数据读完了,就会关闭指向第一块的datanode连接,接着读取下一块。这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流。
6.如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。
如果在读数据的时候,DFSInputStream和datanode的通讯发生异常,就会尝试正在读的block的排第二近的datanode,并且会记录哪个datanode发生错误,剩余的blocks读的时候就会直接跳过该datanode。DFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后DFSInputStream在其他的datanode上读该block的镜像
该设计的方向就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanode,namenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。
九、数据存储->写文件(重要!!!)
1.客户端通过调用DistributedFileSystem的create方法创建新文件
2.DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件,创建前,namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,namenode就会记录下新文件,否则就会抛出IO异常.
3.前两步结束后会返回FSDataOutputStream的对象,象读文件的时候相似,FSDataOutputStream被封装成DFSOutputStream.DFSOutputStream可以协调namenode和datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列data quene。 4.DataStreamer会去处理接受data queue,他先问询namenode这个新的block最适合存储的在哪几个datanode里,比如副本数是3,那么就找到3个最适合的datanode,把他们排成一个pipeline.DataStreamer把packet按队列输出到管道的第一个datanode中,第一个datanode又把packet输出到第二个datanode中,以此类推。
5.DFSOutputStream还有一个对列叫ack queue,也是有packet组成,等待datanode的收到响应,当pipeline中的所有datanode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。 如果在写的过程中某个datanode发生错误,会采取以下几步:1) pipeline被关闭掉;2)为了防止丢包ack queue里的packet会同步到data queue里;3)把产生错误的datanode上当前在写但未完成的block删掉;4)block剩下的部分被写到剩下的两个正常的datanode中;5)namenode找到另外的datanode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。
6.客户端完成写数据后调用close方法关闭写入流
7.DataStreamer把剩余得包都刷到pipeline里然后等待ack信息,收到最后一个ack后,通知datanode把文件标示为已完成。