首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 18)——有几个分支语句?

分支语句又称条件语句,Swift编程语言提供了if、switch和guard三种分支语句。 if语句 由if语句引导的选择结构有if结构、if-else结构和else-if结构3种。 if结构示例代码如下: 1 2 3 4 5 varscore= 95 if score>= 85 { print( "您真优秀!" ) } 程序运行结果如下: 您真优秀! if-else结构示例代码如下: 1 2 3 4 5 6 7 varscore= 95 if score< 60 { print( "不及格" ) } else { print( "及格" ) } 程序运行结果如下: 及格 else-if结构示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 lettestscore= 76 vargrade:Character if testscore>= 90 { grade= "A" } else if testscore>= 80 { grade= "B" } else if testscore>= 70 { grade= "C" } else if testscore>= 60 { grade= "D" } else { grade= "F" } print( "Grade=\(grade)" ) 输出结果如下: Grade = C switch语句 switch语句也称开关语句,它提供多分支程序结构。 switch语句基本形式示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 lettestscore= 86 vargrade:Character switchtestscore/ 10 { case 9 : grade= "优" case 8 : grade= "良" case 7 , 6 : grade= "中" default : grade= "差" } print( "Grade=\(grade)" ) 输出结果如下: Grade =良 guard语句 guard语句是Swift 2.0新添加的关键字,它与if语句非常类似,它设计的目的是提高程序的可读性。 guard语句必须带有else语句,它的语法如下: guard条件表达式else{ 跳转语句 } 语句组 当条件表达式为true时候跳过else语句中的内容,执行语句组内容。条件表达式为false时候执行else语句中的内容,跳转语句一般是return、break、continue和throw。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1746243,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop Hive概念学习系列之hive的索引及案例(八)

hive里的索引是什么? 索引是标准的数据库技术,hive 0.7版本之后支持索引。Hive提供有限的索引功能,这不像传统的关系型数据库那样有“键(key)”的概念,用户可以在某些列上创建索引来加速某些操作,给一个表创建的索引数据被保存在另外的表中。 Hive的索引功能现在还相对较晚,提供的选项还较少。但是,索引被设计为可使用内置的可插拔的java代码来定制,用户可以扩展这个功能来满足自己的需求。 当然不是说有的查询都会受惠于Hive索引。用户可以使用EXPLAIN语法来分析HiveQL语句是否可以使用索引来提升用户查询的性能。像RDBMS中的索引一样,需要评估索引创建的是否合理,毕竟,索引需要更多的磁盘空间,并且创建维护索引也会有一定的代价。 用户必须要权衡从索引得到的好处和代价。 Hive的索引目的是什么? Hive的索引目的是提高Hive表指定列的查询速度。 没有索引时,类似'WHERE tab1.col1= 10' 的查询,Hive会加载整张表或分区,然后处理所有的rows。但是如果在字段col1上面存在索引时,那么只会加载和处理文件的一部分。与其他传统数据库一样,增加索引在提升查询速度时,会消耗额外资源去创建索引和需要更多的磁盘空间存储索引。 Hive 0.7.0版本中,加入了索引。Hive 0.8.0版本中增加了bitmap索引。 如何在hive里创建索引? 说明:索引测试表是user,索引是user_index。 步骤一:先创建索引测试表 create table user( id int, name string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE; 步骤二:往索引测试表里导入数据 LOAD DATA LOCAL INPATH '/export1/tmp/wyp/row.txt' OVERWRITE INTO TABLE user; 步骤三:给索引测试表,创建索引之前测试 SELECT * FROM user where id =500000; 默认会去,加载整张表或分区,然后处理所有的rows。 Total MapReduce jobs = 1 Launching Job 1 out of 1 ....... Ended Job = job_1384246387966_0247 MapReduce Jobs Launched: Job 0: Map: 2 Cumulative CPU: 5.63 sec HDFS Read: 361084006 HDFS Write: 357 SUCCESS Total MapReduce CPU Time Spent: 5 seconds 630 msec OK 500000 wyp.Time taken: 14.107 seconds, Fetched: 1 row(s) 可以看出,一共用了14.107s。 步骤四:对索引测试表,创建索引,即这里是在表的属性id上,创建索引 hive > CREATE INDEX user_index ON TABLE user(id) //索引一定是建立在某个属性或某些属性上的 > AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' > WITH deferred REBUILD > IN TABLE user_index_table; 或者 CREATE INDEX user_index ON TABLE user(id) AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH deferred REBUILD IN TABLE user_index_table; 这样就对索引测试表user创建好了一个索引。索引名字为user_index。创建索引后的表命名为, user_index_table。 步骤五: 填充索引测试表的索引数据 ALTER INDEX user_index on user REBUILD; 步骤六:查看下创建索引后的表的内容 hive> SELECT * FROM user_index_table LIMIT 5; 0 hdfs://mycluster/user/hive/warehouse/table02/000000_0 [0] 1 hdfs://mycluster/user/hive/warehouse/table02/000000_0 [352] 2 hdfs://mycluster/user/hive/warehouse/table02/000000_0 [704] 3 hdfs://mycluster/user/hive/warehouse/table02/000000_0 [1056] 4 hdfs://mycluster/user/hive/warehouse/table02/000000_0 [1408] Time taken: 0.244 seconds, Fetched: 5 row(s) 步骤七:对创建索引后的user再进行测试 hive> select * from user where id =500000; 在表user的字段id上面存在索引时,那么只会加载和处理文件的一部分。 Total MapReduce jobs = 1 Launching Job 1 out of 1 ... MapReduce Total cumulative CPU time: 5 seconds 630 msec Ended Job = job_1384246387966_0247 MapReduce Jobs Launched: Job 0: Map: 2 Cumulative CPU: 5.63 sec HDFS Read: 361084006 HDFS Write: 357 SUCCESS Total MapReduce CPU Time Spent: 5 seconds 630 msec OK 500000 wyp.Time taken: 13.042 seconds, Fetched: 1 row(s) 可以看出,明显加快了些。 扩展 若在Hive创建索引还存在bug:如果表格的模式信息来自SerDe,Hive将不能创建索引: hive> CREATE INDEX employees_index > ON TABLE employees (country) > AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' > WITH DEFERRED REBUILD > IDXPROPERTIES ('creator' = 'me','created_at' = 'some_time') > IN TABLE employees_index_table > COMMENT 'Employees indexed by country and name.'; FAILED: Error in metadata: java.lang.RuntimeException: \ Check the index columns, they should appear in the table being indexed. FAILED: Execution Error, return code 1 from \ org.apache.hadoop.hive.ql.exec.DDLTask 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/6104090.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 50)——扩展计算属性、方法

可以在原始类型上扩展计算属性,包括实例计算属性和静态计算属性。添加计算属性的定义,与普通的计算属性的定义是一样的。 实例计算属性示例:在网络编程时,为了减少流量,从服务器端返回的不是信息描述,而是编码,然后在本地再将编码转换为描述信息。为此定义了如下Int类型扩展: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 extensionInt{ //定义Int类型的扩展 varerrorMessage:String{ //只读计算属性 varerrorStr= "" switch (self){ case - 7 : errorStr= "没有数据。" case - 6 : errorStr= "日期没有输入。" case - 5 : errorStr= "内容没有输入。" case - 4 : errorStr= "ID没有输入。" case - 3 : errorStr= "据访问失败。" case - 2 : errorStr= "您的账号最多能插入10条数据。" case - 1 : errorStr= "用户不存在,请到http://51work6.com注册。" default : errorStr= "" } return errorStr } } letmessage=(- 7 ).errorMessage //获得-7编码对应的描述信息 print( "ErrorCode:-7,ErrorMessage:\(message)" ) 注意整个-7包括负号是一个完整的实例,因此调用它的属性时需要将-7作为一个整体用小括号括起来。然而,如果是7则不需要括号。 下面再看一个静态属性的示例: 1 2 3 4 5 6 7 8 9 10 11 12 structAccount{ //定义Account结构体 varamount:Double= 0.0 //账户金额 varowner:String= "" //账户名 } extensionAccount{ //定义Account结构体的扩展静态 static varinterestRate:Double{ //利率 return0. 0668 } } print(Account.interestRate) //打印输出interestRate属性 打印输出interestRate属性,访问方式与其他的静态计算属性一样,通过“类型名”加“.”来访问静态计算属性。 扩展方法 可以在原始类型上扩展方法,包括实例方法和静态方法。这些添加方法的定义与普通方法的定义是一样的。 下面先看一个示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 extensionDouble{ //定义Double类型的扩展 static varinterestRate:Double= 0.0668 //利率 funcinterestBy1()->Double{ return self*Double.interestRate //静态属性利率 } mutatingfuncinterestBy2(){ //定义实例方法interestBy2 self=self*Double.interestRate } static funcinterestBy3(amount:Double)->Double{ //定义静态方法interestBy3 return interestRate*amount //返回值是计算利息结果 } } letinterest1=(10_000. 00 ).interestBy1() //调用interestBy1方法计算利息 print( "利息1:\(interest1)" ) varinterest2=10_000. 00 //调用interestBy2方法计算利息 interest2.interestBy2() print( "利息2:\(interest2)" ) varinterest3=Double.interestBy3(10_000. 00 ) //调用interestBy3方法计算利息 print( "利息3:\(interest3)" ) 代码self = self *Double.interestRate,把计算结果直接赋值给当前实例self。在结构体和枚举类型中给self赋值会有编译错误,需要在方法前面加上mutating关键字,表明这是变异方法。 调用interestBy1方法计算利息,调用它的实例10_000.00,它的返回值被赋值给interest1常量,这是很常见的调用过程。 调用interestBy2方法计算利息,我们不能使用10_000.00实例调用,而是需要一个Double类型的变量interest2。interestBy2是变异方法,它会直接改变变量interest2的值,因此interest2.interestBy2()语句调用完成后,变量interest2的值就改变了。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1747538,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 24)——枚举(Day 24)——枚举

Swift中的枚举可以定义一组常量、提高程序的可读性;还具有面向对象特性。 使用enum关键词声明枚举类型,具体定义放在一对大括号内,枚举的语法格式如下: enum枚举名 { 枚举的定义 } “枚举名”是该枚举类型的名称。它首先应该是有效的标识符,其次应该遵守面向对象的命名规范,它由一组成员值和一组相关值组成。 成员值 枚举的成员值默认情况下不是整数类型,以下代码是声明枚举示例: 1 2 3 4 5 6 7 enum WeekDays{ case Monday case Tuesday case Wednesday case Thursday case Friday } 在这些成员值前面要加上case关键字,也可以将多个成员值放在同一行,用逗号隔开,如下所示: 1 2 3 enum WeekDays{ case Monday,Tuesday,Wednesday,Thursday,Friday } 下面我们看一个示例,代码如下: 1 2 3 varday=WeekDays.Friday day=WeekDays.Wednesday day=.Monday 使用枚举成员赋值时候,我们可以采用完整的“枚举类型名.成员值”的形式,也可以省略枚举类型采用“.成员值”的形式。这种省略形式能够访问的前提是,Swift编译器能够根据上下文环境推断类型。因为我们已经在第1行和第2行给day变量赋值,所以即使第3行代码采用缩写,Swift编译器能够推断出数据类型是WeekDays。 原始值 出于业务上的需要,要为每个成员提供某种基本数据类型,我们可以为枚举类型提供原始值(raw values)声明,这些原始值类型可以是:字符、字符串、整数和浮点数等。 原始值枚举的语法格式如下: 1 2 3 4 5 enum 枚举名:数据类型 { case 成员名=默认值 ... } 在“枚举名”后面跟“:”和“数据类型”就可以声明原始值枚举的类型,然后在定义case成员的时候需要提供原始值。 以下代码是声明枚举示例: 1 2 3 4 5 6 7 enum WeekDays:Int{ case Monday= 0 case Tuesday= 1 case Wednesday= 2 case Thursday= 3 case Friday= 4 } 我们声明的WeekDays枚举类型的原始值类型是Int,需要给每个成员赋值,只要是Int类型都可以,但是每个分支不能重复。 相关值 在Swift中除了可以定义一组成员值,还可以定义一组相关值(associated values),它有点类似于C中的联合类型。下面看一个枚举类型的声明: 1 2 3 4 enum Figure{ case Rectangle(Int,Int) case Circle(Int) } 枚举类型Figure(图形)有两个相关值:Rectangle(矩形)和Circle(圆形)。Rectangle和Circle是与Figure有关联的相关值,它们都是元组类型,对于一个特定的Figure实例,只能是其中一个相关值。从这一点来看,枚举类型的相关值类似于C中的联合类型。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1746420,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day54)——抛出错误

能放到try后面调用函数或方法都是有要求的,他们是有可能抛出错误,在这些函数或方法声明的参数后面要加上throws关键字,表示这个函数或方法可以抛出错误。 声明抛出错误方法示例代码如下: 1 2 3 4 5 6 7 8 //删除Note记录方法 funcremove(model:Note) throws { ... } //查询所有记录数据方法 funcfindAll() throws ->[Note]{ ... } 上述代码remove(_:)方法没有返回值,throws关键字放到参数后面。findAll()有返回值throws关键字放到参数和返回值类型之间。 在函数或方法中抛出错误 一个函数或方法能够声明抛出错误,是因为在函数或方法中产生并抛出了错误,这样函数或方法声明抛出错误才有实际的意义。 在产生并抛出错误方式: 在函数或方法中通过throw语句,人为地抛出错误。 在函数或方法中调用的其他可以抛出错误函数或方法,但是没有捕获处理,会导致错误被传播出来。 示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 //删除Note方法 funcremove(model:Note) throws { guardletdate=model.date else { //判断抛出时候是有了guard语句 //抛出"主键为空"错误 throw DAOError.PrimaryKeyNull } //比较日期主键是否相等 for (index,note)inlistData.enumerate()wherenote.date==date{ listData.removeAtIndex(index) } } //查询所有数据方法 funcfindAll() throws ->[Note]{ guardlistData.count> 0 else { //判断抛出时候是有了guard语句 //抛出"没有数据"错误。 throw DAOError.NoData } return listData } funcprintNotes() throws { //声明抛出错误 letdatas= try findAll() for noteindatas{ print( "date:\(note.date!)-content:\(note.content!)" ) } } try printNotes() guard语句最擅长处理这种早期判断,条件为false情况下抛出错误。 findAll()语句本身有可能产生错误,但是并没有使用catch语句捕获并处理,这样就导致了这个错误传播给该函数或方法的调用者,如果它的调用者也都不捕获处理,那么最后程序会出现运行期错误。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1748307,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android学习之横竖屏切换与Activity生命周期的关系

这篇文章有着很详细的报告…. 走近科学 对于最后一点表达一下自己的看法… 关于横屏切换竖屏调用两次,我特地的看了一下全键盘的手机,在观察中发现 1,当推出键盘的时候,会触发硬件的改变,使手机竖屏变成了横屏 2,当推进键盘的时候,合上手机的一刻,触发的是同一样的固件,由于,固件是无法辨别那个是推进,和推出,发出的是一样的信号,然后系统就会认为这是一个横屏改变,等到合上手机的时候系统再接受到一个信号,然后切换成竖屏.这样系统,认为横屏切换竖屏改变了两次,这样就导致调用了两次onConfigurationChanged(); 为了证明这点我写了以下代码测试: 设置一个用来切换横竖屏的button privateButtonok; privatebooleanland=false; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.appwidget_configure); ok=(Button)findViewById(R.id.save_button); ok.setOnClickListener(newButtonlistener());} classButtonlistenerimplementsOnClickListener{publicvoidonClick(Viewv){ //TODOAuto-generatedmethodstub Log.d("app","ok"); if(!land){ //切换成横屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);land=true; }else{ //切换成竖屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);land=false;}}} @Override publicvoidonConfigurationChanged(ConfigurationnewConfig){ super.onConfigurationChanged(newConfig); //Checkstheorientationofthescreen if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){ Log.d("app","land"); Toast.makeText(this,"landscape",Toast.LENGTH_SHORT).show(); //切换到横屏的时候我们需要重新创建button ok=(Button)findViewById(R.id.save_button); ok.setOnClickListener(newButtonlistener()); }elseif(newConfig.orientation==Configuration.ORIENTATION_PORTRAIT){ Log.d("app","portalit"); Toast.makeText(this,"portrait",Toast.LENGTH_SHORT).show();}} 实验: 可以看出单纯的横竖屏切换,系统是只认一次的, 无论是横屏切换竖屏,还是竖屏切换横屏都只是调用了一次onConfigurationChanged(); 这个方法只是为了证明我的推测. 使用这个方法以后将会导致全键盘手机推入推出来无法切换横竖屏. PS:以前的想法白痴了..... 实际上,模拟器的翻转是以一个逆时针的方向旋转...你按两次 ctrl + f11实际上是翻转了三次... 版权声明:原创作品,如需转载,请注明出处。否则将追究法律责任

优秀的个人博客,低调大师

Linux学习之CentOS(三十三)--DNS基础及域名系统架构

本篇文章将主要讲解DNS的一些基础知识以及域名的系统架构,当然这篇随笔是为后面的配置自己的DNS服务器来奠定基础的... 一、域名 在讲解DNS之前,首先粗略的说一下域名这个东西 比如说我们在用浏览器访问网址的时候,我们输入的网站的地址就是一个域名,例如 www.google.com,但其实我们知道我们标志互联网中的每一个机器都是有一个IP地址的,我们若需要访问一个网站的服务器,实际上是需要输入该网站的IP地址来进行访问的,但是IP地址往往难以记忆,IPv4尚且难记,IPv6就更不用说了,所以我们就通过使用域名来对其进行管理,但是在访问的时候,系统底层还是通过ip地址来进行访问的,域名和IP地址直接的转换就是通过DNS服务器来完成的。首先我们先来看看域名的一些知识,就拿 www.google.com 这个域名来说。 通常对于一个域名来说,其主要分为3个部分 www.google.com主机名域名类型 ①类型 标志着该域名的类型(com、cn、edu、org等) ②域名 域的名称,如上面的 google ③主机名 域里面一台主机的名字,如www这台主机 其实严格的来说,域名后面还有一个 ".",所以完整的域名应该是 www.google.com. 对于域名来说,其大小写是不敏感的,在浏览器里面我们输入大小写都指向的同一个ip地址 二、DNS 从上面可以知道,每一个域名都对应了一个IP地址,我们访问一个域名时,其实底层的操作系统进行通信时还是通过IP地址来进行通信,所以我们就需要有一个服务能将域名转换成对应的IP地址,或者反向的将IP地址转换成域名,这个服务就是DNS(Domain Name System)。 DNS提供的服务就是在IP和域名之间进行转换,DNS服务是由DNS服务器来提供的,一般提供DNS服务的都有一个单独的DNS服务器,这个DNS服务器的作用就是用来保存我们的域名到其IP地址之间的解析,例如我们在访问 www.google.com 这个域名的时候,我们的主机首先会向一个DNS服务器发起一个DNS的请求,请求DNS服务器告诉我www.google.com这个域名的IP地址,此时DNS服务器就会给我们返回该域名的IP地址,这个时候我们再根据这个IP地址访问www.google.com这台服务器 DNS服务就是将我们的域名解析成其对应的IP地址,我们日常使用的支持网络的计算机一般是做为DNS客户端来使用的,应用程序、服务、进程等等通过操作系统底层的功能发起对DNS服务器的查询,来对指定的域名进行解析 在Linux系统当中,一般是使用系统底层提供的gethostbyname()这个函数来进行域名解析的 在Linux系统当中,解析域名通常可以基于以下三种方式: ①文件 (/etc/hosts、/etc/networks) hosts是主机文件,里面存放的是域名到IP地址的一个对应,在windows下也有这样一个文件,通常linux下通过文件来解析域名都是通过 /etc/hosts 这个文件 [root@xiaoluo~]#cat/etc/hosts127.0.0.1localhostlocalhost.localdomainlocalhost4localhost4.localdomain4 ::1localhostlocalhost.localdomainlocalhost6localhost6.localdomain6 因为hosts文件里面保存的就是域名到IP地址直接的对应关系,我们也可以手动的去将我们的域名指定为其它的IP,例如我们将 www.google.com 的 ip 修改为 192.168.1.1 [root@xiaoluo~]#pingwww.google.com PINGwww.google.com(173.194.72.103)56(84)bytesofdata. [root@xiaoluo~]#vim/etc/hosts127.0.0.1localhostlocalhost.localdomainlocalhost4localhost4.localdomain4 ::1localhostlocalhost.localdomainlocalhost6localhost6.localdomain6192.168.1.1www.google.com[root@xiaoluo~]#pingwww.google.com PINGwww.google.com(192.168.1.1)56(84)bytesofdata. 我们看到,我们在 /etc/hosts 文件里加上 192.168.1.1 www.google.com 这条映射关系以后,此时在ping www.google.com时,其ip地址变成了我们自己设定的 192.168.1.1了,但是我们知道其IP地址肯定不是这个。为此,我们可以在操作系统上将一些域名的IP地址直接写到 hosts 文件里面,这样在进行解析时可以直接去访问我们指定的IP地址 ②DNS 这个就是通过我们指定的DNS服务器来对我们的域名进行解析了 ③NIS 这个用的非常少 我们可以通过查看 /etc/nsswitch.conf 这个文件来查看DNS解析的顺序 [root@xiaoluo~]#cat/etc/nsswitch.conf # #/etc/nsswitch.conf # #AnexampleNameServiceSwitchconfigfile.Thisfileshouldbe #sortedwiththemost-usedservicesatthebeginning. # #Theentry'[NOTFOUND=return]'meansthatthesearchforan #entryshouldstopifthesearchinthepreviousentryturned #upnothing.Notethatifthesearchfailedduetosomeotherreason #(likenoNISserverresponding)thenthesearchcontinueswiththe #nextentry. # #Validentriesinclude: # #nisplusUseNIS+(NISversion3) #nisUseNIS(NISversion2),alsocalledYP #dnsUseDNS(DomainNameService) #filesUsethelocalfiles #dbUsethelocaldatabase(.db)files #compatUseNISoncompatmode #hesiodUseHesiodforuserlookups #[NOTFOUND=return]Stopsearchingifnotfoundsofar # #Tousedb,putthe"db"infrontof"files"forentriesyouwanttobe #lookedupfirstinthedatabases # #Example: #passwd:dbfilesnisplusnis #shadow:dbfilesnisplusnis #group:dbfilesnisplusnispasswd:files shadow:files group:files#hosts:dbfilesnisplusnisdns hosts:filesdns#Example-obeyonlywhatnisplustellsus... #services:nisplus[NOTFOUND=return]files #networks:nisplus[NOTFOUND=return]files #protocols:nisplus[NOTFOUND=return]files #rpc:nisplus[NOTFOUND=return]files #ethers:nisplus[NOTFOUND=return]files #netmasks:nisplus[NOTFOUND=return]files bootparams:nisplus[NOTFOUND=return]files ethers:files netmasks:files networks:files protocols:files rpc:files services:files netgroup:nisplus publickey:nisplus automount:filesnisplus aliases:filesnisplus 我们看到我们 hosts 解析的顺序先是通过 file 文件来进行解析,再是通过DNS进行解析,我们可以直接修改该文件来控制我们的查询顺序 三、DNS查询 我们可以通过 host 或者 dig 命令来查询我们域名对应的IP地址 ①host(显示内容较少) [root@xiaoluo~]#hostwww.google.com www.google.comhasaddress74.125.31.104www.google.comhasaddress74.125.31.147www.google.comhasaddress74.125.31.106www.google.comhasaddress74.125.31.99www.google.comhasaddress74.125.31.103www.google.comhasaddress74.125.31.105www.google.comhasIPv6address2404:6800:4008:c01::6a ②dig(显示内容详细) [root@xiaoluo~]#digwww.google.com ;<<>>DiG9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6<<>>www.google.com ;;globaloptions:+cmd ;;Gotanswer: ;;->>HEADER<<-opcode:QUERY,status:NOERROR,id:65143;;flags:qrrdra;QUERY:1,ANSWER:6,AUTHORITY:0,ADDITIONAL:0;;QUESTIONSECTION: ;www.google.com.INA ;;ANSWERSECTION: www.google.com.5INA74.125.31.104www.google.com.5INA74.125.31.147www.google.com.5INA74.125.31.106www.google.com.5INA74.125.31.99www.google.com.5INA74.125.31.103www.google.com.5INA74.125.31.105;;Querytime:2012msec ;;SERVER:192.168.198.2#53(192.168.198.2) ;;WHEN:MonJun319:49:552013;;MSGSIZErcvd:128 我们看到dig命令查询出来的内容非常多,对于里面的每一行语句的含义,将在后续随笔中详细讲解 对于DNS查询来说,其实DNS是一个树状的结构,查询的时候是根据域名从右到左来进行查询,域名每一级由独立的一个或者多个DNS服务器来进行查询 我们看到,当我们在对 www.google.com 这个域名进行查询时,首先是通过 . 这个根DNS服务器去查询 com 这个类型的 DNS 服务器地址,然后再通过 com 对应的多台DNS服务器(每一层都有多个DNS服务器)去查询 google 这个域名的DNS服务器,最后再通过 google的DNS服务器去查询主机名为 www 的这台主机的资源记录,从而得到 www.google.com 的IP地址。我们可以通过dig +trace www.google.com这个命令来追踪整个DNS查询的过程 [root@xiaoluo~]#dig+tracewww.google.com;<<>>DiG9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6<<>>+tracewww.google.com ;;globaloptions:+cmd .5INNSf.root-servers.net. .5INNSg.root-servers.net. .5INNSh.root-servers.net. .5INNSi.root-servers.net. .5INNSj.root-servers.net. .5INNSk.root-servers.net. .5INNSl.root-servers.net. .5INNSm.root-servers.net. .5INNSa.root-servers.net. .5INNSb.root-servers.net. .5INNSc.root-servers.net. .5INNSd.root-servers.net. .5INNSe.root-servers.net. ;;Received508bytesfrom192.168.198.2#53(192.168.198.2)in28138ms com.172800INNSa.gtld-servers.net. com.172800INNSb.gtld-servers.net. com.172800INNSc.gtld-servers.net. com.172800INNSd.gtld-servers.net. com.172800INNSe.gtld-servers.net. com.172800INNSf.gtld-servers.net. com.172800INNSg.gtld-servers.net. com.172800INNSh.gtld-servers.net. com.172800INNSi.gtld-servers.net. com.172800INNSj.gtld-servers.net. com.172800INNSk.gtld-servers.net. com.172800INNSl.gtld-servers.net. com.172800INNSm.gtld-servers.net. ;;Received492bytesfrom193.0.14.129#53(193.0.14.129)in26867ms google.com.172800INNSns2.google.com. google.com.172800INNSns1.google.com. google.com.172800INNSns3.google.com. google.com.172800INNSns4.google.com. ;;Received168bytesfrom192.54.112.30#53(192.54.112.30)in8681ms www.google.com.300INA173.194.72.103www.google.com.300INA173.194.72.99www.google.com.300INA173.194.72.106www.google.com.300INA173.194.72.104www.google.com.300INA173.194.72.147www.google.com.300INA173.194.72.105;;Received128bytesfrom216.239.38.10#53(216.239.38.10)in82ms 我们看到整个DNS查询过程就是上述的根据域名从右到左来一步步查询, . root DNS -> com DNS -> google DNS -> www DNS查询类型一共有两种,一种是 迭代查询 (Iterative Query),另一种是 递归查询 (Recursive Query)我们通过下面两个示意图就可以知道这两种查询的区别了 ①迭代查询 (Iterative Query) ②递归查询 (Recursive Query) 我们看到迭代查询时本地DNS Server会首先向 . DNS Server发出请求,此时 . DNS Server会返回给本地DNS Server com的 DNS Server,这样依次类推下去,最后将 www.google.com的ip地址返回,而递归查询,则只是本地DNS Server向 . DNS Server发出一个请求,然后解析IP是交给了其下属的DNS Server来完成,最后将IP地址返回,由于递归查询在每个DNS Server上会有缓存信息,所以一般我们都是使用两种查询方式相结合的方式来进行DNS查询的 四、资源记录 在DNS服务器上,DNS的信息都是通过一个叫做资源记录(RR Resource Record)的格式来进行保存的,RR不仅能够保存域名到IP地址的信息,还能保持其他很多的信息 资源记录常用的属性有: -NAME (主机名) -CLASS (类别,通常是IN) -TYPE (类型,资源记录的类型) -RDATA (信息) 如: www IN A 192.168.1.1 mail IN A 192.168.1.2 server1 IN CNAME www IN MX 10 mail.gmail.com.(对于MX记录,后面的域名一定要写完整,即最后的 . 也要加上) NAME CLASS TYPE RDATA 上面都是我们的资源记录。DNS的资源记录可以记录许多类型的资源,而不仅仅是IP地址,常见的资源记录类型如下: 资源记录类型(TYPE) 表示内容 A IPv4地址 AAAA IPv6地址 MX 邮件记录 CNAME 别名 PTR 指针(逆向解析) SRV 服务资源 我们可以使用DNS的高级查询命令来查看这些资源记录的信息 ①dig -t awww.google.com 查看域名的IPv4地址 [root@xiaoluo~]#dig-tawww.google.com;<<>>DiG9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6<<>>-tawww.google.com ;;globaloptions:+cmd ;;Gotanswer: ;;->>HEADER<<-opcode:QUERY,status:NOERROR,id:52161;;flags:qrrdra;QUERY:1,ANSWER:6,AUTHORITY:0,ADDITIONAL:0;;QUESTIONSECTION: ;www.google.com.INA ;;ANSWERSECTION: www.google.com.5INA74.125.31.103www.google.com.5INA74.125.31.99www.google.com.5INA74.125.31.147www.google.com.5INA74.125.31.104www.google.com.5INA74.125.31.106www.google.com.5INA74.125.31.105 // 这些都是www.google.com的IPv4地址;;Querytime:2010msec ;;SERVER:192.168.198.2#53(192.168.198.2) ;;WHEN:MonJun320:45:302013;;MSGSIZErcvd:128 ②dig -t mx gmail.com 查看gmail.com这个域名的邮件记录 [root@xiaoluo~]#dig-tmxgmail.com;<<>>DiG9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6<<>>-tmxgmail.com ;;globaloptions:+cmd ;;Gotanswer: ;;->>HEADER<<-opcode:QUERY,status:NOERROR,id:44633;;flags:qrrdra;QUERY:1,ANSWER:5,AUTHORITY:0,ADDITIONAL:4;;QUESTIONSECTION: ;gmail.com.INMX ;;ANSWERSECTION: gmail.com.5INMX40alt4.gmail-smtp-in.l.google.com. gmail.com.5INMX30alt3.gmail-smtp-in.l.google.com. gmail.com.5INMX10alt1.gmail-smtp-in.l.google.com. gmail.com.5INMX5gmail-smtp-in.l.google.com. gmail.com.5INMX20alt2.gmail-smtp-in.l.google.com. //gmail.com的邮件服务器 ;;ADDITIONALSECTION: alt3.gmail-smtp-in.l.google.com.5INAAAA2607:f8b0:400d:c02::1a alt1.gmail-smtp-in.l.google.com.5INAAAA2a00:1450:4010:c03::1b gmail-smtp-in.l.google.com.5INAAAA2607:f8b0:400e:c01::1a alt4.gmail-smtp-in.l.google.com.5INAAAA2607:f8b0:400c:c01::1a //gmail.com邮件服务器对应的IP地址 ;;Querytime:2003msec ;;SERVER:192.168.198.2#53(192.168.198.2) ;;WHEN:MonJun320:47:322013;;MSGSIZErcvd:262 ③dig -x42.121.135.98 逆向解析42.121.135.98 这个IP地址得到其域名 (博客园的IP) [root@xiaoluo~]#hostwww.cnblogs.com www.cnblogs.comhasaddress42.121.135.98[root@xiaoluo~]#dig-x42.121.135.98;<<>>DiG9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6<<>>-x42.121.135.98;;globaloptions:+cmd ;;Gotanswer: ;;->>HEADER<<-opcode:QUERY,status:NXDOMAIN,id:22590;;flags:qrrdra;QUERY:1,ANSWER:0,AUTHORITY:1,ADDITIONAL:0;;QUESTIONSECTION: ;98.135.121.42.in-addr.arpa.INPTR ;;AUTHORITYSECTION:121.42.in-addr.arpa.5INSOAhidden-master.aliyun.com.hostmaster.aliyun-inc.com.201306030072009002592000600;;Querytime:2004msec ;;SERVER:192.168.198.2#53(192.168.198.2) ;;WHEN:MonJun320:51:272013;;MSGSIZErcvd:126 以上这些都是对DNS以及域名进行一些简单的知识介绍、总结(自己感觉总结的有点繁琐哈。。。),在下一篇文章里面将详细讲解Linux下如何配置我们自己的DNS服务器。。。 本文转自sandshell博客51CTO博客,原文链接http://blog.51cto.com/sandshell/1947776如需转载请自行联系原作者 sandshell

优秀的个人博客,低调大师

小白学习大数据测试之hadoop hdfs和MapReduce小实战

在湿货|大数据测试之hadoop单机环境搭建(超级详细版)这个基础上,我们来运行一个官网的MapReduce demo程序来看看效果和处理过程。 大致步骤如下: 新建一个文件test.txt,内容为 Hello Hadoop Hello xiaoqiang Hello testingbang Hello http://xqtesting.sxl.cn 将test.txt上传到hdfs的根目录 /usr/lib/hadoop/hadoop-2.7.4/bin/hdfs dfs -put /root/install/test.txt / 然后浏览器访问可以看到刚才上传的文件,如下图 运行官方的一个wordcount程序来统计字符数量,命令如下: /usr/lib/hadoop/hadoop-2.7.4/bin/hadoop jar /usr/lib/hadoop/hadoop-2.7.4/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.4.jar wordcount hdfs://localhost:9000/test.txt hdfs://localhost:9000/out 解释下这个命令,大致意思是用hadoop执行一个叫hadoop-mapreduce-examples-2.7.4.jar的wordcount 方法,其中输入参数为hdfs上根目录的test.txt 文件,而输出路径为hdfs跟目录下的out目录 PS:我这里没有把hadoop配置成环境变量,所以命令很长,你可以配置下,这样命令就会短很多了,至于怎么配置,自己悟~ 执行过程如下: 执行完成之后再次刷新浏览器可以看到out目录和结果了 点击part-r-00000,在弹出的页面点击download 这时候下载会出现404,我们只需要在URL里的localhost改为你服务器的ip地址就可以下载了。下载之后用编辑器打开,内容如下: PS:你也可以用命令查看,如下图 到这里,我们既完成了hadoop环境的搭建,也完成一次MapReduce的执行。其实也算是对hadoop功能的测试。如果你都成功了,那么恭喜你!如果你没有成功,那么也恭喜你,因为你发现了自己的不足! 本文转自 小强测试帮 51CTO博客,原文链接:http://blog.51cto.com/xqtesting/2068647,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android学习笔记十]Adapter如何进行视图与数据绑定资料

Android开发中视图和数据的绑定离不开Adapt系列的类,在呈现给用户的界面友好美观和内容丰富的应用中视图为骨,内容为肉,Adapter则是骨肉相连的筋。 下图是Android类库中的Adapter类层次图: 在android support库以及更多的第三方库中存在大量的Adapter类,Adapter在视图和数据绑定中起着至关重要的桥接作用。 本文转自 secondriver 51CTO博客,原文链接:http://blog.51cto.com/aiilive/1721188,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day43)——构造函数继承

Swift中的子类构造函数的来源有两种:自己编写和从父类继承。并不是父类的所有的构造函数都能继承下来,能够从父类继承下来的构造函数是有条件的,如下所示。 条件1:如果子类没有定义任何指定构造函数,它将自动继承所有父类的指定构造函数。 条件2:如果子类提供了所有父类指定构造函数的实现,无论是通过条件1继承过来的,还是通过自己编写实现的,它都将自动继承所有父类的便利构造函数。 下面看示例代码: classPerson{ varname:String varage:Int funcdescription()->String{ return"\(name)年龄是:\(age)" } convenienceinit(){ self.init(name:"Tony") self.age=18 } convenienceinit(name:String){ self.init(name:name,age:18) } init(name:String,age:Int){ self.name=name self.age=age } } classStudent:Person{ varschool:String init(name:String,age:Int,school:String){ self.school=school super.init(name:name,age:age) } convenienceoverrideinit(name:String,age:Int){ self.init(name:name,age:age,school:"清华大学") } } classGraduate:Student{ varspecial:String="" } 来看看符合条件1的继承,Graduate继承Student,Graduate类没有定义任何指定构造函数,它将自动继承所有Student的指定构造函数。符合条件1后,Graduate从Student继承了如下指定构造函数: init(name : String,age : Int,school : String) 再看符合条件2的继承,由于Graduate实现了Student的所有指定构造函数,Graduate将自动继承所有Student的便利构造函数。符合条件2后,Graduate从Student继承了如下3个便利构造函数: init(name:String,age:Int) init(name:String) init() Student继承Person后有4个构造函数。 条件1对Student不满足,因为它有指定构造函数,Student类中的便利构造函数init (name: String, age: Int)满足了条件2,它实现了父类指定构造函数init (name: String, age: Int)。另外,由于子类构造函数与父类构造函数参数相同,需要使用override关键字,表示子类构造函数重写(overriding)了父类构造函数。 由于Student类实现了父类指定构造函数,因此也继承了父类的另外两个便利构造函数。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1747499,如需转载请自行联系原作者

优秀的个人博客,低调大师

阿里云云计算工程师ACP学习笔记--知识点总结

Elastic Compute Server 是一种处理能力可弹性伸缩的计算服务。 CPU内存需要停机,带宽不需要。 垂直:带宽 CPU 内存 水平:服务器 Region 地域 Zone 可用区 安全组, 允许包含跨可用区的实例 磁盘 只能挂在同一可用区 快照镜像 可以跨可用区,镜像可以复制到别的地域 发生故障时,实例只能在同一个可用区迁移 默认系统盘40GB-500GB ,系统盘设备名:/dev/xvda ECS创建时必须要选择镜像来确定其操作系统 更换系统盘不会更改实例的 IP 地址和 MAC 地址。 包年包月 最小一周 支持随时升级 带宽 不能提前释放 按量付费 不支持实例规格升级 带宽 可随时释放 高效云盘 20 -- 32768GB 3000* 80MBps 都是3个备份,不同交换机下的不同物理服务器上 SSD云盘 20 -- 32768GB 20000* 吞吐量 300MBps 普通云盘 2000GB 数百 30MBps 磁盘同一时间内,只能挂载在1个实例上。可设置是否随实例一起释放,只支持按量付费 一个ECS实例最多可以挂载16块数据盘 扩容需要重启服务器,手动去格式化,数据是保留的。 e2fsck -f /dev/vdb1 resize2fs /dev/vdb1 实例卸载 全部磁盘卸载 快照 磁盘数据在某个时间点的拷贝 增量快照 默认安装云盾 安全组 指定源IP地址段 CIDR Block 指定源安全组的ID(内网) 支持对入 出方向 每个用户最多100个安全组,每个安全组最多有1000个实例。 每个实例最多加入5个安全组,每个安全组最多100条规则。 安全组优先级1-100,1最大 4G内存以上不能选择32位操作系统 实例系列2 3 支持I/0优化,1的只有2C4G以上。 删除快照需要先删除相对应的镜像 每块磁盘提供 64 个快照额度 每个实例最多有10个标签 ECS API ecs.aliyuncs.com 签名机制 signature Access Key ID Accesss Key Secret 单个key 5000次/天 5个key Object Storage Server 云存储服务 可用性99.9% 可靠性 10个9 数据三备份 安全 防DDos 访问日志 无限扩展 Object put 5GB multipart 上传最大48.8TB 必须包含在Bucket Bucket 命名空间 1个用户最多10个 全局唯一 不能修改 容量最高2PB Server 虚拟存储空间 (用户) Access ID & Key 用户标示 API密钥 Bcuket 不可以修改所属可用区 三级域名 bucketname.endpoint 只有使用ECS实例用户 才能通过OSS内网地址访问,免流量 必须在同一区域 http://bucket名字.数据中心服务域名/object名字 私有 公共读 公共读写 不允许删除非空的bucket 没有任何碎片以及object 过期时间 自定义空间 批量删除最多1000个object 每个bucket可以绑定20个域名 当Object的Content-Type=application/octet-stream,采用OSS外网地址访问一个文件格式为jpg的Object ,默认直接下载 基于header中表头 referer 防盗链 白名单为空: -不会检查referer字段是否为空(不然所有的请求都会被拒绝) 白名单不为空: - 且设置了不允许referer字段为空的规则,则只有referer属于白名单的请求才允许,其他(包括referer为空)会被拒绝 - 设置了允许referer字段为空的故障,则referer为空的请求和符合白名单的请求会被允许;其他请求会被拒绝。 如果用浏览器浏览,需要设置允许 referer字段为空。 日志记录 用户自定义 源bucket 时间 OSS系统生成的字符串 图片服务 样式功能(将一系列的复杂的处理参数用简单的别名去代表) 规则 @ 样式@!别名(避免URL太长) 管道 | 多个处理动作一起操作 先关闭图片处理服务,再删除bucket Public-read-write Public-read 创建者可以写 Private 服务器端加密 防盗链 bucket权限控制 Acccess ID 和请求签名 OSS 本身不提供IP黑名单,但是可以通过CDN来间接使用IP黑白名单 弹性伸缩服务 免费 定时任务 20个 同一时间内的,会选取最近创建的定时任务执行 报警任务 名称唯一 必须指定ECS实例 支持RDS访问白名单 伸缩组 Scaling Group ECS实例的集合,最小值,最大值 权限最高 伸缩配置 Scaling Configuration ECS实例的规格 伸缩规则 Scaling Rule 扩展或收缩个数 伸缩活动 Scaling Activity 规则成功出发后,产生一个伸缩活动。(同一伸缩组内,同一时刻只能有一个伸缩活动在执行,无法终止互动) 伸缩触发任务 Scaling Trigger Task 用于触发伸缩规则的任务。 定时报警任务 冷却时间 Cooldown Period 伸缩活动完成后的 锁定时间 (只会拒绝云监控报警任务类型的伸缩活动请求,其他手工、定时可以绕过冷却时间)(最后一个成功后) 触发伸缩规则的任务独立于伸缩组存在,删除伸缩组不会删除任务 生效,失效,删除中 修改伸缩组属性时,地域 SLB RDS 不可以修改| 生效和失效 才可以修改 强制删除 1个伸缩桌10个伸缩规则,1个用户最多伸缩100个ECS 手工加入既有的ECS实例: 1,判断伸缩组的健康状态、边界条件和ECS实例的状态、类型。 2,分配ActivityId和执行伸缩活动。 3,加入ECS实例 4,修改Total Capacity。 5,添加RDS白名单 6,挂载SLB,将权重设为0。 7,等待60秒后,将权重设为50。 8,伸缩活动完成,启动cooldown。 虚拟专有网络 应用层 HTTP 传输层 TCP UDP 网络层 ICMP IP 路由选择 数据链路层 ARP RARP 不同VPC之间通过隧道ID进行隔离 VRouter VSwitch Route Table 1个 Route Entry 路由条目 Elastic IP Address 专线接入 每个专有网络最多容纳200个,可以工单申请。 CIDRBlock 创建成功后,不能修改网段 删除专有网络,需要先删除里面所有的东西 每个路由表最多只能创建48个自定义路由条目 一个专有网络最多只能创建24个交换机 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 Server Load Balancer 负载均衡 高可用 低成本 安全 | 公网 私网免费 LoadBalancer 代表一个SLB实例 Listener 代表用户定制的负责均衡策略和转发规则 BackendServer是后端的一组云服务器 四层 TCP/UDP LVS 健康检查是 可以选择TCP HTTP 七层 HTTP/HTTPS Tengine 可以关闭健康检查 控制系统 用于配置和监控SLB 健康检查 会话保持 session 加权轮询WRR 加权最小连接数WLC 针对HTTPS,提供证书管理服务 使用流量 只收下行流量 (为公网出流量) 固定带宽 内网限流 1Gbps 1个SLB 最多支持50个服务监听配置 权重0-100, 0是不转发,设置后,长连接仍然存在。 实时生效 证书最多100个 每个用户最多30个SLB实例。1-65535 SLB 可以是不同Zone。 同一或不同地域,创建多个SLB, 通过DNS轮询的方式对外提供服务 不会限制SLB后面的ECS 可用性高达99.95% 安全结合云盾提供防 DDoS 攻击能力,包括 CC、SYN flood 等 DDoS 攻击方式。 负载均衡各监听连接超时时间如下: TCP 900秒 UDP 300秒 HTTP 60秒 HTTPS 60秒 Content Delivery Network 内容分发网络 将源站内容分发至全国所有的节点,缩短用户查看对象的延迟。 业务: 小文件加速 大文件加速 视频点播 视频直播 用户:快捷申请 个性化配置 报表 日志分析 OPEN API接口 防盗链支持 边缘节点 cache高速缓存 带宽峰值 流量 带宽利用率=实际使用流量GB/(带宽峰值Mbpsx10.54),1Mbps带宽每日100%利用率为10.54GB。 带宽计费:阶梯计费 智能DNS 根据客户的来源返回不同的IP地址 阿里云CDN:智能调度系统和Cacha软件 构成 | L1cache - BGP - L2cache - 源 IP 源站 OSS源站 缓存刷新 : URL刷新 目录刷新 URL预热 源站: 源站决定回源时,请求到哪个IP 回源host:回源host决定回源请求到该IP 上的哪个站点 WAF防护(WEB应用防护系统) CC防护(针对CC共计) 黑白名单 (IP) 同一时间内只能生效一种。 URL鉴权 3种方式 4层防御体系结构:网络层 主机层 应用层 数据层 安全体系: 云盾 云服务 云安全运维 安全管家:防DDOS服务、端口安全检查、异地登陆提醒、主机密码暴力破解防御、网站后门检测 安全体检:WEB漏洞检测 网页挂马检测 DDOS: DNS query Flooad 、 NTP reply Flood 清洗阈值: 自动 手动 云盾技术防护不支持防护CC攻击 安骑士: 主机密码防爆破 异地登陆报警 网站后门检测 高危漏洞修复 木马文件查杀 数据库防护: 白名单限制访问源IP 内网访问模式 防暴力破解 SQL注入防护 SQL审计 应用防火墙: 跨站攻击 CRLF攻击 SQL注入攻击 FastCGI攻击 WEBSHELL攻击 Cloud Monitor System 云监控 开放性 网络优势 开放平台支持 站点监控 云产品监控 自定义监控 报警及联系人管理 监控项目: HTTP: http.response Time & http.status 监控点:监控项的一个实例 维度: 定位监控项数据位置的维度, 目前维度用“字段信息表示” 规则: 条件 报警组 报警方式 状态码 响应时间 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1974241,如需转载请自行联系原作者

优秀的个人博客,低调大师

学习node.js第一天:node模块化

上一篇说完了如何创建一个简单的http服务,现在说说模块化. 在开发过程中,经常会说模块化这个词.那都表示什么含义呢?一般都有以下几层意思: 1.业务解耦. 业务耦合太多,后期不便于扩展和维护.这种情况常常出现于创业公司,当公司业务发展起来的时候,就会发现业务系统有严重的瓶颈,服务能力不足会制约公司的发展.所以需要把不相关的业务做成独立的系统. 2.微服务 在大的企业中经常会出现多种系统,每种系统又用到相同的功能.比喻说上传图片,如果每个开发小组都去造轮子,那就太浪费了.如果将图片上传做成单独的服务,以开发API的方式提供给大家使用,就会系统不少效率. 3.功能模块化 在同一个系统中可能会出现交叉使用别的模块的数据,大家都去操作别的业务的对应的表数据.在这种情况下,很难避免数据不会出现问题.吃蛋糕的人太多,而蛋糕只有一块,大家都动手去切的后果会怎么样?解决方案也一样,负责该模块的开发人员封装好该业务的代码,提供接口即可.而此时需要该使用该模块的人只管去调用,而不必去管背后逻辑的实现. 讲了废话一堆,现在就说说node怎么进行代码模块化,打包服务,方便其他地方调用. 模块化http服务:httpServer.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //业务功能:将http服务打包为一个模块,方便在其他地方调用 //引入http模块 var http=require( 'http' ); //封装启动http服务 var startHttp= function (){ var onRequest= function (request,response){ response.writeHead(200,{ 'Content-Type' : 'text/plain;charset=UTF-8' }); response.write( '大家好' ); response.end(); } http.createServer(onRequest).listen( '8888' ); console.log( 'Httpserverhasstarted.' ); } //exports生成模块beginStart,作用是调用启动http服务 exports.beginStart=startHttp; 调用模块服务 先创建一个统一入口的文件index.js 1 2 3 4 //引入httpServer模块 var httpServer=require( './httpServer' ); //启动httpserver服务 httpServer.beginStart(); 最后可以在终端启动服务:node index.js 打开浏览器http://localhost:8888,可以看到效果 本文转自 hgditren 51CTO博客,原文链接:http://blog.51cto.com/phpme/1893920,如需转载请自行联系原作者

优秀的个人博客,低调大师

Spark RDD概念学习系列之Spark的算子的分类(十一)

Spark的算子的分类 从大方向来说Spark 算子大致可以分为以下两类: 1Transformation 变换/转换算子这种变换并不触发提交作业完成作业中间过程处理。 Transformation 操作是延迟计算的也就是说从一个RDD 转换生成另一个 RDD 的转换操作不是马上执行需要等到有 Action 操作的时候才会真正触发运算。 2Action 行动算子这类算子会触发 SparkContext 提交 Job 作业。 Action 算子会触发 Spark 提交作业Job并将数据输出 Spark系统。 从小方向来说Spark 算子大致可以分为以下三类: 1Value数据类型的Transformation算子这种变换并不触发提交作业针对处理的数据项是Value型的数据。 2Key-Value数据类型的Transfromation算子这种变换并不触发提交作业针对处理的数据项是Key-Value型的数据对。 3Action算子这类算子会触发SparkContext提交Job作业。 1Value数据类型的Transformation算子 一、输入分区与输出分区一对一型 1、map算子 2、flatMap算子 3、mapPartitions算子 4、glom算子 二、输入分区与输出分区多对一型 5、union算子 6、cartesian算子 三、输入分区与输出分区多对多型 7、grouBy算子 四、输出分区为输入分区子集型 8、filter算子 9、distinct算子 10、subtract算子 11、sample算子 12、takeSample算子 五、Cache型 13、cache算子 14、persist算子 2Key-Value数据类型的Transfromation算子 一、输入分区与输出分区一对一 15、mapValues算子 二、对单个RDD或两个RDD聚集 单个RDD聚集 16、combineByKey算子 17、reduceByKey算子 18、partitionBy算子 两个RDD聚集 19、Cogroup算子 三、连接 20、join算子 21、leftOutJoin和 rightOutJoin算子 Spark算子的作用详细见http://www.cnblogs.com/zlslch/p/5723979.html 3Action算子 一、无输出 22、foreach算子 二、HDFS 23、saveAsTextFile算子 24、saveAsObjectFile算子 三、Scala集合和数据类型 25、collect算子 26、collectAsMap算子 27、reduceByKeyLocally算子 28、lookup算子 29、count算子 30、top算子 31、reduce算子 32、fold算子 33、aggregate算子 Spark算子的作用详细见http://www.cnblogs.com/zlslch/p/5723979.html 1. Transformations 算子 1map 将原来 RDD 的每个数据项通过map 中的用户自定义函数 f映射转变为一个新的元素。源码中 map 算子相当于初始化一个 RDD 新 RDD 叫做 MappedRDD(this, sc.clean(f))。 图 1中每个方框表示一个 RDD 分区左侧的分区经过用户自定义函数 f:T->U映射为右侧的新 RDD 分区。但是实际只有等到 Action算子触发后这个 f 函数才会和其他函数在一个stage 中对数据进行运算。在图 1 中的第一个分区数据记录 V1 输入 f通过 f 转换输出为转换后的分区中的数据记录 V'1。 图1 map 算子对 RDD 转换 2flatMap 将原来 RDD 中的每个元素通过函数 f 转换为新的元素并将生成的 RDD 的每个集合中的元素合并为一个集合内部创建 FlatMappedRDD(thissc.clean(f))。 图 2 表 示 RDD 的 一 个 分 区 进 行 flatMap函 数 操 作 flatMap 中 传 入 的 函 数 为 f:T->UT和 U 可以是任意的数据类型。将分区中的数据通过用户自定义函数 f 转换为新的数据。外部大方框可以认为是一个 RDD 分区小方框代表一个集合。 V1、 V2、 V3 在一个集合作为 RDD 的一个数据项可能存储为数组或其他容器转换为V'1、 V'2、 V'3 后将原来的数组或容器结合拆散拆散的数据形成为 RDD 中的数据项。 图2 flapMap 算子对 RDD 转换 3mapPartitions mapPartitions 函 数 获 取 到 每 个 分 区 的 迭 代器在 函 数 中 通 过 这 个 分 区 整 体 的 迭 代 器 对整 个 分 区 的 元 素 进 行 操 作。 内 部 实 现 是 生 成 MapPartitionsRDD。图 3 中的方框代表一个 RDD 分区。图 3 中用户通过函数 f (iter)=>iter.f ilter(_>=3) 对分区中所有数据进行过滤大于和等于 3 的数据保留。一个方块代表一个 RDD 分区含有 1、 2、 3 的分区过滤只剩下元素 3。 图3 mapPartitions 算子对 RDD 转换 4glom glom函数将每个分区形成一个数组内部实现是返回的GlommedRDD。 图4中的每个方框代表一个RDD分区。图4中的方框代表一个分区。 该图表示含有V1、 V2、 V3的分区通过函数glom形成一数组Array[V1V2V3]。 图 4 glom算子对RDD转换 5union 使用 union 函数时需要保证两个 RDD 元素的数据类型相同返回的 RDD 数据类型和被合并的 RDD 元素数据类型相同并不进行去重操作保存所有元素。如果想去重 可以使用 distinct()。同时 Spark 还提供更为简洁的使用 union 的 API通过 ++ 符号相当于 union 函数操作。 图 5 中左侧大方框代表两个 RDD大方框内的小方框代表 RDD 的分区。右侧大方框代表合并后的 RDD大方框内的小方框代表分区。 含有V1、V2、U1、U2、U3、U4的RDD和含有V1、V8、U5、U6、U7、U8的RDD合并所有元素形成一个RDD。V1、V1、V2、V8形成一个分区U1、U2、U3、U4、U5、U6、U7、U8形成一个分区。 图 5 union 算子对 RDD 转换 6cartesian 对 两 个 RDD 内 的 所 有 元 素进 行 笛 卡 尔 积 操 作。 操 作 后 内 部 实 现 返 回CartesianRDD。图6中左侧大方框代表两个 RDD大方框内的小方框代表 RDD 的分区。右侧大方框代表合并后的 RDD大方框内的小方框代表分区。图6中的大方框代表RDD大方框中的小方框代表RDD分区。 例 如 V1 和 另 一 个 RDD 中 的 W1、 W2、 Q5 进 行 笛 卡 尔 积 运 算 形 成 (V1,W1)、(V1,W2)、 (V1,Q5)。 图 6 cartesian 算子对 RDD 转换 7groupBy groupBy 将元素通过函数生成相应的 Key数据就转化为 Key-Value 格式之后将 Key 相同的元素分为一组。 函数实现如下 1将用户函数预处理 val cleanF = sc.clean(f) 2对数据 map 进行函数操作最后再进行 groupByKey 分组操作。 this.map(t => (cleanF(t), t)).groupByKey(p) 其中 p 确定了分区个数和分区函数也就决定了并行化的程度。 图7 中方框代表一个 RDD 分区相同key 的元素合并到一个组。例如 V1 和 V2 合并为 V Value 为 V1,V2。形成 V,Seq(V1,V2)。 图 7groupBy 算子对 RDD 转换 8filter filter 函数功能是对元素进行过滤对每个 元 素 应 用 f 函 数 返 回 值 为 true 的 元 素 在RDD 中保留返回值为 false 的元素将被过滤掉。 内 部 实 现 相 当 于 生 成 FilteredRDD(thissc.clean(f))。 下面代码为函数的本质实现 deffilter(f:T=>Boolean):RDD[T]=newFilteredRDD(this,sc.clean(f)) 图 8 中每个方框代表一个 RDD 分区 T 可以是任意的类型。通过用户自定义的过滤函数 f对每个数据项操作将满足条件、返回结果为 true 的数据项保留。例如过滤掉 V2 和 V3 保留了 V1为区分命名为 V'1。 图 8 filter 算子对 RDD 转换 9distinct distinct将RDD中的元素进行去重操作。图9中的每个方框代表一个RDD分区通过distinct函数将数据去重。 例如重复数据V1、 V1去重后只保留一份V1。 图9 distinct算子对RDD转换 10subtract subtract相当于进行集合的差操作RDD 1去除RDD 1和RDD 2交集中的所有元素。图10中左侧的大方框代表两个RDD大方框内的小方框代表RDD的分区。 右侧大方框 代表合并后的RDD大方框内的小方框代表分区。 V1在两个RDD中均有根据差集运算规则新RDD不保留V2在第一个RDD有第二个RDD没有则在新RDD元素中包含V2。 图10 subtract算子对RDD转换 11sample sample 将 RDD 这个集合内的元素进行采样获取所有元素的子集。用户可以设定是否有放回的抽样、百分比、随机种子进而决定采样方式。内部实现是生成 SampledRDD(withReplacement fraction seed)。 函数参数设置 withReplacement=true表示有放回的抽样。 withReplacement=false表示无放回的抽样。 图 11中 的 每 个 方 框 是 一 个 RDD 分 区。 通 过 sample 函 数 采 样 50% 的 数 据。V1、 V2、 U1、 U2、U3、U4 采样出数据 V1 和 U1、 U2 形成新的 RDD。 图11 sample 算子对 RDD 转换 12takeSample takeSample函数和上面的sample函数是一个原理但是不使用相对比例采样而是按设定的采样个数进行采样同时返回结果不再是RDD而是相当于对采样后的数据进行 Collect返回结果的集合为单机的数组。 图12中左侧的方框代表分布式的各个节点上的分区右侧方框代表单机上返回的结果数组。 通过takeSample对数据采样设置为采样一份数据返回结果为V1。 图12 takeSample算子对RDD转换 13cache cache将 RDD 元素从磁盘缓存到内存。 相当于 persist(MEMORY_ONLY) 函数的功能。 图13 中每个方框代表一个 RDD 分区左侧相当于数据分区都存储在磁盘通过 cache 算子将数据缓存在内存。 图 13 Cache 算子对 RDD 转换 14persist persist 函数对RDD 进行缓存操作。数据缓存在哪里依据 StorageLevel 这个枚举类型进行确定。 有以下几种类型的组合见10 DISK 代表磁盘MEMORY 代表内存 SER 代表数据是否进行序列化存储。 下面为函数定义 StorageLevel 是枚举类型代表存储模式用户可以通过图 14-1 按需进行选择。 persist(newLevel:StorageLevel) 图 14-1 中列出persist 函数可以进行缓存的模式。例如MEMORY_AND_DISK_SER 代表数据可以存储在内存和磁盘并且以序列化的方式存储其他同理。 图 14-1 persist 算子对 RDD 转换 图 14-2 中方框代表 RDD 分区。 disk 代表存储在磁盘 mem 代表存储在内存。数据最初全部存储在磁盘通过 persist(MEMORY_AND_DISK) 将数据缓存到内存但是有的分区无法容纳在内存将含有 V1、 V2、 V3 的RDD存储到磁盘将含有U1U2的RDD仍旧存储在内存。 图 14-2 Persist 算子对 RDD 转换 15mapValues mapValues 针对Key Value型数据中的 Value 进行 Map 操作而不对 Key 进行处理。 图 15 中的方框代表 RDD 分区。 a=>a+2 代表对 (V1,1) 这样的 Key Value 数据对数据只对 Value 中的 1 进行加 2 操作返回结果为 3。 图 15 mapValues 算子 RDD 对转换 16combineByKey 下面代码为 combineByKey 函数的定义 combineByKey[C](createCombiner:(V) C, mergeValue:(C, V) C, mergeCombiners:(C, C) C, partitioner:Partitioner, mapSideCombine:Boolean=true, serializer:Serializer=null):RDD[(K,C)] 说明 createCombiner V => C C 不存在的情况下比如通过 V 创建 seq C。 mergeValue (C V) => C当 C 已经存在的情况下需要 merge比如把 item V 加到 seq C 中或者叠加。 mergeCombiners (C C) => C合并两个 C。 partitioner Partitioner, Shuff le 时需要的 Partitioner。 mapSideCombine Boolean = true为了减小传输量很多 combine 可以在 map 端先做比如叠加可以先在一个 partition 中把所有相同的 key 的 value 叠加 再 shuff le。 serializerClass String = null传输需要序列化用户可以自定义序列化类 例如相当于将元素为 (Int Int) 的 RDD 转变为了 (Int Seq[Int]) 类型元素的 RDD。图 16中的方框代表 RDD 分区。如图通过 combineByKey 将 (V1,2) (V1,1)数据合并为 V1,Seq(2,1)。 图 16 comBineByKey 算子对 RDD 转换 17reduceByKey reduceByKey 是比 combineByKey 更简单的一种情况只是两个值合并成一个值 Int Int Vto Int Int C比如叠加。所以 createCombiner reduceBykey 很简单就是直接返回 v而 mergeValue和 mergeCombiners 逻辑是相同的没有区别。 函数实现 def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)] = { combineByKey[V]((v: V) => v, func, func, partitioner) } 图17中的方框代表 RDD 分区。通过用户自定义函数 (A,B) => (A + B) 函数将相同 key 的数据 (V1,2) 和 (V1,1) 的 value 相加运算结果为 V1,3。 图 17reduceByKey 算子对 RDD 转换 18partitionBy partitionBy函数对RDD进行分区操作。 函数定义如下。 partitionBypartitionerPartitioner如果原有RDD的分区器和现有分区器partitioner一致则不重分区如果不一致则相当于根据分区器生成一个新的ShuffledRDD。 图18中的方框代表RDD分区。 通过新的分区策略将原来在不同分区的V1、 V2数据都合并到了一个分区。 图18 partitionBy算子对RDD转换 19Cogroup cogroup函数将两个RDD进行协同划分cogroup函数的定义如下。 cogroup[W]other RDD[K W] numPartitions Int RDD[K Iterable[V] Iterable[W]] 对在两个RDD中的Key-Value类型的元素每个RDD相同Key的元素分别聚合为一个集合并且返回两个RDD中对应Key的元素集合的迭代器。 K Iterable[V] Iterable[W] 其中Key和ValueValue是两个RDD下相同Key的两个数据集合的迭代器所构成的元组。 图19中的大方框代表RDD大方框内的小方框代表RDD中的分区。 将RDD1中的数据U11、 U12和RDD2中的数据U12合并为U1122。 图19 Cogroup算子对RDD转换 20join join 对两个需要连接的 RDD 进行 cogroup函数操作将相同 key 的数据能够放到一个分区在 cogroup 操作之后形成的新 RDD 对每个key 下的元素进行笛卡尔积的操作返回的结果再展平对应 key 下的所有元组形成一个集合。最后返回 RDD[(K (V W))]。 下 面 代 码 为 join 的 函 数 实 现 本 质 是通 过 cogroup 算 子 先 进 行 协 同 划 分 再 通 过flatMapValues 将合并的数据打散。 this.cogroup(other,partitioner).f latMapValues{case(vs,ws) =>for(v<-vs;w<-ws)yield(v,w) } 图 20是对两个 RDD 的 join 操作示意图。大方框代表 RDD小方框代表 RDD 中的分区。函数对相同 key 的元素如 V1 为 key 做连接后结果为 (V1,(1,1)) 和 (V1,(1,2))。 图 20 join 算子对 RDD 转换 21eftOutJoin和rightOutJoin LeftOutJoin左外连接和RightOutJoin右外连接相当于在join的基础上先判断一侧的RDD元素是否为空如果为空则填充为空。 如果不为空则将数据进行连接运算并 返回结果。 下面代码是leftOutJoin的实现。 if ws.isEmpty { vs.mapv => v None } else { for v <- vs w <- ws yield v Somew } 2. Actions 算子 本质上在 Action 算子中通过 SparkContext 进行了提交作业的 runJob 操作触发了RDD DAG 的执行。 例如 Action 算子 collect 函数的代码如下感兴趣的读者可以顺着这个入口进行源码剖析 /** * Return an array that contains all of the elements in this RDD. */ def collect(): Array[T] = { /* 提交 Job*/ val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray) Array.concat(results: _*) } 22foreach foreach 对 RDD 中的每个元素都应用 f 函数操作不返回 RDD 和 Array 而是返回Uint。图22表示 foreach 算子通过用户自定义函数对每个数据项进行操作。本例中自定义函数为 println()控制台打印所有数据项。 图 22 foreach 算子对 RDD 转换 23saveAsTextFile 函数将数据输出存储到 HDFS 的指定目录。 下面为 saveAsTextFile 函数的内部实现其内部 通过调用 saveAsHadoopFile 进行实现 this.map(x => (NullWritable.get(), new Text(x.toString))).saveAsHadoopFile[TextOutputFormat[NullWritable, Text]](path) 将 RDD 中的每个元素映射转变为 (null x.toString)然后再将其写入 HDFS。 图 23中左侧方框代表 RDD 分区右侧方框代表 HDFS 的 Block。通过函数将RDD 的每个分区存储为 HDFS 中的一个 Block。 图 23 saveAsHadoopFile 算子对 RDD 转换 24saveAsObjectFile saveAsObjectFile将分区中的每10个元素组成一个Array然后将这个Array序列化映射为NullBytesWritableY的元素写入HDFS为SequenceFile的格式。 下面代码为函数内部实现。 mapx=>NullWritable.getnew BytesWritableUtils.serializex 图24中的左侧方框代表RDD分区右侧方框代表HDFS的Block。 通过函数将RDD的每个分区存储为HDFS上的一个Block。 图24 saveAsObjectFile算子对RDD转换 25collect collect 相当于 toArray toArray 已经过时不推荐使用 collect 将分布式的 RDD 返回为一个单机的 scala Array 数组。在这个数组上运用 scala 的函数式操作。 图 25中左侧方框代表 RDD 分区右侧方框代表单机内存中的数组。通过函数操作将结果返回到 Driver 程序所在的节点以数组形式存储。 图 25 Collect 算子对 RDD 转换 26collectAsMap collectAsMap对KV型的RDD数据返回一个单机HashMap。 对于重复K的RDD元素后面的元素覆盖前面的元素。 图26中的左侧方框代表RDD分区右侧方框代表单机数组。 数据通过collectAsMap函数返回给Driver程序计算结果结果以HashMap形式存储。 图26 CollectAsMap算子对RDD转换 27reduceByKeyLocally 实现的是先reduce再collectAsMap的功能先对RDD的整体进行reduce操作然后再收集所有结果返回为一个HashMap。 28lookup 下面代码为lookup的声明。 lookupkeyKSeq[V] Lookup函数对KeyValue型的RDD操作返回指定Key对应的元素形成的Seq。 这个函数处理优化的部分在于如果这个RDD包含分区器则只会对应处理K所在的分区然后返回由KV形成的Seq。 如果RDD不包含分区器则需要对全RDD元素进行暴力扫描处理搜索指定K对应的元素。 图28中的左侧方框代表RDD分区右侧方框代表Seq最后结果返回到Driver所在节点的应用中。 图28 lookup对RDD转换 29count count 返回整个 RDD 的元素个数。 内部函数实现为 defcount():Long=sc.runJob(this,Utils.getIteratorSize_).sum 图 29中返回数据的个数为 5。一个方块代表一个 RDD 分区。 图29 count 对 RDD 算子转换 30top top可返回最大的k个元素。 函数定义如下。 topnumIntimplicit ordOrdering[T]Array[T] 相近函数说明如下。 ·top返回最大的k个元素。 ·take返回最小的k个元素。 ·takeOrdered返回最小的k个元素并且在返回的数组中保持元素的顺序。 ·first相当于top1返回整个RDD中的前k个元素可以定义排序的方式Ordering[T]。 返回的是一个含前k个元素的数组。 31reduce reduce函数相当于对RDD中的元素进行reduceLeft函数的操作。 函数实现如下。 Someiter.reduceLeftcleanF reduceLeft先对两个元素<KV>进行reduce函数操作然后将结果和迭代器取出的下一个元素<kV>进行reduce函数操作直到迭代器遍历完所有元素得到最后结果。在RDD中先对每个分区中的所有元素<KV>的集合分别进行reduceLeft。 每个分区形成的结果相当于一个元素<KV>再对这个结果集合进行reduceleft操作。 例如用户自定义函数如下。 fAB=>A._1+"@"+B._1A._2+B._2 图31中的方框代表一个RDD分区通过用户自定函数f将数据进行reduce运算。 示例 最后的返回结果为V1@[1]V2U@U2@U3@U412。 图31 reduce算子对RDD转换 32fold fold和reduce的原理相同但是与reduce不同相当于每个reduce时迭代器取的第一个元素是zeroValue。 图32中通过下面的用户自定义函数进行fold运算图中的一个方框代表一个RDD分区。 读者可以参照reduce函数理解。 fold"V0@"2 AB=>A._1+"@"+B._1A._2+B._2 图32 fold算子对RDD转换 33aggregate aggregate先对每个分区的所有元素进行aggregate操作再对分区的结果进行fold操作。 aggreagate与fold和reduce的不同之处在于aggregate相当于采用归并的方式进行数据聚集这种聚集是并行化的。 而在fold和reduce函数的运算过程中每个分区中需要进行串行处理每个分区串行计算完结果结果再按之前的方式进行聚集并返回最终聚集结果。 函数的定义如下。 aggregate[B]z Bseqop BA => Bcombop BB => B B 图33通过用户自定义函数对RDD 进行aggregate的聚集操作图中的每个方框代表一个RDD分区。 rdd.aggregate"V0@"2AB=>A._1+"@"+B._1A._2+B._2AB=>A._1+"@"+B_1A._@+B_.2 最后介绍两个计算模型中的两个特殊变量。 广播broadcast变量其广泛用于广播Map Side Join中的小表以及广播大变量等场景。 这些数据集合在单节点内存能够容纳不需要像RDD那样在节点之间打散存储。 Spark运行时把广播变量数据发到各个节点并保存下来后续计算可以复用。 相比Hadoo的distributed cache广播的内容可以跨作业共享。 Broadcast的底层实现采用了BT机制。 图33 aggregate算子对RDD转换 ②代表V。 ③代表U。 accumulator变量允许做全局累加操作如accumulator变量广泛使用在应用中记录当前的运行指标的情景。 本文转自大数据躺过的坑博客园博客原文链接http://www.cnblogs.com/zlslch/p/5723857.html如需转载请自行联系原作者

优秀的个人博客,低调大师

[BigData]关于Hadoop学习笔记第二天(PPT总结)(一)

Plan: 分布式文件系统与HDFS HDFS体系结构与基本概念 HDFS的shell操作 java接口及常用api HADOOP的RPC机制 HDFS源码分析 远程debug 自己设计一分布式文件系统? Distributed File System 1.数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统 。 2.是一种允许文件通过网络在多台主机上分享的文件系统,可让多机器上的多用户分享文件和存储空间。 3.通透性。让实际上是通过网络来访问文件的动作,由程序与用户看来,就像是访问本地的磁盘一般。 4.容错。即使系统中有某些节点脱机,整体来说系统仍然可以持续运作而不会有数据损失。 5.分布式文件管理系统很多,hdfs只是其中一种。适用于一次写入多次查询的情况,不支持并发写情况,小文件不合适。 HDFS的Shell 1.调用文件系统(FS)Shell命令应使用 bin/hadoop fs 的形式。 2.所有的FS shell命令使用URI路径作为参数。 URI格式是scheme://authority/path。HDFS的scheme是hdfs,对本地文件系统,scheme是file。其中scheme和authority参数都是可选的,如果未加指定,就会使用配置中指定的默认scheme。 例如:/parent/child可以表示成hdfs://namenode:namenodePort/parent/child,或者更简单的/parent/child(假设配置文件是namenode:namenodePort) 3.大多数FS Shell命令的行为和对应的Unix Shell命令类似。 HDFS fs命令 -help [cmd] //显示命令的帮助信息 -ls(r) <path> //显示当前目录下所有文件 -du(s) <path> //显示目录中所有文件大小 -count[-q] <path> //显示目录中文件数量 -mv <src> <dst> //移动多个文件到目标目录 -cp <src> <dst> //复制多个文件到目标目录 -rm(r) //删除文件(夹) -put <localsrc> <dst> //本地文件复制到hdfs -copyFromLocal //同put -moveFromLocal //从本地文件移动到hdfs -get [-ignoreCrc] <src> <localdst> //复制文件到本地,可以忽略crc校验 -getmerge <src> <localdst> //将源目录中的所有文件排序合并到一个文件中 -cat <src> //在终端显示文件内容 -text <src> //在终端显示文件内容 -copyToLocal [-ignoreCrc] <src> <localdst> //复制到本地 -moveToLocal <src> <localdst> -mkdir <path> //创建文件夹 -touchz <path> //创建一个空文件 HDFS的Shell命令练习 #hadoop fs -ls / 查看HDFS根目录 #hadoop fs -mkdir /test 在根目录创建一个目录test #hadoop fs -mkdir /test1 在根目录创建一个目录test1 #hadoop fs -put ./test.txt /test 或#hadoop fs -copyFromLocal ./test.txt /test #hadoop fs -get /test/test.txt . 或#hadoop fs -getToLocal /test/test.txt . #hadoop fs -cp /test/test.txt /test1 #hadoop fs -rm /test1/test.txt #hadoop fs -mv /test/test.txt /test1 #hadoop fs -rmr /test1 HDFS架构 NameNode DataNode Secondary NameNode HDFS Architecture 元数据存储细节 NameNode 1.是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表。接收用户的操作请求。 2.文件包括: ①fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息。(hdfs-site.xml的dfs.name.dir属性 ) ②edits:操作日志文件。 ③fstime:保存最近一次checkpoint的时间 3.以上这些文件是保存在linux的文件系统中。 NameNode的工作特点 1.Namenode始终在内存中保存metedata,用于处理“读请求” 2.到有“写请求”到来时,namenode会首先写editlog到磁盘,即向edits文件中写日志,成功返回后,才会修改内存,并且向客户端返回 3.Hadoop会维护一个fsimage文件,也就是namenode中metedata的镜像,但是fsimage不会随时与namenode内存中的metedata保持一致,而是每隔一段时间通过合并edits文件来更新内容。Secondary namenode就是用来合并fsimage和edits文件来更新NameNode的metedata的。 SecondaryNameNode 1.HA的一个解决方案。但不支持热备。配置即可。 2.执行过程:从NameNode上下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,替换旧的fsimage. 3.默认在安装在NameNode节点上,但这样...不安全! secondary namenode的工作流程 1.secondary通知namenode切换edits文件 2.secondary从namenode获得fsimage和edits(通过http) 3.secondary将fsimage载入内存,然后开始合并edits 4.secondary将新的fsimage发回给namenode 5.namenode用新的fsimage替换旧的fsimage 什么时候checkpiont 1.fs.checkpoint.period 指定两次checkpoint的最大时间间隔,默认3600秒。 2.fs.checkpoint.size 规定edits文件的最大值,一旦超过这个值则强制checkpoint,不管是否到达最大时间间隔。默认大小是64M。 Datanode 1.提供真实文件数据的存储服务。 2.文件块(block):最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。HDFS默认Block大小是128MB,以一个256MB文件,共有256/128=2个Block. dfs.block.size 3.不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间 4.Replication。多复本。默认是三个。 hdfs-site.xml的dfs.replication属性 Shell命令练习:验证块大小 1.方法:上传大于128MB的文件,观察块大小 2.验证:使用 http://hadoop0:50070 观察 HDFS的java访问接口——FileSystem •写文件 create •读取文件 open •删除文件delete • • •创建目录 mkdirs •删除文件或目录 delete •列出目录的内容 listStatus •显示文件系统的目录和文件的元数据信息 getFileStatus HDFS的FileSystem读取文件 private static FileSystem getFileSystem() throws URISyntaxException, IOException { Configuration conf = new Configuration(); URI uri = new URI("hdfs://hadoop240:9000"); final FileSystem fileSystem = FileSystem.get(uri , conf); return fileSystem; } /** * 读取文件,调用fileSystem的open(path) * @throws Exception */ private static void readFile() throws Exception { FileSystem fileSystem = getFileSystem(); FSDataInputStream openStream = fileSystem.open(new Path("hdfs://itcast0106:9000/aaa")); IOUtils.copyBytes(openStream, System.out, 1024, false); IOUtils.closeStream(openStream); } HDFS的FileSystem目录 /** * 创建目录,调用fileSystem的mkdirs(path) * @throws Exception */ private static void mkdir() throws Exception { FileSystem fileSystem = getFileSystem(); fileSystem.mkdirs(new Path("hdfs://itcast0106:9000/bbb")); } /** * 删除目录,调用fileSystem的deleteOnExit(path) * @throws Exception */ private static void rmdir() throws Exception { FileSystem fileSystem = getFileSystem(); fileSystem.delete(new Path("hdfs://itcast0106:9000/bbb")); } HDFS的FileSystem遍历目录 /** * 遍历目录,使用FileSystem的listStatus(path) * 如果要查看file状态,使用FileStatus对象 * @throws Exception */ private static void list() throws Exception{ FileSystem fileSystem = getFileSystem(); FileStatus[] listStatus = fileSystem.listStatus(new Path("hdfs://itcast0106:9000/")); for (FileStatus fileStatus : listStatus) { String isDir = fileStatus.isDir()?"目录":"文件"; String name = fileStatus.getPath().toString(); System.out.println(isDir+" "+name); } } FileSystem 用户代码操作HDFS时,是直接调用FileSystem的子类完成的。 Remote Procedure Call 1.RPC——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 2.RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。 3.hadoop的整个体系结构就是构建在RPC之上的(见org.apache.hadoop.ipc)。 RPC示例 public interface Bizable extends VersionedProtocol{ public abstract String hello(String name); } class Biz implements Bizable{ @Override public String hello(String name){ System.out.println("被调用了"); return "hello "+name; } @Override public long getProtocolVersion(String protocol, long clientVersion) throws IOException { System.out.println("Biz.getProtocalVersion()="+MyServer.VERSION); return MyServer.VERSION; } } public class MyServer { public static int PORT = 3242; public static long VERSION = 23234l; public static void main(String[] args) throws IOException { final Server server = RPC.getServer(new Biz(), "127.0.0.1", PORT, new Configuration()); server.start(); } } public class MyClient { public static void main(String[] args) throws IOException { final InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", MyServer.PORT); final Bizable proxy = (Bizable) RPC.getProxy(Bizable.class, MyServer.VERSION, inetSocketAddress, new Configuration()); final String ret = proxy.hello("吴超"); System.out.println(ret); RPC.stopProxy(proxy); } } RPC调用流程 ClientProtocol l是客户端(FileSystem)与NameNode通信的接口。 DatanodeProtocol l是DataNode与NameNode通信的接口 NamenodeProtocol l是SecondaryNameNode与NameNode通信的接口。 HDFS读过程 1.初始化FileSystem,然后客户端(client)用FileSystem的open()函数打开文件 2.FileSystem用RPC调用元数据节点,得到文件的数据块信息,对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。 3.FileSystem返回FSDataInputStream给客户端,用来读取数据,客户端调用stream的read()函数开始读取数据。 4.DFSInputStream连接保存此文件第一个数据块的最近的数据节点,data从数据节点读到客户端(client) 5.当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。 6.当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。 7.在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。 8.失败的数据节点将被记录,以后不再连接。 HDFS写过程 1.初始化FileSystem,客户端调用create()来创建文件 2.FileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件,元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。 3.FileSystem返回DFSOutputStream,客户端用于写数据,客户端开始写入数据。 4.DFSOutputStream将数据分成块,写入data queue。data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。 5.DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。 6.当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。 7.如果数据节点在写入的过程中失败,关闭pipeline,将ack queue中的数据块放入data queue的开始,当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。 练习题 1.练习shell命令 2.在HDFS创建一个文本文件hadoop.test。内容自定;然后,用Java程序在本地终端打印hadoop.test文件内容 3.用Java程序实现copyFromLocal 思考题 1.hdfs的组成部分有哪些,分别解释一下 2.hdfs的高可靠如何实现 3.hdfs的常用shell命令有哪些 4.hdfs的常用java api有哪些 5.请用shell命令实现目录、文件的增删改查 6.请用java api实现目录、文件的增删改查 本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/4566838.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册