hadoop相关(以期为单位)

2020年05月16日 阅读数:85
这篇文章主要向大家介绍hadoop相关(以期为单位),主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

学习Hadoop不错的系列文章

1)Hadoop学习总结html

  (1)HDFS简介前端

  地址:http://forfuture1978.iteye.com/blog/615033java

  (2)HDFS读写过程解析node

  地址:http://blog.csdn.net/forfuture1978/article/details/6001302mysql

  (3)Map-Reduce入门linux

  地址:http://blog.csdn.net/forfuture1978/article/details/6043926ios

  (4)Map-Reduce的过程解析web

  地址:http://blog.csdn.net/forfuture1978/article/details/6043929算法

  (5)Hadoop的运行痕迹sql

  地址:http://blog.csdn.net/forfuture1978/article/details/6028559

2)Hadoop-0.20.0源代码分析

  (1)Hadoop-0.20.0源代码分析(01)

  地址:http://blog.csdn.net/shirdrn/article/details/4569702

  (2)Hadoop-0.20.0源代码分析(02)

  地址:http://blog.csdn.net/shirdrn/article/details/4571445

  (3)Hadoop-0.20.0源代码分析(03)

  地址:http://blog.csdn.net/shirdrn/article/category/595039/3

  (4)Hadoop-0.20.0源代码分析(04)

  地址:http://blog.csdn.net/shirdrn/article/details/4574402

  (5)Hadoop-0.20.0源代码分析(05)

  地址:http://blog.csdn.net/shirdrn/article/details/4577243

  (6)Hadoop-0.20.0源代码分析(06)

  地址:http://blog.csdn.net/shirdrn/article/details/4581473

  (7)Hadoop-0.20.0源代码分析(07)

  地址:http://blog.csdn.net/shirdrn/article/details/4581666

  (8)Hadoop-0.20.0源代码分析(08)

  地址:http://blog.csdn.net/shirdrn/article/details/4581666

  (9)Hadoop-0.20.0源代码分析(09)

  地址:http://blog.csdn.net/shirdrn/article/details/4590359

  (10)Hadoop-0.20.0源代码分析(10)

  地址:http://blog.csdn.net/shirdrn/article/details/4594892

  (11)Hadoop-0.20.0源代码分析(11)

  地址:http://blog.csdn.net/shirdrn/article/details/4598295

  (12)Hadoop-0.20.0源代码分析(12)

  地址:http://blog.csdn.net/shirdrn/article/details/4598419

  (13)Hadoop-0.20.0源代码分析(13)

  地址:http://blog.csdn.net/shirdrn/article/details/4604229

  (14)Hadoop-0.20.0源代码分析(14)

  地址:http://blog.csdn.net/shirdrn/article/details/4608377

  (15)Hadoop-0.20.0源代码分析(15)

  地址:http://blog.csdn.net/shirdrn/article/details/4610578

  (16)Hadoop-0.20.0源代码分析(16)

  地址:http://blog.csdn.net/shirdrn/article/details/4631518

  (17)Hadoop-0.20.0源代码分析(17)

  地址:http://blog.csdn.net/shirdrn/article/details/4634119

  (18)Hadoop-0.20.0源代码分析(18)

  地址:http://blog.csdn.net/shirdrn/article/details/4636169

  (19)Hadoop-0.20.0源代码分析(19)

  地址:http://blog.csdn.net/shirdrn/article/details/4639345


Hadoop集群(第1期)_CentOS安装配置

 

一、准备安装

 

1.1 系统简介

  CentOS 是什么?

 

  CentOS是一个基于Red Hat 企业级 Linux 提供的可自由使用的源代码企业级的 Linux 发行版本。每一个版本CentOS 都会得到七年支持(经过安全更新方式)。版本的 CentOS两年发行一次,而每一个版本的 CentOS 会按期(大概每六个月)更新一次,以便支持新的硬件。这样,创建一个安全、低维护、稳定、高预测性、高重复性的 Linux 环境。

  CentOS(Community Enterprise Operating System)是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。因为出自一样的源代码,所以有些要求高度稳定性的服务器以CentOS替代商业版的Red Hat Enterprise Linux使用。二者不一样,在于CentOS不包含封闭源代码软件

  CentOS是一个开源软件贡献者和用户的社区。它对RHEL源代码进行从新编译,成为众多发布新发行版本的社区当中的一个,而且在不断的发展过程当中,CentOS社区不断与其余的同类社区合并,使CentOS Linux逐渐成为使用最普遍的RHEL兼容版本。CentOS Linux的稳定性不比RHEL差,惟一不足的就是缺少技术支持,由于它是由社区发布的免费版。

  CentOS LinuxRHEL产品有着严格版本对应关系,例如使用RHEL4源代码从新编译发布的是CentOS Linux 4.0,RHEL5对应的是CentOS Linux 5.0,RHEL6对应的是CentOS Linux 6。因为RHEL产品的生命周期较长(一般具备3~5年的官方支持),所以Red Hat公司在RHEL系列产品发布后每隔一段时间,都会将累积的更新程序从新打包成为更新的发行版进行发布,一般称为RHEL Update。

  例如,RHEL5的第1个更新版本叫作RHEL 5 Update 1,用户一般也称为RHEL 5.1。对Red Hat公司发布的每个RHEL Update CentOS社区都会发布对应的更新发行版,例如根据RHEL 5的Update 1更新程序源码包,CentOS会从新编译并打包发布CentOS Linux 5.1版。CentOS Linux和与之对应版本号的RHEL发行版具备软件包级别的二进制兼容性,即某个RPM软件包若是能够安装运行在RHEL产品中,就能够正常地安装运行在对应版本的CentOS Linux中。CentOS Linux因为同时具备与RHEL的兼容性和企业级应用的稳定性,又容许用户自由使用,所以获得了愈来愈普遍的应用。

 

  CentOS特色

  • 能够把CentOS理解为Red Hat AS系列!它彻底就是对Red Hat AS进行改进后发布的!各类操做、使用和RED HAT没有区别!
  • CentOS彻底免费,不存在RED HAT AS4须要序列号的问题。
  • CentOS独有yum命令支持在线升级,能够即时更新系统,不像RED HAT那样须要花钱购买支持服务!
  • CentOS修正了许多RED HAT AS的BUG!
  • CentOS版本说明: CentOS3.1 等同于 RED HAT AS3 Update1 CentOS3.4 等同于 RED HAT AS3 Update4 CentOS4.0 等同于 RED HAT AS4。

 

1.2 安装版本

  本次安装咱们选择CetOS6.0版本,下面从几个方面介绍一下这个版本。

  • 集成基于内核的虚拟化。CentOS 6.0集成了基于内核的虚拟化,将KVM管理程序彻底集成到内核中。这样的功能能够帮助CentOS 6.0用户在主机之间轻松迁移虚拟机,更加灵活地部署和管理IT资源,有效为企业节省资源。利用内核的硬件抽象使应用程序可以独立于底层硬件,而且提升 CPU和内存可扩展性,使每一个服务器可容纳更多虚拟机。
  • 提高系统和资源管理功能。基于标准的Linux可管理性规范(SBLIM)使用基于Web的企业管理(WBEM)来管理系统。用Dracut取代mkinitrd,最大限度地减小底层硬件改变的影响,更易于维护,并使支持第三方驱动程序更容易。
  • 增强电源管理,按时的内核改进使CentOS 6.0能够将没有活动任务的处理器置为空闲状态,以达到下降CPU的温度和更进一步减小能耗。
  • 在一种叫作控制组(即cgroups)的新框架的帮助下CentOS 6.0提供对硬件资源的细颗粒度控制、分配和管理。cgroups运行在进程组水平上,可被用于为应用管理从CPU、内存、网络和硬盘I/O的资源。
  • 加强了系统的可靠性、可用性和适用性 。CentOS 6.0利用新硬件能力提供热插拔特性,而且能够经过AER的PCIe设备的加强错误检查。CentOS 6.0包括高级数据完整性特性(DIF/DIX)。这类特性经过硬件检查和检验来自应用的数据。自动缺陷报告工具(ABRT)的引进提供了肯定和报告系统 异常状况,包括内核故障和用户空间应用崩溃等。
  • 改进了可伸缩性和内核性能 。CentOS 6.0提供了适应将来系统的可伸缩性,其可伸缩性能力从对大量CPU和内存配置的优化的支持处处理更多数量的系统互联总线和外设的能力。在虚拟化变得同裸机部署同样无处不在之时,这些能力适合于裸机环境和虚拟化环境。
  • CentOS 6.0改进了内核性能 ,能够经过让更高优先级的进程在最低限度的较低优先级处理干扰的条件下,更公平地在处理器之间分配计算时间。同时CentOS 6.0将多种多处理器锁同步进行改进,以消除没必要要的锁定事件、用睡眠锁定代替许多旋转(spin)锁定和采用更高效的锁定基元。
  • 稳定的应用程序开发与生产平台 。CentOS 6.0是一个高性能、高度可扩展、分布式、基于内存的对象缓存系统,大大提升了动态Web应用程序的速度。在Web基础架构上主要改进了Apache、 Squid和Memcached三个方面的改进。在Java性能支持上,CentOS 6.0和OpenJDK的紧密集成包括在SystemTap中支持Java探测器,从而可支持更好的Java调试。同时,CentOS 6.0也在逐步完善Tomcat 6的支持。

 

  官方网站与文档

 

官方主页: http://www.centos.org/

官方Wiki: http://wiki.centos.org/

官方中文文档 :http://wiki.centos.org/zh/Documentation

安装说明: http://www.centos.org/docs/

 

1.3 硬件信息

  如今Linux发行版安装程序硬件识别能力都比较强,即便不查询什么硬件信息,安装操做系统也没有什么大问题,不过对于很是新的硬件和笔记本电脑这样比较特殊的设备,仍是建议在网络上查询一下相关硬件的信息,以确保硬件能够被驱动。这里列举几种可能须要重点考察的硬件,对于任何一种发行版都须要注意以下这些问题。

 

  • 主板芯片组支持。这是一组比较重要的硬件信息,可能影响到硬盘是否能够使用、能够启用UDMA,是否能够使用ACPI或APM电源管理等。这里的支持程序老是和内核版本相关的,考察的时候要注意对应的内核版本。
  • 网络设备支持。目前,对于通常用户主要是以太网卡和无线网卡,有些无线网卡的驱动尚未被整合进内核,但确实已经有驱动支持了。
  • 声卡。Linux对声音芯片的支持在历史上饱受诟病,但自从ALSA(Advanced Linux Sound Architecture)诞生以来,这个问题已经获得了很大程序的缓解,如今,ALSA是2.6内核的一部分。不过,仍然有一些声卡问题不时地出现。特别的,目前大多数的用户使用的是主板板载声卡,在安装系统以前应该考察一下Linux内核对该主板芯片声效功能的支持。
  • 显卡。主流的显卡目前均可以获得支持,若是须要的话,看一下显卡芯片的厂商、型号、显存大小基本就能够了,若是但愿省事的话,能够考虑选择性能虽然不强,但开源驱动的稳定性和性能最好的Intel整合显卡,而追求高性能显卡的用户能够考虑NVIDIA芯片并在往后使用官方的驱动程序,来得到更好的3D性能,ATI/ADM显卡目前的Linux驱动是不理想的,但AMD已经开放了芯片的技术规范,将来必定会获得开源驱动的良好支持。
  • 其余外设。USB键盘和鼠标通常均可以被支持,少数最低端的硬盘盒的移动硬盘可能不会被支持,摄像头这些小硬件大部分均可以被支持了,另外就是一些笔记本电脑,须要考察一下。

  为了有备无患,要考察的信息仍是比较多的,除了上网查找和询问周围的朋友外,使用Live CD进行体验也是一个很不错的办法。

 

1.4 硬盘分区

  在计算机上安装Linux系统,对硬盘进行分区是一个很是重要的步骤,下面介绍几个分区方案。

  •  方案1(桌面

/boot:用来存放与Linux系统启动有关的程序,好比启动引导装载程序等,建议大小为100MB。

/:Linux系统的根目录,全部的目录都挂在这个目录下面,建议大小为5GB以上。

/home:存放普通用户的数据,是普通用户的宿主目录,建议大小为剩下的空间。

swap:实现虚拟内存,建议大小是物理内存的1~2倍。

 

  • 方案2(服务器

 

/boot:用来存放与Linux系统启动有关的程序,好比启动引导装载程序等,建议大小为100MB。

/usr:用来存放Linux系统中的应用程序,其相关数据较多,建议大于3GB以上。

/var:用来存放Linux系统中常常变化的数据以及日志文件,建议大于1GB以上。

/home:存放普通用户的数据,是普通用户的宿主目录,建议大小为剩下的空间。

/:Linux系统的根目录,全部的目录都挂在这个目录下面,建议大小为5GB以上。

/tmp:将临时盘在独立的分区,可避免在文件系统被塞满时影响到系统的稳定性。建议大小为500MB以上。

swap:实现虚拟内存,建议大小是物理内存的1~2倍。

 

二、光盘安装

 

2.1 安装引导

  首先要设置计算机的BIOS启动顺序为光驱启动,保存设置后将安装光盘放入光驱,从新启动计算机。

  计算机启动之后会出现以下图所示的界面。

 

 

  你能够直接按下<Enter>来进入图形界面安装方式或者等待60

  下面是上图所示引导菜单选项以下:

 

  • Install or upgrade an existing system(安装或升级现有系统):

  这个选项是默认的。 选择此选项,安装到您的计算机使用CentOS的图形安装程序的系统。

  • Install system with basic video driver(安装系统,基本的视频驱动程序):

  此选项容许您安装CentOS的模式,即便在图形安装程序没法加载视频卡的正确驱动程序为您的。若是你的屏幕上出现扭曲或一片空白时使用的安装或升级现有系统的选项,从新启动计算机,并尝试此选项。

  • Rescue installed system(救援安装的系统):

  选择这个选项来修复您的安装CentOS系统,防止正常启动你一个问题。虽然CentOS是一个很是稳定的计算平台,它是偶然的问题仍有可能发生,防止启动。 救援环境包含实用程序,容许您解决这些问题,品种繁多。

  • Boot from local drive(从本地驱动器启动):

  此选项将引导从第一个安装的磁盘系统。 若是你意外地启动这个光盘,使用未当即启动安装程序这是从硬盘启动选项。

 

2.2 检测光盘介质

  以下图所示,若是是一张完整的安装盘,能够直接单击"Skip"按钮跳过,不然单击"OK"按钮检测安装盘的完整性。

 

 

  备注:若是你肯定你所下载的DVD或光盘没有问题的话,那么这里能够选择'Skip', 不过,你也能够按下'OK'来进行DVD的分析,由于经过DVD的分析后,后续的安装比较不会出现奇怪的问题。 不过若是你按下'OK'后,程式会开始分析光盘内的全部文件的资讯,会花很是多的时间喔!

 

2.3 安装欢迎界面

  当检测完电脑硬件信息后,进入安装欢迎界面,以下图所示。

 

 

2.4 选择安装过程当中的语言

  单击"Next"按钮进入以下图所示的界面,选择安装过程当中使用的语言,此处选择"Chinese (Simplified)(中文(简体))"。

 

 

2.5 选择键盘布局类型

  选择完安装过程当中的语言后,单击"下一步"按钮进入以下图所示的界面,选择键盘类型通常默认会选择"美国英语式(U.S.English)",即美式键盘,在此使用默认的选择。

 

 

2.6 选择设备

  选择一种存储设备进行安装。"基本存储设备"做为安装空间的默认选择,适合哪些不知道应该选择哪一个存储设备的用户。而"指定的存储设备"则须要用户将系统安装指定到特定的存储设备上,能够是本地某个设备,固然也能够是SAN(存储局域网)。用户一旦选择了这个选项,能够添加FCoE/iSCSI/zFCP磁盘,而且可以过滤掉安装程序应该忽略的设备。这里选择"基本存储设备",单击"下一步"按钮。

 

  备注基本存储设备:用于台式机和笔记本等等;指定存储设备:用于服务器等等。

 

2.7 初始化硬盘

  若是硬盘上没有找到分区表,安装程序会要求初始化硬盘。此操做使硬盘上的任何现有数据没法读取。若是您的系统具备全新的硬盘没有操做系统安装,或删除硬盘上的全部分区,则单击 "从新初始化"。

 

  备注:安装程序将为您提供一个单独的对话框,为每一个磁盘,它没法读取一个有效的分区表。单击"忽略全部"按钮,或"从新初始化全部"按钮,可将应用到全部设备相同的答案。

 

2.8 设置主机名与网络

  安装程序会提示您提供和域名为这台计算机的主机名格式,设置主机名和域名 。 许多网络有DHCP(动态主机配置协议)服务,它会自动提供域名系统的一个链接,让用户输入一个主机名。除非您有特定须要定制的主机名和域名,默认设置 localhost.localdomain 是一个很好的选择大多数用户。咱们这里按照下表进行填写主机名和域名,详情请看"Hadoop集群_第2期_机器信息分布表"。

 

表2.8-1 机器信息分布

 

机器名称

IP地址

Master.Hadoop 

192.168.1.2 

Salve1.Hadoop 

192.168.1.3 

Salve2.Hadoop 

192.168.1.4 

Salve3.Hadoop 

192.168.1.5

 

 

  设置固定IP

  选择『配置网络』à『有线』à『eth0』à『编辑』,弹出编辑窗口上选择"IPv4设置",打开"方法"边上的下拉菜单,选择"手动"。单击 "添加"按钮,依次输入本机的IP子网掩码网关。在下面的"DNS服务器"处输入DNS地址。最后,点击"应用"按钮便可。

 

  按照前面的表2.8-1进行配置IP地址。

 

2.9 时区选择

  由于全世界分为24个时区,因此,要告知系统时区在哪里。以下图所示,你能够选择北京,或直接用鼠标在地图上选择。要特别注意UTC,它与"夏令时"有关,咱们不须要选择这个选项,不然会形成时区混乱,致使系统显示的时间与本地时间不一样。

 

 

2.10 设置管理员密码

  下面是最重要的"系统管理员的口令"设置,以下图所示。在Linux中,系统管理员的默认名称为root,请注意,这个口令很重要。至少6个字符以上,含有特殊符号,并要记好。

 

  备注:当你设置好进入下一步时,因为你的密码可能设置的过于简单,此时会弹出一个对话框,若是你要坚持你设置的密码,能够选择"不管如何都是用"。

 

2.11 磁盘分区配置

  为方便你们分区硬盘,CentOS预设给了咱们分区模式,分别为:

 

  备注:咱们实际是直接选的是"使用全部空间",当时就是图方便,但实际工做中却要按照实际的要求对硬盘进行分区,合理利用硬盘。而这里选择"建立自定义布局",按照1.4小节给出的服务器分区方案对硬盘从新分区。

 

  下面是对每一个选项的详细介绍:

 

  • 使用全部空间(Use All Space ):

  选择此选项,删除您硬盘上的全部分区(这包括如Windows的NTFS分区VFAT或其余操做系统建立的分区)。

  • 替换现有的Linux系统(Replace Existing Linux System):

  选择此选项,以消除先前的Linux安装建立的分区。 这不会删除其余分区(如VFAT或FAT32分区),你可能对您的硬盘驱动器。

  • 缩小现有系统(Shrink Current System):

  选择此选项,调整当前的数据和分区安装在手动释放的空间是一个默认的红帽企业Linux布局。

  • 使用剩余空间(Use Free Space):

  选择此选项以保留您当前的数据和分区并安装在未使用的存储驱动器上的空间可用的Scientific。 确保有足够的存储驱动器上的可用空间,而后再选择此选项。

  • 建立自定义布局(Create Custom Layout):

  选择此选项,手动存储设备进行分区并建立自定义布局。

 

  下面是"建立自定义布局"的步骤:

 

  第一步:选择"建立自定义布局",按"下一步"按钮;以下图所示。

 

  第二步:建立"/boot"

  选择要分区的空闲空间,按下"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

 

  挂载点:选择"/boot";文件系统类型:使用默认"Ext4 日志文件系统";大小:输入分配的大小100,以 MB 为单位;其它大小选项:选择"固定大小";点"肯定"按钮。

 

  第三步:建立"/"

  继续选择空闲空间,按下"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

  挂载点:选择"/";文件系统类型:使用默认"Ext4 日志文件系统";大小:输入分配的大小5000,以 MB 为单位;其它大小选项:选择"固定大小";点"肯定"按钮。

 

  第四步:建立交换空间

  继续选择空闲空间,点"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

  文件系统类型:选择"swap";大小:输入分配的大小1000,以 MB 为单位;其它大小选项:选择"固定大小"。点"肯定"按钮。

 

  备注:"交换空间"用于实现虚拟内存,建议大小是物理内存的1~2倍。

  第五步:建立"/usr"

  继续选择空闲空间,按下"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

  挂载点:选择"/usr";文件系统类型:使用默认"Ext4 日志文件系统";大小:输入分配的大小3000,以 MB 为单位;其它大小选项:选择"固定大小";点"肯定"按钮。

 

  第六步:建立"/var"

  继续选择空闲空间,按下"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

  挂载点:选择"/var";文件系统类型:使用默认"Ext4 日志文件系统";大小:输入分配的大小1000,以 MB 为单位;其它大小选项:选择"固定大小",点"肯定"按钮。

  备注:图与第五步基本相同,故略。

  第七步:建立"/tmp"

  继续选择空闲空间,按下"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

  挂载点:选择"/tmp";文件系统类型:使用默认"Ext4 日志文件系统";大小:输入分配的大小500,以 MB 为单位;其它大小选项:选择"固定大小",点"肯定"按钮。

  备注:图与第五步基本相同,故略。

  第八步:"/home"分区

  继续选择空闲空间,点"建立"后,就会出现以下的画面。选择"标准分区"后,点击"生成"。

  挂载点:选择"/home";文件系统类型:使用默认"Ext4 日志文件系统";其它大小选项:选择"使用所有可用空间",点"肯定"按钮。

 

 

  至此,分区已所有建立完毕,若是不满意,还能够点击"重设"按钮进行更改。若是肯定,就点"下一步"按钮后,弹出"是否格式化如下已存在的硬盘",选择"格式化"。

 

 

  安装程序会提示您确认您所选的分区选项。单击"将修改写入磁盘",以容许安装程序在您的硬盘进行分区,并安装系统更改。

 

 

2.12引导装载程序设置

  以下图所示为GRUB引导安装窗口,可采用默认设置,直接单击"下一步"按钮。

 

  备注:设置引导装载程序密码的方法是,选择"使用引导装载程序口令",在弹出的窗口中输入密码。咱们实际并无设置此项

 

2.13选择安装的软件包

  可选的服务器类型更多,并且默认安装是一个很是小的甚至不完整的系统。选中"如今自定义",而后单击"下一步"按钮,以下图所示。

 

 

  可选的类型说明以下:

  • Desktop:基本的桌面系统,包括经常使用的桌面软件,如文档查看工具。
  • Minimal Desktop:基本的桌面系统,包含的软件更少。
  • Minimal:基本的系统,不含有任何可选的软件包。
  • Basic Server:安装的基本系统的平台支持,不包含桌面。
  • Database Server:基本系统平台,加上MySQL和PostgreSQL数据库,无桌面。
  • Web Server:基本系统平台,加上PHP,Web server,还有MySQL和PostgreSQL数据库的客户端,无桌面。
  • Virtual Host:基本系统加虚拟平台。
  • Software Development Workstation:包含软件包较多,基本系统,虚拟化平台,桌面环境,开发工具。

 

  备注:咱们这里安装Linux是做为服务器使用,没有必要安装图形界面,故选择的是最小化安装(Minimal),若是想安装图形界面,能够选择桌面安装(Desktop)。

由于上一步咱们选择的是最小化安装(Minimal),因此在如下软件包设置画面中,全部的软件包默认都是没有被选中的状态。这里咱们只选择咱们须要的软件包来安装。

 

  首先,选中「基本系统」中的「基本」。

 

 

  而后,选中「开发」中的「开发工具」。

 

 

  最后,在「语言支持」中选中「中文支持」。若是您有支持其余语言的须要,也能够在这里一并选择。最后点击"下一步",开始安装。

 

 

2.14开始安装Linux系统

  开始安装。在安装的画面中,会显示还须要多少时间,每一个软件包的名称,以及该软件包的简单说明,以下图所示。

 

 

  等到安装完以后,一切就都完成了。出现最后这个画面时,请将光盘拿出来,并按下"从新引导"按钮去启动,以下图所示。

 

 

三、环境设置

  在CentOS 6刚刚安装好以后,默认的安全设置以及服务启动等等可能并不符合咱们的需求,因此在搭建各类系统服务以前,咱们先将系统环境设置为最为简洁的状态,在之后开通各类服务的时候,在按照服务的需求来进行具体的定制。

 

3.1 创建通常用户

  root 用户拥有控制整个系统最高权限,若是在通常的操做中咱们用 root 来进行,很容易不当心对系统形成误删、误更改等操做,因此咱们首先创建通常用户,用通常用户来应付平常的系统操做。

 

  

  在通常用户创建成功之后,咱们就能够用通常用户来登陆系统进行平常的系统管理。在一些须要 root 权限的状况,咱们能够经过如下方式在通常用户的登陆状态下直接登陆为 root 用户来进行须要 root 权限的操做。

 

 

  如以上示范,咱们能够在通常用户登陆的状态下经过"su -"命令来直接登陆为 root 用户。

 

3.2 关闭防火墙及SELinux

  本站文档是假定「服务器在防火墙之内」的前提下编纂的,在这个前提下,服务器自己在内部网络是不须要防火墙的(在须要抵御内部安全威胁的状况下,您也能够用您在 iptables 方面的相关知识,根据实情设置防火前,并保证服务器端防火墙启动的状态)。另外,在通常状况下,咱们不须要 SELinux 复杂的保护,因此也将其设置为无效的状态。

 

  关闭防火墙

 

 

  关闭SELinux

   

  用下面命令执行,并修改内容以下所示:

 

vim /etc/sysconfig/selinux

 

SELINUX=enforcing

SELINUX=disabled

 

 

  接着在执行以下命令:

 

setenforce 0

getenforce

 

 

3.3 关闭不须要的服务

  使用下面命令进行关闭不须要的服务:

 

for SERVICES in abrtd acpid auditd avahi-daemon cpuspeed haldaemon mdmonitor messagebus udev-post; do chkconfig ${SERVICES} off; done

 

 

  备注:该文档因为是过后好久才编写,当时在安装Linux的时候,因此本节的3.2和3.3并无进行,以致于后来遇到很多麻烦,因此在这里把这些遗漏的补上。另外本文档全部的截图并非当时实际安装,而是为了编写此文档在虚拟机上安装时截的图,因此个别图上的信息反映的是虚拟机的硬件信息,在实际中则不同,安装时请注意细微差异。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.1.rar


Hadoop集群(第2期)_机器信息分布表

一、分布式环境搭建

  采用4台安装Linux环境的机器来构建一个小规模的分布式集群。

图1 集群的架构

 

  其中有一台机器是Master节点,即名称节点,另外三台是Slaver节点,即数据节点。这四台机器彼此间经过路由器相连,从而实验相互通讯以及数据传输。它们均可以经过路由器访问Internet,实验网页文档的采集。

二、集群机器详细信息

2.1 Master服务器

名称

详细信息

机器名称

Master.Hadoop

机器IP地址

192.168.1.2

最高用户名称(Name

root 

最用用户密码(PWD

hadoop(全小写)

通常用户名称(Name

hadoop(全小写)

通常用户密码(PWD

hadoop(全小写)

2.2 Slave1服务器

名称

详细信息

机器名称

Slave1.Hadoop 

机器IP地址

192.168.1.3 

最高用户名称(Name

root 

最用用户密码(PWD

hadoop(全小写)

通常用户名称(Name

hadoop(全小写)

通常用户密码(PWD

hadoop(全小写)

 

2.3 Slave2服务器

名称

详细信息

机器名称

Slave2.Hadoop 

机器IP地址

192.168.1.4 

最高用户名称(Name

root 

最用用户密码(PWD

hadoop(全小写)

通常用户名称(Name

hadoop(全小写)

通常用户密码(PWD

hadoop(全小写)

 

2.4 Slave3服务器

名称

详细信息

机器名称

Slave3.Hadoop 

机器IP地址

192.168.1.5 

最高用户名称(Name

root 

最用用户密码(PWD

hadoop(全小写)

通常用户名称(Name

hadoop(全小写)

通常用户密码(PWD

hadoop(全小写)

 

  备注:

      添加新用户命令:useradd;修改新用户密码:passwd 用户名

      退出当前用户:exit;         登陆root用户:su –

三、集群机器实际布局

  下面是几张Hadoop集群实际机器的部署状况,能够从图中看到那时的咱们怎么实际配置Hadoop集群的。

 

3.1 Hadoop工做集群

  该Hadoop集群机器是学习和研究之用,上面运行着已经搭建好的的Hadoop平台以及运行着一些实际程序。

 

图3.1-1 Hadoop工做集群部署图(1)

 

图3.1-2 Hadoop工做集群部署图(2)

  上面从两个角度来分别观察Hadoop集群部署,做为Hadoop集群的Master节点,用的是机器较为不错的Dell,而三台Slave机器则是实验室淘汰的Lenovo,用一个小路由器他们组成了一个局域网。

 

图3.1-3 路由器特写

3.2 Hadoop实验集群

  为了方便新成员练习Hadoop技术,又防止在实际Hadoop集群上破坏已运行的程序,故另外弄了两台旧Lenovo电脑组成:一个"主——TMaster";一个"辅——TSlave"。

 

图3.2-1 Hadoop实验集群部署

 

  上面就是实验室Hadoop集群的样子,虽然很简陋,但足够学习用了。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.2.rar

Hadoop集群(第3期)_VSFTP安装配置

  

一、VSFTP简介

  VSFTP是一个基于GPL发布的类Unix系统上使用的FTP服务器软件,它的全称是Very Secure FTP 今后名称能够看出来,编制者的初衷是代码的安全。

  安全性是编写VSFTP的初衷,除了这与生俱来的安全特性之外,高速与高稳定性也是VSFTP的两个重要特色。

  在速度方面,使用ASCII代码的模式下载数据时,VSFTP的速度是Wu-FTP的两倍,若是Linux主机使用2.4.*的内核,在千兆以太网上的下载速度可达86MB/S。

  在稳定方面,VSFTP就更加的出色,VSFTP在单机(非集群)上支持4000个以上的并发用户同时链接,根据Red Hat的Ftp服务器(ftp.redhat.com)的数据,VSFTP服务器能够支持15000个并发用户。

 

二、VSFTP安装及配置

    安装该软件须要使用最高用户(root)进行安装,不然不能进行。

 

 

2.1 安装

  首先用命令检查VSFTP是否已经安装。

 

chkconfig –list | grep vsftpd

    

  显示结果以下,没有任何反应,说明没有安装VSFTP。

 

 

  接着使用yum命令直接安装

 

yum –y install vsftpd

 

 

  上图中表示正在下载,须要耐心等一下,若是网络不顺畅通,也可能须要下载失败,不过不要担忧,只要在从新提交一次命令就行。

 

 

  从上面的结果中看出,已经成功安装。而后为它建立日志文件:

 

touch /var/log/vsftpd.log

 

 

  这样简单的两个命令就完成了vsftp的安装,可是若是你如今想这样ftp://your_ip来访问的话,那还不行,还须要配置权限!

 

2.2 启动与配置自启动

  再次使用"chkconfig –list | grep vsfpd"来查看vsftpd服务启动项状况;

  若是看到的是以下显示的结果:

 

 

  服务所有都是关闭(off)的,注意这里的关闭(off)表示的是服务器启动的时候是否会自启动服务,咱们使用以下命令来配置其自启动:

 

chkconfig vsftpd on

 

  或者

 

chkconfig –level 2345 vsftpd on

 

  执行结果以下:

 

 

  查看与管理ftp服务:

 

启动ftp服务:service vsftpd start

查看ftp服务状态:service vsftpd status

重启ftp服务:service vsftpd restart

关闭ftp服务:service vsftpd stop

 

2.3 配置vsfpd服务

  编辑/etc/vsftpd/vsftpd.conf文件,配置vsftp服务:

 

vim /etc/vsftpd/vsftpd.conf

 

 

  上图中先显示出"/etc/vsftpd"下面有哪些文件,而后在用"vim"编辑器进行修改。

 

   先按键盘上的"a"就能够进行编辑了,按照下面进行操做。

 

anonymous_enable=YES --> anonymous_enable=NO //不容许匿名用户访问,默认是容许

xferlog_file=/var/log/vsftpd.log #设定vsftpd的服务日志保存路径。注意,该文件默认不存在。必需要手动touch出来

#idle_session_timeout=600 --> idle_session_timeout=600 //会话超时,客户端链接到ftp但未操做,默认被注释掉,可根据我的状况修改

#async_abor_enable=YES --> async_abor_enable=YES //支持异步传输功能,默认是注释掉的,去掉注释

#ascii_upload_enable=YES --> ascii_upload_enable=YES //支持ASCII模式的下载功能,默认是注释掉的,去掉注释

#ascii_download_enable=YES --> ascii_download_enable=YES //支持ASCII模式的上传功能,默认是注释掉的,去掉注释

#ftpd_banner=Welcome to blah FTP service //FTP的登陆欢迎语,自己是被注释掉的,去不去都行

#chroot_local_user=YES --> chroot_local_user=YES

//禁止本地用户登出本身的FTP主目录,自己被注释掉,去掉注释

 

  下面几个都是已经去掉的,只是写出来,明白其用意。

 

local_enable=YES //容许本地用户访问,默认就是YES,不用改

write_enable=YES //容许写入,默认是YES,不用改

local_umask=022 //上传后文件的权限掩码,不用改

dirmessage_enable=YES //开启目录标语,默认是YES,开不开无所谓,我是默认就行

xferlog_enable=YES //开启日志,默认是YES,不用改

connect_from_port_20=YES //设定链接端口20

xferlog_std_format=YES //设定vsftpd的服务日志保存路径,不用改

 

pam_service_name=vsftpd //设定pam服务下vsftpdd的验证配置文件名,不用改

userlist_enable=YES //拒绝登陆用户名单,不用改

TCP_wrappers=YES //限制主机对VSFTP服务器的访问,不用改(经过/etc/hosts.deny和/etc/hosts.allow这两个文件来配置)

 

    按照上面修改完以后,按键盘"Esc"退出编辑,再按":",并在后面输入"wq",进行保存并退出。

 

2.4 配置iptables防火墙

  按照以上步骤还不能运行,用下面命令能够查看一下防火墙容许的端口号,咱们知道ftp的端口号是"20、21",从结果中能够看出,并无。

 

service ipstables status

 

 

   这时须要对"/etc/sysconfig/iptables"进行配置:

 

vim /etc/sysconfig/iptables

 

 

  上图中先列出以"iptables"模糊比配的文件,而后在用上面的命名对"iptables"文件进行添加下面的内容。

 

-A INPUT -m state --state NEW -m tcp -p tcp --dport 21 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 20 -j ACCEPT

 

  具体的添加操做命令和前面对"/etc/vsftpd/vsftpd.conf"的操做同样。

 

 

2.5 设置selinux问题

  SELinux(Security-Enhanced Linux) 是美国国家安全局(NSA)对于强制访问控制的实现,是 Linux史上最杰出的新安全子系统。SELinux 是 2.6 版本的 Linux 内核中提供的强制访问控制 (MAC)系统。对于目前可用的 Linux 安全模块来讲,SELinux 是功能最全面,并且测试最充分的,它是在 20 年的 MAC 研究基础上创建的。SELinux 在类型强制服务器中合并了多级安全性或一种可选的多类策略,并采用了基于角色的访问控制概念SELinux提供了比传统的UNIX权限更好的访问控制。

  正式如此,因此此时还不能访问FTP服务器。用下面命令查询:

 

getsebool -a | grep ftp

 

 

  能够经过下面命令把上图中红色圈住的两个的值设置为"on"。

 

setsebool -P ftp_home_dir 1

setsebool -P allow_ftpd_full_access 1

 

 

2.6 重启相关服务

  最后就是把"vsftpd"和"iptables"两个服务从新启动一下。

 

service vsftpd restart

 

 

  若是出现下图,说明刚才没有把vsftpd服务启动起来。

 

service vsftpd start

 

 

  最后把防火墙从新启动一下。

service iptables restart

 

 

  到此为止FTP服务器就搭建完毕了,下面能够经过"FlashFXP.exe"软件进行访问了。

 

三、FlashFXP使用

 

3.1 FlashFXP简介

 

  FlashFXP是一款功能强大的FXP/FTP软件,集成了其它优秀的FTP软件的优势,如CuteFTP的目录比较,支持彩色文字显示;如BpFTP支持多目录选择文件,暂存目录;又如LeapFTP的界面设计。支持目录(和子目录)的文件传输,删除;支持上传,下载,以及第三方文件续传;能够跳过指定的文件类型,只传送须要的本件;可自定义不一样文件类型的显示颜色;暂存远程目录列表,支持FTP代理及Socks 3&4;有避免闲置断线功能,防止被FTP平台踢出;可显示或隐藏具备"隐藏"属性的文档和目录;支持每一个平台使用被动模式等。

 

 

  上图为FlashFXP开启界面,左面是显示的"本地文件系统",后面是显示"服务器文件系统",点击右侧上面的闪电图标,按照下图选择"Quick Connect"。

 

  点击以后出现下图,并按照下图进行填写。例如:

 

 

 

3.2 示例上传

 

 

   连接成功后,会显示上面的内容,能够尝试把左边的一个文件拖到右边,就能上传了,咱们如今试一下。

 

 

  最后登陆一下看看是否在linux下面有这个文件。

 

 

   从上图中发现了咱们刚才上传的文件"SqlHelper1.cs"文件,好了,到此为止,咱们的Linux下的FTP服务器基本完成了, 可是离真正的FTP服务器还差的很远,由于咱们只是用于"远程上传"点文件,因此基本能知足咱们的须要。

 

四、用到的Linux命令

4.1 chkconfig命令详解

  chkconfig命令主要用来更新启动中止)和查询系统服务的运行级信息。谨记chkconfig不是当即自动禁止或激活一个服务,它只是简单的改变了符号链接。

 

  使用语法:

 

chkconfig [--add][--del][--list][系统服务] 或 chkconfig [--level <等级代号>][系统服务][on/off/reset]

 

  chkconfig在没有参数运行时,显示用法。若是加上服务名,那么就检查这个服务是否在当前运行级启动。若是是,返回true,不然返回false。若是在服务名后面指定了on,off或者reset,那么chkconfig会改变指定服务的启动信息。on和off分别指服务被启动和中止,reset指重置服务的启动信息,不管有问题的初始化脚本指定了什么。on和off开关,系统默认只对运行级3,4,5有效,可是reset能够对全部运行级有效。

 

  参数用法:

 

--add 增长所指定的系统服务,让chkconfig指令得以管理它,并同时在系统启动的叙述文件内增长相关数据。

--del 删除所指定的系统服务,再也不由chkconfig指令管理,并同时在系统启动的叙述文件内删除相关数据。

--level<等级代号> 指定读系统服务要在哪个执行等级中开启或关毕。

 

等级0表示:表示关机

等级1表示:单用户模式

等级2表示:无网络链接的多用户命令行模式

等级3表示:有网络链接的多用户命令行模式

等级4表示:不可用

等级5表示:带图形界面的多用户模式

等级6表示:从新启动

 

  须要说明的是,level选项能够指定要查看的运行级而不必定是当前运行级。对于每一个运行级,只能有一个启动脚本或者中止脚本。当切换运行级时,init不会从新启动已经启动的服务,也不会再次去中止已经中止的服务。

 

chkconfig --list [name]:显示全部运行级系统服务的运行状态信息(on或off)。若是指定了name,那么只显示指定的服务在不一样运行级的状态。

chkconfig --add name:增长一项新的服务。chkconfig确保每一个运行级有一项启动(S)或者杀死(K)入口。若有缺乏,则会从缺省的init脚本自动创建。

chkconfig --del name:删除服务,并把相关符号链接从/etc/rc[0-6].d删除。

chkconfig [--level levels] name:设置某一服务在指定的运行级是被启动,中止仍是重置。

 

  运行级文件:

 

  每一个被chkconfig管理的服务须要在对应的init.d下的脚本加上两行或者更多行的注释。第一行告诉chkconfig缺省启动的运行级以及启动和中止的优先级。若是某服务缺省不在任何运行级启动,那么使用 - 代替运行级。第二行对服务进行描述,能够用\ 跨行注释。

 

  例如,random.init包含三行:

# chkconfig: 2345 20 80

# description: Saves and restores system entropy pool for \

# higher quality random number generation.

 

  使用范例:

 

chkconfig --list #列出全部的系统服务

chkconfig --add httpd #增长httpd服务

chkconfig --del httpd #删除httpd服务

chkconfig --level httpd 2345 on #设置httpd在运行级别为二、三、四、5的状况下都是on(开启)的状态

chkconfig --list #列出系统全部的服务启动状况

chkconfig --list mysqld #列出mysqld服务设置状况

chkconfig --level 35 mysqld on #设定mysqld在等级3和5为开机运行服务,--level 35表示操做只在等级3和5执行,on表示启动,off表示关闭

chkconfig mysqld on #设定mysqld在各等级为on,"各等级"包括二、三、四、5等级

 

  如何增长一个服务:

 

1.服务脚本必须存放在/etc/ini.d/目录下;

2.chkconfig --add servicename

在chkconfig工具服务列表中增长此服务,此时服务会被在/etc/rc.d/rcN.d中赋予K/S入口了;

3.chkconfig --level 35 mysqld on

修改服务的默认启动等级。

 

4.2 yum命令详解

  yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器。基於RPM包管理,可以从指定的服务器自动下载RPM包而且安装,能够自动处理依赖性关系,而且一次安装全部依赖的软体包,无须繁琐地一次次下载、安装。yum提供了查找、安装、删除某一个、一组甚至所有软件包的命令,并且命令简洁而又好记。

 

  yum的命令形式通常是以下:yum [options] [command] [package ...]

 

  其中的[options]是可选的,选项包括-h(帮助),-y(当安装过程提示选择所有为"yes"),-q(不显示安装的过程)等等。[command]为所要进行的操做,[package ...]是操做的对象。

 

  归纳了部分经常使用的命令包括:

 

  自动搜索最快镜像插件: yum install yum-fastestmirror

  安装yum图形窗口插件: yum install yumex

  查看可能批量安装的列表: yum grouplist

 

  1 安装

 

yum install 所有安装

yum install package1 安装指定的安装包package1

yum groupinsall group1 安装程序组group1

 

  2 更新和升级

 

yum update 所有更新

yum update package1 更新指定程序包package1

yum check-update 检查可更新的程序

yum upgrade package1 升级指定程序包package1

yum groupupdate group1 升级程序组group1

 

  3 查找和显示

 

yum info package1 显示安装包信息package1

yum list 显示全部已经安装和能够安装的程序包

yum list package1 显示指定程序包安装状况package1

yum groupinfo group1 显示程序组group1信息yum search string 根据关键字string查找安装包

 

  4 删除程序

 

yum remove package1 删除程序包package1

yum groupremove group1 删除程序组group1

yum deplist package1 查看程序package1依赖状况

 

  5 清除缓存

 

yum clean packages 清除缓存目录下的软件包

yum clean headers 清除缓存目录下的 headers

yum clean oldheaders 清除缓存目录下旧的 headers

yum clean, yum clean all (= yum clean packages; yum clean oldheaders) 清除缓存目录下的软件包及旧的headers

 

  好比,要安装游戏程序组,首先进行查找:

  #:yum grouplist

  能够发现,可安装的游戏程序包名字是"Games and Entertainment",这样就能够进行安装:

  #:yum groupinstall "Games and Entertainment"

  所 有的游戏程序包就自动安装了。在这里Games and Entertainment的名字必须用双引号选定,由于linux下面遇到空格会认为文件名结束了,所以必须告诉系统安装的程序包的名字是"Games and Entertainment"而不是"Games"。

 

  此外,还能够修改配置文件/etc/yum.conf选择安装源。可见yum进行配置程序有多方便了吧。更多详细的选项和命令,固然只要在命令提示行下面:man yum

 

4.3 SELinux两个命令

  getsebool与setsebool工具

 

  说明:SELinux规范了许多boolean数值清单档案,提供开启或关闭功能存取项目,而这些值都存放在/selinux/booleans/目录内相关档案,这些档案里的值只有两种:1(启用)或 0(关闭)

 

  1)getsebool

 

  说明:列出全部selinux bool数值清单表与内容

  使用方式:getsebool [ -a ]

  例如如下范例:

 

#getsebool ftpd_disable_trans

ftpd_disable_trans –> off

#getsebool -a

NetworkManager_disable_trans –> off

allow_cvs_read_shadow –> off

allow_daemons_dump_core –> on

allow_daemons_use_tty –> off

allow_execheap –> off

allow_execmem –> on

allow_execmod –> off

………

 

2)setsebool

 

  说明:设定selinux bool数值清单表与内容

  使用方式:setsebool [ -P ] boolean value | bool1=val1 bool2=val2 bool3=val3……

  参数配置: -P表示设定该项目永久套用

  使用范例:

setsebool ftpd_disable_trans=on ( on 或者 1 )

setsebool -P ftpd_disable_trans=off ( off 或者 0 )

 

 

4.4 vim命令详解

  vi编辑器是全部Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。因为对Unix及Linux系统的任何版本,vi编辑器是彻底相同的,所以您能够在其余任何介绍vi的地方进一步了解它。Vi也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻。

 

  一、vi的基本概念

 

  基本上vi能够分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分以下:

  1) 命令行模式command mode)

  控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。

 

  2) 插入模式(Insert mode)

  只有在Insert mode下,才能够作文字输入,按「ESC」键可回到命令行模式。

 

  3) 底行模式(last line mode)

  将文件保存或退出vi,也能够设置编辑环境,如寻找字符串、列出行号……等。

  不过通常咱们在使用时把vi简化成两个模式,就是将底行模式(last line mode)也算入命令行模式command mode)。

 

二、vi的基本操做

 

  a) 进入vi

  在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面:

 

$ vi myfile

 

  不过有一点要特别注意,就是您进入vi以后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才可以输入文字。初次使用vi的人都会想先用上下左右键移动光标,结果电脑一直哔哔叫,把本身气个半死,因此进入vi后,先不要乱动,转换到「插入模式(Insert mode)」再说吧!

 

  b) 切换至插入模式(Insert mode)编辑文件

  在「命令行模式(command mode)」下按一下字母「i」就能够进入「插入模式(Insert mode)」,这时候你就能够开始输入文字了。

 

  c) Insert 的切换

  您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,若是您发现输错了字!想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode)」再删除文字。

 

  d) 退出vi及保存文件

  在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例如:

 

: w filename (输入 「w filename」将文章以指定的文件名filename保存)

: wq (输入「wq」,存盘并退出vi)

: q! (输入q!, 不存盘强制退出vi)

 

三、命令行模式(command mode)功能键

 

  1)插入模式

  按「i」切换进入插入模式「insert mode」,按"i"进入插入模式后是从光标当前位置开始输入文件;

  按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;

  按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。

 

  2)从插入模式切换为命令行模式

  按「ESC」键。

 

  3)移动光标

  vi能够直接用键盘上的光标来上下左右移动,但正规的vi是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。

 

  按「ctrl」+「b」:屏幕往"后"移动一页。

  按「ctrl」+「f」:屏幕往"前"移动一页。

  按「ctrl」+「u」:屏幕往"后"移动半页。

  按「ctrl」+「d」:屏幕往"前"移动半页。

  按数字「0」:移到文章的开头。

  按「G」:移动到文章的最后。

  按「$」:移动到光标所在行的"行尾"。

  按「^」:移动到光标所在行的"行首"

  按「w」:光标跳到下个字的开头

  按「e」:光标跳到下个字的字尾

  按「b」:光标回到上个字的开头

  按「#l」:光标移到该行的第#个位置,如:5l,56l。

 

  4)删除文字

  「x」:每按一次,删除光标所在位置的"后面"一个字符。

  「#x」:例如,「6x」表示删除光标所在位置的"后面"6个字符。

  「X」:大写的X,每按一次,删除光标所在位置的"前面"一个字符。

  「#X」:例如,「20X」表示删除光标所在位置的"前面"20个字符。

  「dd」:删除光标所在行。

  「#dd」:从光标所在行开始删除#行

 

  5)复制

  「yw」:将光标所在之处到字尾的字符复制到缓冲区中。

  「#yw」:复制#个字到缓冲区

  「yy」:复制光标所在行到缓冲区。

  「#yy」:例如,「6yy」表示拷贝从光标所在的该行"往下数"6行文字。

  「p」:将缓冲区内的字符贴到光标所在位置。注意:全部与"y"有关的复制命令都必须与"p"配合才能完成复制与粘贴功能。

 

  6)替换

  「r」:替换光标所在处的字符。

  「R」:替换光标所到之处的字符,直到按下「ESC」键为止。

 

  7)回复上一次操做

  「u」:若是您误执行一个命令,能够立刻按下「u」,回到上一个操做。按屡次"u"能够执行屡次回复。

 

  8)更改

  「cw」:更改光标所在处的字到字尾处

  「c#w」:例如,「c3w」表示更改3个字

 

  9)跳至指定的行

  「ctrl」+「g」列出光标所在行的行号。

  「#G」:例如,「15G」,表示移动光标至文章的第15行行首。

 

  四、Last line mode下命令简介

 

  在使用「last line mode」以前,请记住先按「ESC」键肯定您已经处于「command mode」下后,再按「:」冒号便可进入「last line mode」。

 

  A) 列出行号

  「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。

  B) 跳到文件中的某一行

  「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。

  C) 查找字符

  「/关键字」:先按「/」键,再输入您想寻找的字符,若是第一次找的关键字不是您想要的,能够一直按「n」会日后寻找到您要的关键字为止。

  「?关键字」:先按「?」键,再输入您想寻找的字符,若是第一次找的关键字不是您想要的,能够一直按「n」会往前寻找到您要的关键字为止。

  D) 保存文件

  「w」:在冒号输入字母「w」就能够将文件保存起来。

  E) 离开vi

  「q」:按「q」就是退出,若是没法离开vi,能够在「q」后跟一个「!」强制离开vi。

  「qw」:通常建议离开时,搭配「w」一块儿使用,这样在退出的时候还能够保存文件。

 

  五、vi命令列表

 

  一、下表列出命令模式下的一些键的功能:

 

h         左移光标一个字符

l         右移光标一个字符

k         光标上移一行

j         光标下移一行

^         光标移动至行首

0         数字"0",光标移至文章的开头

G         光标移至文章的最后

$         光标移动至行尾

Ctrl+f     向前翻屏

Ctrl+b     向后翻屏

Ctrl+d     向前翻半屏

Ctrl+u     向后翻半屏

i         在光标位置前插入字符

a         在光标所在位置的后一个字符开始增长

o         插入新的一行,从行首开始输入

ESC     从输入状态退至命令状态

x         删除光标后面的字符

#x         删除光标后的#个字符

X         (大写X),删除光标前面的字符

#X         删除光标前面的#个字符

dd         删除光标所在的行

#dd     删除从光标所在行数的#行

yw         复制光标所在位置的一个字

#yw     复制光标所在位置的#个字

yy         复制光标所在位置的一行

#yy     复制从光标所在行数的#行

p         粘贴

u         取消操做

cw         更改光标所在位置的一个字

#cw     更改光标所在位置的#个字

 

  二、下表列出行命令模式下的一些指令

 

w filename     储存正在编辑的文件为filename

wq filename     储存正在编辑的文件为filename,并退出vi

q!             放弃全部修改,退出vi

set nu         显示行号

/或?         查找,在/后输入要查找的内容

n             与/或?一块儿使用,若是查找的内容不是想要找的关键字,按n或向后(与/联用)或向前(与?联用)继续查找,直到找到为止。

 

  对于第一次用vi,有几点注意要提醒一下:

 

  一、用vi打开文件后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才可以输入文字。切换方法:在「命令行模式(command mode)」下按一下字母「i」就能够进入「插入模式(Insert mode)」,这时候你就能够开始输入文字了。

  二、编辑好后,需从插入模式切换为命令行模式才能对文件进行保存,切换方法:按「ESC」键。

  三、保存并退出文件:在命令模式下输入:wq便可!(别忘了wq前面的:)

 

4.5 touch命令详解

  linux中新建文件命令touch用法详解:

 

  linux中的touch命令通常用来修改文件的时间,或者新建一个不存在的文件。

 

  语法以下:

 

touch [-acm][-r ref_file(参照文件)|-t time(时间值)] file(文件名)

 

  例子:

 

touch file1.txt 更新file1.txt的存取和修改时间

touch -c file1.txt 若是file1.txt不存在,不建立文件

touch -r ref_file file1.txt 更新file1.txt的时间戳和ref+file相同

touch -t 0911252234.40 file1.txt 设定文件的时间为09年11月25日22点34分40秒

 

  个参数说明以下:

 

-a          修改文件 file 的存取时间.

-c          不建立文件 file.

-m          修改文件 file 的修改时间

-r ref_file 将参照文件 ref_file 相应的时间戳记的数值做为指定文件 file 时间戳记的新值.

-t time      使用指定的时间值 time 做为指定文件 file 相应时间戳记的新值.此处的 time 规定为以下形式的十进制数∶ [[CC]YY]MMDDhhmm[.SS]

  这里,CC为年数中的前两位,即"世纪数";YY为年数的后两位,即某世纪中的年数.若是不给出CC的值,则touch 将把年数CCYY限定在1969--2068以内.MM为月数,DD为天将把年数CCYY限定在1969--2068以内.MM为月数,DD为天数,hh 为小时数(几点),mm为分钟数,SS为秒数.此处秒的设定范围是0--61,这样能够处理闰秒.这些数字组成的时间是环境变量TZ指定的时区中的一个时 间.因为系统的限制,早于1970年1月1日的时间是错误的。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.3.rar

Hadoop集群(第4期)_SecureCRT使用

 

一、SecureCRT简介

 

  SecureCRT是一款支持SSH(SSH1和SSH2)的终端仿真程序,同时支持Telnet和rlogin协议。SecureCRT是一款用于链接运行包括Windows、UNIX和VMS的远程系统的理想工具。经过使用内含的VCP命令行程序能够进行加密文件的传输。有流行CRTTelnet客户机的全部特色,包括:自动注册、对不一样主机保持不一样的特性、打印功能、颜色设置、可变屏幕尺寸、用户定义的键位图和优良的VT100,VT102,VT220和ANSI竞争。能从命令行中运行或从浏览器中运行。其它特色包括文本手稿、易于使用的工具条、用户的键位图编辑器、可定制的ANSI颜色等.SecureCRT的SSH协议支持DES,3DES和RC4密码和密码与RSA鉴别。

 

二、SecureCRT安装

 

2.1 下载软件

      为了使实验室后续人员还能按照该文档设置,故把本次用的软件上传到CSDN上,即便你实验室找不到该软件的状况下还能够从下面地址中下载。

    地址http://download.csdn.net/detail/xia520pi/4088823

 

2.2 安装软件

  由于这包软件是绿色安装,因此只须要把压缩包解压到你想要的地方便可。例如:

 

 

  上图中是本人的解压以后的地方,我放在了E盘下,打开文件夹,找到SecureCRT.exe

 

 

  接着击"SecureCRT.exe",创建桌面快捷方式。

 

 

  当首次运行该软件时会弹出一个选项框,别管它,关掉便可,这是会出现以下界面。

 

 

  上图就是这个软件的启动界面,下面咱们就将如何实现该软件实现远程登陆咱们的Linux系统。

 

三、用密码登陆Linux

  这小节咱们将采用"密码"的方式登陆Linux,首先咱们作的第一件事儿就是创建"远程会话"。有两种途径创建。

  第一种:"文件"à"链接"

  第二种:用菜单栏的快捷方式

 

 

  按照两种方式均可以,而后弹出下面选项框,照着图那样点击所示按钮。

 

 

  而后弹出以下界面。

 

 

  选择"SSH2",接着点击"下一步"。

 

 

  按照上图所示,填写要远程链接的"主机名"和"用户名",好比我要链接"主机名:192.168.1.10"且"用户名:hadoop"的机器,就如上所写。

 

 

  上面这个"会话名称"能够修改,也能够保持不变,点击"完成",就设置成功了。

 

 

  若是刚才改"会话名称",上图的就不是一个IP地址了,而是你本身设置的名字。还有记得勾上"在标签页中打开",若是你想在一个界面中打开多个终端,就有这个必要。这时选择你想远程链接,选择一个"会话名称",好比"192.168.1.10",点击"链接"。

 

 

  出现上面画面,默认"接受并保存",直接按回车,就能够了。

 

 

  而后就会让你输入密码,写上密码,在"保存密码"前打上对勾,接着"确认"。若是网络畅通,就能够进行远程访问了。

 

 

  出现上面的"绿色"对勾,就表示你已经链接上了, 咱们如今试一个命令吧。

 

 

  咱们发现了两个不如意的地方,第一个:出现了红色标记的乱码;第二个:黑白显示不是很舒服。固然这个咱们是能够进行调节的。那咱们还等什么呢?那就赶忙行动吧,使咱们的界面变得更加人性化。

 

 

  按照上图中,右击"192.168.1.10"标签,会弹出一个菜单。点击"会话选项"。

 

 

  按照上图中三步进行设置,点击"仿真",在终端选择"Linux",接着,把"使用颜色方案"和"ANSI颜色"打上对勾

  而后还有一个问题没有解决,就是"中文乱码"问题,好,咱们选择"外观",能够更改"当前颜色方案",默认的是"Monochrone",我比较喜欢"花白/暗青",接着设置字体,若是你感受默认字体比较舒服,就按原来不动,若是感受本身比较小,能够把字体设置大,我比较喜欢"楷体 14号",这样看显示结果比较舒服一点,你如今该问了,咱们不是解决"中文乱码"问题吗?怎么如今竟弄了一下可有可无的事儿,哈哈,下面就该设置编码了,细心的你会发现有一个"字符编码"的选项,默认是"Default",如今咱们选择"UTF-8"。这样设置完,从新链接,就换成咱们想要的界面了。下面是咱们刚才设置以后的界面截图。

 

 

  下图是咱们从新链接以后的界面,发现界面颜色变了,并且也没有乱码了。

 

 

  好了,到目前为止,咱们用密码链接Linux已经结束了,如今就能够远程对Linux进行操做了。下一节咱们将进行SSH密钥链接Linux,这样每次链接就不须要进行输入用户名和密码就能够直接进行链接,并且安全性是最高的。

 

四、用SSH登陆Linux

 

4.1 SSH基础知识

  我想确定有很多朋友在使用 SecureCRT 作为 SSH 的客户端软件,但都不多使用他的 RSA/DSA 加密功能吧,怎么你还不知道 RSA 是什么?

  SSH,特别是 OpenSSH,是一个相似于 telnet 或 rsh,ssh 客户程序也能够用于登陆到远程机器。咱们中有许多人把优秀的 OpenSSH用做古老的 telnet 和 rsh 命令的替代品,OpenSSH 不只是安全的并且是加密的。OpenSSH 更加吸引人的特性之一是它可以使用基于一对互补数字式密钥RSADSA 认证协议来认证用户。RSA 和 DSA 认证承诺没必要提供密码就可以同远程系统创建链接,这是它的主要魅力之一。虽然这很是吸引人,可是 OpenSSH 的新用户们经常以一种快速却不完善的方式配置 RSA/DSA,结果虽然实现了无密码登陆,却也在此过程当中开了一个很大的安全漏洞。

  什么是 RSA/DSA 认证?

  SSH,特别是 OpenSSH(彻底免费的 SSH 的实现),是一个难以想象的工具。相似于 telnet 或 rsh,ssh 客户程序也能够用于登陆到远程机器。所要求的只是该远程机器正在运行 sshd,即 ssh 服务器进程。可是,与 telnet 不一样的是,ssh 协议很是安全。加密数据流,确保数据流的完整性,甚至安全可靠的进行认证它都使用了专门的算法。

  然而,虽然 ssh 的确很棒,但仍是有一个 ssh 功能组件经常被忽略、被危险的误用或者简直就是被误解。这个组件就是 OpenSSH 的 RSA/DSA 密钥认证系统,它能够代替 OpenSSH 缺省使用的标准安全密码认证系统。

  OpenSSH 的 RSA 和 DSA 认证协议的基础是一对专门生成的密钥,分别叫作专用密钥公用密钥。使用这些基于密钥的认证系统的优点在于:在许多状况下,有可能没必要手工输入密码就能创建起安全的链接。

  两项注意事项

  关于 RSA 和 DSA 认证有两项重要的注意事项。第一项是咱们的确只须要生成一对密钥。而后咱们能够把咱们的公用密钥拷贝到想要访问的那些远程机器上,它们都会根据咱们的那把专用密钥进行恰当的认证。换句话说,咱们并不须要为想要访问的 每一个系统都准备一对密钥。只要一对就足够了。

  另外一项注意事项是专用密钥不该落入其它人手中。正是专用密钥受权咱们访问远程系统,任何拥有咱们的专用密钥的人都会被授予和咱们彻底相同的特权。如同咱们不想让陌生人有咱们的住处的钥匙同样,咱们应该保护咱们的专用密钥以防未受权的使用。在比特和字节的世界里,这意味着没有人是原本就应该能读取或是拷贝咱们的专用密钥的。

 

4.2 建立公钥

  了解了SSH的基本知识后,咱们开始进行本小节的SSH登陆Linux,首先在SecureCRT软件的菜单栏中:工具à建立公钥

 

 

  点击"建立公钥"以后出现下图,并借着点击"下一步"便可。

 

 

  选择非对称加密方式RSA,而后点击"下一步"。

 

 

  通行短语是可选的,若是设置了,在链接上服务器的时候须要输入。例如:我这里设置了通行短语"myhadoop",而且下面的注释写为"虾皮工做室@Linux"。

 

 

  下一步,密钥长度,默认便可,2048也行,越长越安全。咱们在这里就保持默认便可,若是选择的越大,生成密钥生成的时间也就越长。

 

 

  下一步,生成密钥,请耐心等待。

 

 

  完成后下一步,这里保存了私钥地址和文件名。建议将这个名字改一改,由于生成多个用户的密钥的时候方便识别,并且放在U盘里随身携带的时候也好认识,例如把原来的"Identity"改写成"PubKey_TMaster_Hadoop"。

 

 

  到此为止,使用客户端 SecureCRT 生成密钥已经完成。接下来,就是要将密钥文件上传至服务器端,并在服务器端导入密钥。

 

4.3 SSH服务器设置

  第一步:在须要配置的用户根目录下建立.ssh目录并设置必定的权限。本次在通常用户(hadoop)下面进行。

 

 

  如上图所示经过下面命令创建了.ssh目录,而且修改了其权限。

 

# mkdir /root/.ssh

# chmod 700 /root/.ssh

 

  第二步:采用Hadoop集群创建VSFTP服务器,经过FTP把咱们的公钥上传上去,固然你能够经过U盘把公钥拷贝到服务器上。这次咱们采用FTP的方式。

 

 

   而后经过SecureCRT查看文件是否已经上传。

 

 

  从上图中咱们知道已经上传了。

  第三步:用上传的公钥生成authorized_keys文件并设置文件的权限,将SSH2兼容格式的公钥转换成为Openssh兼容格式。

 

 

  上图中遇到的命令以下所示:

 

# ssh-keygen -i -f /home/hadoop/.ssh/PubKey_TMaster_Hadoop.pub >>/home/hadoop/.ssh /authorized_keys

# chmod 600 /home/hadoop/.ssh/authorized_keys

    

  上面命令红色标注的部分是根据实际状况变化的,好比这是从网上找的一个例子,他是这样设置的。

 

# ssh-keygen -i -f Identity.pub >> /root/.ssh/authorized_keys

# chmod 600 /root/.ssh/authorized_keys

 

  上面蓝色标注的部分是两个命令的共同点。

  第四步:设置ssh配置文件,为了安全建议只使用密钥登陆,去掉默认的密码登陆。

  通常用户没法修改"/etc/ssh/sshd_config"文件,因此必须切换到root最高权限用户下进行修改。使用下面命令。

 

Protocol 2              # 使用SSH2协议

RSAAuthentication yes # 启用 RSA 认证

PubkeyAuthentication yes # 启用公钥私钥配对认证方式

AuthorizedKeysFile .ssh/authorized_keys # 公钥文件路径(和上面生成的文件同)

PasswordAuthentication no # 禁止密码验证登录(根据须要,不过通常启用了密钥,就不用密码了)

 

  第五步:重启Linux服务器的ssh服务

 

# service sshd restart

 

4.4 SSH链接服务器

  在"用密码登录Linux"小节中,咱们讲到过用两种方式打开"链接"界面,而后选择"快速链接"。

 

 

  点击完"快速链接"会弹出下面界面:

 

 

  按照上面的步骤进行,步骤1是默认就选择SSH2协议的,步骤2步骤3是根据实际状况填写的。好比我上面要链接远程Linux的IP为"192.168.1.10"且通常帐户为"hadoop"的机器。步骤4只须要勾上"公钥"和"键盘交互",而后中"公钥",点击其"属性"按钮,及图中标注的步骤5

 

 

  经过浏览选择咱们刚才生成的证书,点击肯定,回到"快速链接"界面点击"链接"按钮,而后弹出一个窗口,然填写咱们的"通行短语"。把咱们刚才设置的通行短语"myhadoop"输入进去,就能够了。点击肯定,就能够实现SSH无密码链接了。

 

  

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.4.rar


Hadoop集群(第5期)_Hadoop安装配置

 

一、集群部署介绍

 

1.1 Hadoop简介

 

  Hadoop是Apache软件基金会旗下的一个开源分布式计算平台。以Hadoop分布式文件系统(HDFS,Hadoop Distributed Filesystem)和MapReduce(Google MapReduce的开源实现)为核心的Hadoop为用户提供了系统底层细节透明的分布式基础架构。

  对于Hadoop的集群来说,能够分红两大类角色:Master和Salve。一个HDFS集群是由一个NameNode和若干个DataNode组成的。其中NameNode做为主服务器,管理文件系统的命名空间和客户端对文件系统的访问操做;集群中的DataNode管理存储的数据。MapReduce框架是由一个单独运行在主节点上的JobTracker和运行在每一个集群从节点的TaskTracker共同组成的。主节点负责调度构成一个做业的全部任务,这些任务分布在不一样的从节点上。主节点监控它们的执行状况,而且从新执行以前的失败任务;从节点仅负责由主节点指派的任务。当一个Job被提交时,JobTracker接收到提交做业和配置信息以后,就会将配置信息等分发给从节点,同时调度任务并监控TaskTracker的执行。

  从上面的介绍能够看出,HDFS和MapReduce共同组成了Hadoop分布式系统体系结构的核心。HDFS在集群上实现分布式文件系统MapReduce在集群上实现了分布式计算任务处理。HDFS在MapReduce任务处理过程当中提供了文件操做和存储等支持,MapReduce在HDFS的基础上实现了任务的分发、跟踪、执行等工做,并收集结果,两者相互做用,完成了Hadoop分布式集群的主要任务。

 

1.2 环境说明

  集群中包括4个节点:1个Master,3个Salve,节点之间局域网链接,能够相互ping通,具体集群信息能够查看"Hadoop集群(第2期)"。节点IP地址分布以下:

 

机器名称

IP地址

Master.Hadoop

192.168.1.2

Salve1.Hadoop 

192.168.1.3 

Salve2.Hadoop 

192.168.1.4 

Salve3.Hadoop 

192.168.1.5 

 

  四个节点上均是CentOS6.0系统,而且有一个相同的用户hadoop。Master机器主要配置NameNode和JobTracker的角色,负责总管分布式数据和分解任务的执行;3个Salve机器配置DataNode和TaskTracker的角色,负责分布式数据存储以及任务的执行。其实应该还应该有1个Master机器,用来做为备用,以防止Master服务器宕机,还有一个备用立刻启用。后续经验积累必定阶段后补上一台备用Master机器。

 

1.3 网络配置

  Hadoop集群要按照1.2小节表格所示进行配置,咱们在"Hadoop集群(第1期)"的CentOS6.0安装过程就按照提早规划好的主机名进行安装和配置。若是实验室后来人在安装系统时,没有配置好,没关系,没有必要从新安装,在安装完系统以后仍然能够根据后来的规划对机器的主机名进行修改。

  下面的例子咱们将以Master机器为例,即主机名为"Master.Hadoop",IP为"192.168.1.2"进行一些主机名配置的相关操做。其余的Slave机器以此为依据进行修改。

 

  1)查看当前机器名称

  用下面命令进行显示机器名称,若是跟规划的不一致,要按照下面进行修改。

 

hostname

 

   

  上图中,用"hostname"查"Master"机器的名字为"Master.Hadoop",与咱们预先规划的一致。

 

  2)修改当前机器名称

  假定咱们发现咱们的机器的主机名不是咱们想要的,经过对"/etc/sysconfig/network"文件修改其中"HOSTNAME"后面的值,改为咱们规划的名称。

  这个"/etc/sysconfig/network"文件是定义hostname和是否利用网络的不接触网络设备的对系统全体定义的文件。

  设定形式:设定值=值

  "/etc/sysconfig/network"的设定项目以下:

 

NETWORKING 是否利用网络

GATEWAY 默认网关

IPGATEWAYDEV 默认网关的接口名

HOSTNAME 主机名

DOMAIN 域名

 

  用下面命令进行修改当前机器的主机名(备注:修改系统文件通常用root用户)

 

vim /etc/sysconfig/network

 

 

  经过上面的命令咱们从"/etc/sysconfig/network"中找到"HOSTNAME"进行修改,查看内容以下:

 

 

    3)修改当前机器IP

    假定咱们的机器连IP在当时安装机器时都没有配置好,那此时咱们须要对"ifcfg-eth0"文件进行配置,该文件位于"/etc/sysconfig/network-scripts"文件夹下。

  在这个目录下面,存放的是网络接口(网卡)的制御脚本文件(控制文件),ifcfg- eth0是默认的第一个网络接口,若是机器中有多个网络接口,那么名字就将依此类推ifcfg-eth1,ifcfg-eth2,ifcfg- eth3,……。

  这里面的文件是至关重要的,涉及到网络可否正常工做。

  设定形式:设定值=值

  设定项目项目以下:

 

DEVICE 接口名(设备,网卡)

BOOTPROTO IP的配置方法(static:固定IP, dhcpHCP, none:手动)

HWADDR MAC地址

ONBOOT 系统启动的时候网络接口是否有效(yes/no)

TYPE 网络类型(一般是Ethemet)

NETMASK 网络掩码

IPADDR IP地址

IPV6INIT IPV6是否有效(yes/no)

GATEWAY 默认网关IP地址

 

  查看"/etc/sysconfig/network-scripts/ifcfg-eth0"内容,若是IP不复核,就行修改。

 

 

  若是上图中IP与规划不相符,用下面命令进行修改:

 

vim /etc/sysconfig/network-scripts/ifcgf-eth0

 

  修改完以后能够用"ifconfig"进行查看。

 

   

  4)配置hosts文件(必须

  "/etc/hosts"这个文件是用来配置主机将用的DNS服务器信息,是记载LAN内接续的各主机的对应[HostName和IP]用的。当用户在进行网络链接时,首先查找该文件,寻找对应主机名(或域名)对应的IP地址。

  咱们要测试两台机器之间知否连通,通常用"ping 机器的IP",若是想用"ping 机器的主机名"发现找不见该名称的机器,解决的办法就是修改"/etc/hosts"这个文件,经过把LAN内的各主机的IP地址和HostName的一一对应写入这个文件的时候,就能够解决问题。

  例如:机器为"Master.Hadoop:192.168.1.2"对机器为"Salve1.Hadoop:192.168.1.3"用命令"ping"记性链接测试。测试结果以下:

 

   

   从上图中的值,直接对IP地址进行测试,可以ping通,可是对主机名进行测试,发现没有ping通,提示"unknown host——未知主机",这时查看"Master.Hadoop"的"/etc/hosts"文件内容。

 

   

  发现里面没有"192.168.1.3 Slave1.Hadoop"内容,故而本机器是没法对机器的主机名为"Slave1.Hadoop" 解析。

  在进行Hadoop集群配置中,须要在"/etc/hosts"文件中添加集群中全部机器的IP与主机名,这样Master与全部的Slave机器之间不只能够经过IP进行通讯,并且还能够经过主机名进行通讯。因此在全部的机器上的"/etc/hosts"文件末尾中都要添加以下内容:

 

192.168.1.2 Master.Hadoop

192.168.1.3 Slave1.Hadoop

192.168.1.4 Slave2.Hadoop

192.168.1.5 Slave3.Hadoop

 

  用如下命令进行添加:

 

vim /etc/hosts

 

 

  添加结果以下:

 

 

  如今咱们在进行对机器为"Slave1.Hadoop"的主机名进行ping通测试,看是否能测试成功。

 

 

  从上图中咱们已经能用主机名进行ping通了,说明咱们刚才添加的内容,在局域网内能进行DNS解析了,那么如今剩下的事儿就是在其他的Slave机器上进行相同的配置。而后进行测试。(备注:当设置SSH无密码验证后,能够"scp"进行复制,而后把原来的"hosts"文件执行覆盖便可。)

 

1.4 所需软件

1)JDK软件

    下载地址:http://www.oracle.com/technetwork/java/javase/index.html

    JDK版本:jdk-6u31-linux-i586.bin

2)Hadoop软件

    下载地址:http://hadoop.apache.org/common/releases.html

    Hadoop版本:hadoop-1.0.0.tar.gz

 

1.5 VSFTP上传

  在"Hadoop集群(第3期)"讲了VSFTP的安装及配置,若是没有安装VSFTP能够按照该文档进行安装。若是安装好了,就能够经过FlashFXP.exe软件把咱们下载的JDK6.0和Hadoop1.0软件上传到"Master.Hadoop:192.168.1.2"服务器上。

 

 

  刚才咱们用通常用户(hadoop)经过FlashFXP软件把所需的两个软件上传了跟目下,咱们经过命令查看下一下是否已经上传了。

 

 

    从图中,咱们的所需软件已经准备好了。

 

二、SSH无密码验证配置

  Hadoop运行过程当中须要管理远端Hadoop守护进程,在Hadoop启动之后,NameNode是经过SSH(Secure Shell)来启动和中止各个DataNode上的各类守护进程的。这就必须在节点之间执行指令的时候是不须要输入密码的形式,故咱们须要配置SSH运用无密码公钥认证的形式,这样NameNode使用SSH无密码登陆并启动DataName进程,一样原理,DataNode上也能使用SSH无密码登陆到NameNode。

 

2.1 安装和启动SSH协议

  在"Hadoop集群(第1期)"安装CentOS6.0时,咱们选择了一些基本安装包,因此咱们须要两个服务:ssh和rsync已经安装了。能够经过下面命令查看结果显示以下:

 

rpm –qa | grep openssh

rpm –qa | grep rsync

 

 

  假设没有安装ssh和rsync,能够经过下面命令进行安装。

 

yum install ssh 安装SSH协议

yum install rsync (rsync是一个远程数据同步工具,可经过LAN/WAN快速同步多台主机间的文件)

service sshd restart 启动服务

 

  确保全部的服务器都安装,上面命令执行完毕,各台机器之间能够经过密码验证相互登。

 

2.2 配置Master无密码登陆全部Salve

  1)SSH无密码原理

  Master(NameNode | JobTracker)做为客户端,要实现无密码公钥认证,链接到服务器Salve(DataNode | Tasktracker)上时,须要在Master上生成一个密钥对,包括一个公钥和一个私钥,然后将公钥复制到全部的Slave上。当Master经过SSH链接Salve时,Salve就会生成一个随机数并用Master的公钥对随机数进行加密,并发送给Master。Master收到加密数以后再用私钥解密,并将解密数回传给Slave,Slave确认解密数无误以后就容许Master进行链接了。这就是一个公钥认证过程,其间不须要用户手工输入密码。重要过程是将客户端Master复制到Slave上。

  2)Master机器上生成密码对

   在Master节点上执行如下命令:

 

ssh-keygen –t rsa –P ''

 

  这条命是生成其无密码密钥对,询问其保存路径时直接回车采用默认路径。生成的密钥对:id_rsa和id_rsa.pub,默认存储在"/home/hadoop/.ssh"目录下。

 

 

  查看"/home/hadoop/"下是否有".ssh"文件夹,且".ssh"文件下是否有两个刚生产的无密码密钥对。

 

 

  接着在Master节点上作以下配置,把id_rsa.pub追加到受权的key里面去。

 

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

 

 

  在验证前,须要作两件事儿。第一件事儿是修改文件"authorized_keys"权限(权限的设置很是重要,由于不安全的设置安全设置,会让你不能使用RSA功能),另外一件事儿是用root用户设置"/etc/ssh/sshd_config"的内容。使其无密码登陆有效。

  1)修改文件"authorized_keys"

    

chmod 600 ~/.ssh/authorized_keys

 

   

   备注:若是不进行设置,在验证时,扔提示你输入密码,在这里花费了将近半天时间来查找缘由。在网上查到了几篇不错的文章,把做为"Hadoop集群_第5期副刊_JDK和SSH无密码配置"来帮助额外学习之用。

 

    2)设置SSH配置

  用root用户登陆服务器修改SSH配置文件"/etc/ssh/sshd_config"的下列内容。

 

 

RSAAuthentication yes # 启用 RSA 认证

PubkeyAuthentication yes # 启用公钥私钥配对认证方式

AuthorizedKeysFile .ssh/authorized_keys # 公钥文件路径(和上面生成的文件同)

 

  设置完以后记得重启SSH服务,才能使刚才设置有效。

 

service sshd restart

    

  退出root登陆,使用hadoop普通用户验证是否成功。

 

ssh localhost

 

   

  从上图中得知无密码登陆本级已经设置完毕,接下来的事儿是把公钥复制全部Slave机器上。使用下面的命令格式进行复制公钥:

 

scp ~/.ssh/id_rsa.pub 远程用户名@远程服务器IP:~/

 

  例如:

 

scp ~/.ssh/id_rsa.pub hadoop@192.168.1.3:~/

 

  上面的命令是复制文件"id_rsa.pub"到服务器IP为"192.168.1.3"的用户为"hadoop"的"/home/hadoop/"下面。

 

  下面就针对IP为"192.168.1.3"的Slave1.Hadoop的节点进行配置。

  1)把Master.Hadoop上的公钥复制到Slave1.Hadoop上

 

 

 

  从上图中咱们得知,已经把文件"id_rsa.pub"传过去了,由于并无创建起无密码链接,因此在链接时,仍然要提示输入输入Slave1.Hadoop服务器用户hadoop的密码。为了确保确实已经把文件传过去了,用SecureCRT登陆Slave1.Hadoop:192.168.1.3服务器,查看"/home/hadoop/"下是否存在这个文件。

 

 

  从上面得知咱们已经成功把公钥复制过去了。

  2)在"/home/hadoop/"下建立".ssh"文件夹

  这一步并非必须的,若是在Slave1.Hadoop的"/home/hadoop"已经存在就不须要建立了,由于咱们以前并无对Slave机器作过无密码登陆配置,因此该文件是不存在的。用下面命令进行建立。(备注:用hadoop登陆系统,若是不涉及系统文件修改,通常状况下都是用咱们以前创建的普通用户hadoop进行执行命令。)

 

mkdir ~/.ssh

 

  而后是修改文件夹".ssh"的用户权限,把他的权限修改成"700",用下面命令执行:

 

chmod 700 ~/.ssh

 

  备注:若是不进行,即便你按照前面的操做设置了"authorized_keys"权限,并配置了"/etc/ssh/sshd_config",还重启了sshd服务,在Master能用"ssh localhost"进行无密码登陆,可是对Slave1.Hadoop进行登陆仍然须要输入密码,就是由于".ssh"文件夹的权限设置不对。这个文件夹".ssh"在配置SSH无密码登陆时系统自动生成时,权限自动为"700",若是是本身手动建立,它的组权限和其余权限都有,这样就会致使RSA无密码远程登陆失败。

 

 

  对比上面两张图,发现文件夹".ssh"权限已经变了。

  3)追加到受权文件"authorized_keys"

  到目前为止Master.Hadoop的公钥也有了,文件夹".ssh"也有了,且权限也修改了。这一步就是把Master.Hadoop的公钥追加到Slave1.Hadoop的受权文件"authorized_keys"中去。使用下面命令进行追加并修改"authorized_keys"文件权限:

 

cat ~/id_rsa.pub >> ~/.ssh/authorized_keys

chmod 600 ~/.ssh/authorized_keys

 

  4)用root用户修改"/etc/ssh/sshd_config"

  具体步骤参考前面Master.Hadoop的"设置SSH配置",具体分为两步:第1是修改配置文件;第2是重启SSH服务。

  5)用Master.Hadoop使用SSH无密码登陆Slave1.Hadoop

  当前面的步骤设置完毕,就能够使用下面命令格式进行SSH无密码登陆了。

 

ssh 远程服务器IP

 

 

  从上图咱们主要3个地方,第1个就是SSH无密码登陆命令,第二、3个就是登陆先后"@"后面的机器名变了,由"Master"变为了"Slave1",这就说明咱们已经成功实现了SSH无密码登陆了。

  最后记得把"/home/hadoop/"目录下的"id_rsa.pub"文件删除掉。

 

rm –r ~/id_rsa.pub

 

 

  到此为止,咱们通过前5步已经实现了从"Master.Hadoop"到"Slave1.Hadoop"SSH无密码登陆,下面就是重复上面的步骤把剩余的两台(Slave2.Hadoop和Slave3.Hadoop)Slave服务器进行配置。这样,咱们就完成了"配置Master无密码登陆全部的Slave服务器"。

 

2.3 配置全部Slave无密码登陆Master

  和Master无密码登陆全部Slave原理同样,就是把Slave的公钥追加到Master的".ssh"文件夹下的"authorized_keys"中,记得是追加(>>)

  为了说明状况,咱们如今就以"Slave1.Hadoop"无密码登陆"Master.Hadoop"为例,进行一遍操做,也算是巩固一下前面所学知识,剩余的"Slave2.Hadoop"和"Slave3.Hadoop"就按照这个示例进行就能够了。

  首先建立"Slave1.Hadoop"本身的公钥和私钥,并把本身的公钥追加到"authorized_keys"文件中。用到的命令以下:

 

ssh-keygen –t rsa –P ''

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

 

 

  接着是用命令"scp"复制"Slave1.Hadoop"的公钥"id_rsa.pub"到"Master.Hadoop"的"/home/hadoop/"目录下,并追加到"Master.Hadoop"的"authorized_keys"中。

  1)在"Slave1.Hadoop"服务器的操做

  用到的命令以下:

 

scp ~/.ssh/id_rsa.pub     hadoop@192.168.1.2:~/

 

  

  2)在"Master.Hadoop"服务器的操做

  用到的命令以下:

 

cat ~/id_rsa.pub >> ~/.ssh/authorized_keys

 

 

  而后删除掉刚才复制过来的"id_rsa.pub"文件。

 

    

  最后是测试从"Slave1.Hadoop"到"Master.Hadoop"无密码登陆。

 

 

  从上面结果中能够看到已经成功实现了,再试下从"Master.Hadoop"到"Slave1.Hadoop"无密码登陆。

 

 

  至此"Master.Hadoop"与"Slave1.Hadoop"之间能够互相无密码登陆了,剩下的就是按照上面的步骤把剩余的"Slave2.Hadoop"和"Slave3.Hadoop"与"Master.Hadoop"之间创建起无密码登陆。这样,Master能无密码验证登陆每一个Slave,每一个Slave也能无密码验证登陆到Master。

 

三、Java环境安装

  全部的机器上都要安装JDK,如今就先在Master服务器安装,而后其余服务器按照步骤重复进行便可。安装JDK以及配置环境变量,须要以"root"的身份进行。

 

3.1 安装JDK

  首先用root身份登陆"Master.Hadoop"后在"/usr"下建立"java"文件夹,再把用FTP上传到"/home/hadoop/"下的"jdk-6u31-linux-i586.bin"复制到"/usr/java"文件夹中。

 

mkdir /usr/java

cp /home/hadoop/ jdk-6u31-linux-i586.bin /usr/java

 

 

  接着进入"/usr/java"目录经过下面命令使其JDK得到可执行权限,并安装JDK。

 

chmod    +x     jdk-6u31-linux-i586.bin

./jdk-6u31-linux-i586.bin

 

 

  按照上面几步进行操做,最后点击"Enter"键开始安装,安装完会提示你按"Enter"键退出,而后查看"/usr/java"下面会发现多了一个名为"jdk1.6.0_31"文件夹,说明咱们的JDK安装结束,删除"jdk-6u31-linux-i586.bin"文件,进入下一个"配置环境变量"环节。

 

 

3.2 配置环境变量

  编辑"/etc/profile"文件,在后面添加Java的"JAVA_HOME"、"CLASSPATH"以及"PATH"内容。

  1)编辑"/etc/profile"文件

 

vim     /etc/profile

 

 

  2)添加Java环境变量

  在"/etc/profile"文件的尾部添加如下内容:

 

# set java environment

export JAVA_HOME=/usr/java/jdk1.6.0_31/

export JRE_HOME=/usr/java/jdk1.6.0_31/jre

export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib

export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin

 

  或者

 

# set java environment

export JAVA_HOME=/usr/java/jdk1.6.0_31

export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib

export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin

 

   以上两种意思同样,那么咱们就选择第2种来进行设置。

 

 

  3)使配置生效

  保存并退出,执行下面命令使其配置当即生效。

 

source /etc/profile

 

 

3.3 验证安装成功

  配置完毕并生效后,用下面命令判断是否成功。

 

java -version

 

 

  从上图中得知,咱们以肯定JDK已经安装成功。

 

3.4 安装剩余机器

  这时用普通用户hadoop经过下面命令格式把"Master.Hadoop"文件夹"/home/hadoop/"的JDK复制到其余Slave的"/home/hadoop/"下面,剩下的事儿就是在其他的Slave服务器上按照上图的步骤安装JDK。

 

scp /home/hadoop/jdk-6u31-linux-i586.bin 远程用户名@远程服务器IP:~/

 

  或者

 

scp ~/jdk-6u31-linux-i586.bin 远程用户名@远程服务器IP:~/

 

  备注:"~"表明当前用户的主目录,当前用户为hadoop,因此"~"表明"/home/hadoop"。

  例如:把JDK从"Master.Hadoop"复制到"Slave1.Hadoop"的命令以下。

 

scp ~/jdk-6u31-linux-i586 hadoop@192.168.1.3:~/

 

 

  而后查看"Slave1.Hadoop"的"/home/hadoop"查看是否已经复制成功了。

 

 

  从上图中得知,咱们已经成功复制了,如今咱们就用最高权限用户root进行安装了。其余的与这个同样。

 

四、Hadoop集群安装

  全部的机器上都要安装hadoop,如今就先在Master服务器安装,而后其余服务器按照步骤重复进行便可。安装和配置hadoop须要以"root"的身份进行。

 

4.1 安装hadoop

  首先用root用户登陆"Master.Hadoop"机器,查看咱们以前用FTP上传至"/home/Hadoop"上传的"hadoop-1.0.0.tar.gz"。

 

 

  接着把"hadoop-1.0.0.tar.gz"复制到"/usr"目录下面。

 

cp /home/hadoop/hadoop-1.0.0.tar.gz /usr

 

 

  下一步进入"/usr"目录下,用下面命令把"hadoop-1.0.0.tar.gz"进行解压,并将其命名为"hadoop",把该文件夹的读权限分配给普通用户hadoop,而后删除"hadoop-1.0.0.tar.gz"安装包。

 

cd /usr #进入"/usr"目录

tar –zxvf hadoop-1.0.0.tar.gz #解压"hadoop-1.0.0.tar.gz"安装包

mv hadoop-1.0.0 hadoop #将"hadoop-1.0.0"文件夹重命名"hadoop"

chown –R hadoop:hadoop hadoop #将文件夹"hadoop"读权限分配给hadoop用户

rm –rf hadoop-1.0.0.tar.gz                 #删除"hadoop-1.0.0.tar.gz"安装包

 

 

  解压后,并重命名。

 

 

  把"/usr/hadoop"读权限分配给hadoop用户(很是重要

 

 

  删除"hadoop-1.0.0.tar.gz"安装包

 

 

  最后在"/usr/hadoop"下面建立tmp文件夹,把Hadoop的安装路径添加到"/etc/profile"中,修改"/etc/profile"文件(配置java环境变量的文件),将如下语句添加到末尾,并使其有效:

 

# set hadoop path

export HADOOP_HOME=/usr/hadoop

export PATH=$PATH :$HADOOP_HOME/bin

 

    1)在"/usr/hadoop"建立"tmp"文件夹

 

mkdir /usr/hadoop/tmp

 

 

    2)配置"/etc/profile"

 

vim /etc/profile

 

 

  配置后的文件以下:

 

    

3)重启"/etc/profile"

 

source /etc/profile

 

 

4.2 配置hadoop

  1)配置hadoop-env.sh

  该"hadoop-env.sh"文件位于"/usr/hadoop/conf"目录下。

 

 

  在文件的末尾添加下面内容。

 

# set java environment

export JAVA_HOME=/usr/java/jdk1.6.0_31

 

 

  Hadoop配置文件在conf目录下,以前的版本的配置文件主要是Hadoop-default.xml和Hadoop-site.xml。因为Hadoop发展迅速,代码量急剧增长,代码开发分为了core,hdfs和map/reduce三部分,配置文件也被分红了三个core-site.xml、hdfs-site.xml、mapred-site.xml。core-site.xml和hdfs-site.xml是站在HDFS角度上配置文件;core-site.xml和mapred-site.xml是站在MapReduce角度上配置文件。

 

  2)配置core-site.xml文件

  修改Hadoop核心配置文件core-site.xml,这里配置的是HDFS的地址和端口号。

 

<configuration>

    <property>

        <name>hadoop.tmp.dir</name>

        <value>/usr/hadoop/tmp</value>

        (备注:请先在 /usr/hadoop 目录下创建 tmp 文件夹)

        <description>A base for other temporary directories.</description>

    </property>

<!-- file system properties -->

    <property>

        <name>fs.default.name</name>

        <value>hdfs://192.168.1.2:9000</value>

    </property>

</configuration>

 

  备注:如没有配置hadoop.tmp.dir参数,此时系统默认的临时目录为:/tmp/hadoo-hadoop。而这个目录在每次重启后都会被干掉,必须从新执行format才行,不然会出错。

    用下面命令进行编辑:

 

 

    编辑结果显示以下:

 

 

  3)配置hdfs-site.xml文件

  修改Hadoop中HDFS的配置,配置的备份方式默认为3。

 

<configuration>

    <property>

        <name>dfs.replication</name>

        <value>1</value>

        (备注:replication 是数据副本数量,默认为3,salve少于3台就会报错)

    </property>

<configuration>

 

  用下面命令进行编辑:

 

 

  编辑结果显示以下:

 

 

  4)配置mapred-site.xml文件

  修改Hadoop中MapReduce的配置文件,配置的是JobTracker的地址和端口。

 

<configuration>

    <property>

        <name>mapred.job.tracker</name>

        <value>http://192.168.1.2:9001</value>

    </property>

</configuration>

 

  用下面命令进行编辑:

 

 

  编辑结果显示以下:

 

 

  5)配置masters文件

  有两种方案:

    (1)第一种

        修改localhost为Master.Hadoop

    (2)第二种

        去掉"localhost",加入Master机器的IP:192.168.1.2

  为保险起见,启用第二种,由于万一忘记配置"/etc/hosts"局域网的DNS失效,这样就会出现意想不到的错误,可是一旦IP配对,网络畅通,就能经过IP找到相应主机。

  用下面命令进行修改:

 

 

  编辑结果显示以下:

 

 

    6)配置slaves文件(Master主机特有

    有两种方案:

    (1)第一种

去掉"localhost",每行只添加一个主机名,把剩余的Slave主机名都填上。

        例如:添加形式以下

 

Slave1.Hadoop

Slave2.Hadoop

Slave3.Hadoop

 

    (2)第二种

        去掉"localhost",加入集群中全部Slave机器的IP,也是每行一个。

        例如:添加形式以下

 

192.168.1.3

192.168.1.4

192.168.1.5

 

  缘由和添加"masters"文件同样,选择第二种方式。

  用下面命令进行修改:

 

 

  编辑结果以下:

 

 

  如今在Master机器上的Hadoop配置就结束了,剩下的就是配置Slave机器上的Hadoop。

 

  一种方式是按照上面的步骤,把Hadoop的安装包在用普通用户hadoop经过"scp"复制到其余机器的"/home/hadoop"目录下,而后根据实际状况进行安装配置,除了第6步,那是Master特有的。用下面命令格式进行。(备注:此时切换到普通用户hadoop)

 

scp ~/hadoop-1.0.0.tar.gz hadoop@服务器IP:~/

 

    例如:从"Master.Hadoop"到"Slave1.Hadoop"复制Hadoop的安装包。

 

 

    另外一种方式是将 Master上配置好的hadoop所在文件夹"/usr/hadoop"复制到全部的Slave的"/usr"目录下(实际上Slave机器上的slavers文件是没必要要的, 复制了也没问题)。用下面命令格式进行。(备注:此时用户能够为hadoop也能够为root)

    

scp -r /usr/hadoop root@服务器IP:/usr/

 

    例如:从"Master.Hadoop"到"Slave1.Hadoop"复制配置Hadoop的文件。

 

 

    上图中以root用户进行复制,固然无论是用户root仍是hadoop,虽然Master机器上的"/usr/hadoop"文件夹用户hadoop有权限,可是Slave1上的hadoop用户却没有"/usr"权限,因此没有建立文件夹的权限。因此不管是哪一个用户进行拷贝,右面都是"root@机器IP"格式。由于咱们只是创建起了hadoop用户的SSH无密码链接,因此用root进行"scp"时,扔提示让你输入"Slave1.Hadoop"服务器用户root的密码。

    查看"Slave1.Hadoop"服务器的"/usr"目录下是否已经存在"hadoop"文件夹,确认已经复制成功。查看结果以下:

 

 

  从上图中知道,hadoop文件夹确实已经复制了,可是咱们发现hadoop权限是root,因此咱们如今要给"Slave1.Hadoop"服务器上的用户hadoop添加对"/usr/hadoop"读权限。

  以root用户登陆"Slave1.Hadoop",执行下面命令。

 

chown -R hadoop:hadoop(用户名:用户组) hadoop(文件夹

 

  

  接着在"Slave1 .Hadoop"上修改"/etc/profile"文件(配置 java 环境变量的文件),将如下语句添加到末尾,并使其有效(source /etc/profile):

 

# set hadoop environment

export HADOOP_HOME=/usr/hadoop

export PATH=$PATH :$HADOOP_HOME/bin

 

  若是不知道怎么设置,能够查看前面"Master.Hadoop"机器的"/etc/profile"文件的配置,到此为此在一台Slave机器上的Hadoop配置就结束了。剩下的事儿就是照葫芦画瓢把剩余的几台Slave机器按照《从"Master.Hadoop"到"Slave1.Hadoop"复制Hadoop的安装包。》这个例子进行部署Hadoop。

 

4.3 启动及验证

  1)格式化HDFS文件系统

  在"Master.Hadoop"上使用普通用户hadoop进行操做。(备注:只需一次,下次启动再也不须要格式化,只需 start-all.sh)

 

hadoop namenode -format

 

  某些书上和网上的某些资料中用下面命令执行。

 

 

  咱们在看好多文档包括有些书上,按照他们的hadoop环境变量进行配置后,并当即使其生效,可是执行发现没有找见"bin/hadoop"这个命令。

 

 

  其实咱们会发现咱们的环境变量配置的是"$HADOOP_HOME/bin",咱们已经把bin包含进入了,因此执行时,加上"bin"反而找不到该命令,除非咱们的hadoop坏境变量以下设置。

 

# set hadoop path

export HADOOP_HOME=/usr/hadoop

export PATH=$PATH : $HADOOP_HOME :$HADOOP_HOME/bin

 

  这样就能直接使用"bin/hadoop"也能够直接使用"hadoop",如今无论哪一种状况,hadoop命令都能找见了。咱们也没有必要从新在设置hadoop环境变量了,只须要记住执行Hadoop命令时不须要在前面加"bin"就能够了。

 

 

    

  从上图中知道咱们已经成功格式话了,可是美中不足就是出现了一个警告,从网上的得知这个警告并不影响hadoop执行,可是也有办法解决,详情看后面的"常见问题FAQ"。

    

  2)启动hadoop

  在启动前关闭集群中全部机器的防火墙,否则会出现datanode开后又自动关闭。

 

service iptables stop

 

  使用下面命令启动。

 

start-all.sh

 

 

  执行结果以下:

 

 

  能够经过如下启动日志看出,首先启动namenode 接着启动datanode1,datanode2,…,而后启动secondarynamenode。再启动jobtracker,而后启动tasktracker1,tasktracker2,…。

  启动 hadoop成功后,在 Master 中的 tmp 文件夹中生成了 dfs 文件夹,在Slave 中的 tmp 文件夹中均生成了 dfs 文件夹和 mapred 文件夹。

  查看Master中"/usr/hadoop/tmp"文件夹内容

 

 

  查看Slave1中"/usr/hadoop/tmp"文件夹内容。

 

 

  3)验证hadoop

  (1)验证方法一:用"jps"命令

  在Master上用 java自带的小工具jps查看进程。

 

 

  在Slave1上用jps查看进程。

 

 

  若是在查看Slave机器中发现"DataNode"和"TaskTracker"没有起来时,先查看一下日志的,若是是"namespaceID"不一致问题,采用"常见问题FAQ6.2"进行解决,若是是"No route to host"问题,采用"常见问题FAQ6.3"进行解决。

 

  (2)验证方式二:用"hadoop dfsadmin -report"

  用这个命令能够查看Hadoop集群的状态。

  Master服务器的状态:

 

 

  Slave服务器的状态

 

 

4.4 网页查看集群

  1)访问"http:192.168.1.2:50030"

 

 

  2)访问"http:192.168.1.2:50070"

 

 

五、常见问题FAQ

 

5.1 关于 Warning: $HADOOP_HOME is deprecated.

  hadoop 1.0.0版本,安装完以后敲入hadoop命令时,是提示这个警告:

 

Warning: $HADOOP_HOME is deprecated.

 

  经查hadoop-1.0.0/bin/hadoop脚本和"hadoop-config.sh"脚本,发现脚本中对HADOOP_HOME的环境变量设置作了判断,笔者的环境根本不须要设置HADOOP_HOME环境变量。

  解决方案一:编辑"/etc/profile"文件,去掉HADOOP_HOME的变量设定,从新输入hadoop fs命令,警告消失。

  解决方案二:编辑"/etc/profile"文件,添加一个环境变量,以后警告消失:

 

export HADOOP_HOME_WARN_SUPPRESS=1

 

  解决方案三:编辑"hadoop-config.sh"文件,把下面的"if - fi"功能注释掉。

 

 

  咱们这里本着不动Hadoop原配置文件的前提下,采用"方案二",在"/etc/profile"文件添加上面内容,并用命令"source /etc/profile"使之有效。

  1)切换至root用户

 

 

  2)添加内容

 

 

  3)从新生效

 

 

5.2 解决"no datanode to stop"问题

  当我中止Hadoop时发现以下信息:

 

 

  缘由:每次namenode format会从新建立一个namenodeId,而tmp/dfs/data下包含了上次format下的id,namenode format清空了namenode下的数据,可是没有清空datanode下的数据,致使启动时失败,所要作的就是每次fotmat前,清空tmp一下的全部目录。

  第一种解决方案以下:

  1)先删除"/usr/hadoop/tmp"

 

rm -rf /usr/hadoop/tmp

 

  2)建立"/usr/hadoop/tmp"文件夹

 

mkdir /usr/hadoop/tmp

 

  3)删除"/tmp"下以"hadoop"开头文件

 

rm -rf /tmp/hadoop*

 

  4)从新格式化hadoop

 

hadoop namenode -format

 

  5)启动hadoop

 

start-all.sh

 

  使用第一种方案,有种很差处就是原来集群上的重要数据全没有了。假如说Hadoop集群已经运行了一段时间。建议采用第二种。

  第二种方案以下:

  1)修改每一个Slave的namespaceID使其与Master的namespaceID一致。

  或者

  2)修改Master的namespaceID使其与Slave的namespaceID一致。

 

  该"namespaceID"位于"/usr/hadoop/tmp/dfs/data/current/VERSION"文件中,前面蓝色的可能根据实际状况变化,但后面红色是不变的。

  例如:查看"Master"下的"VERSION"文件

 

 

  本人建议采用第二种,这样方便快捷,并且还能防止误删。

 

5.3 Slave服务器中datanode启动后又自动关闭

  查看日志发下以下错误。

  ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: java.io.IOException: Call to ... failed on local exception: java.net.NoRouteToHostException: No route to host

  解决方案是:关闭防火墙

 

service iptables stop

 

5.4 从本地往hdfs文件系统上传文件

  出现以下错误:

  INFO hdfs.DFSClient: Exception in createBlockOutputStream java.io.IOException: Bad connect ack with firstBadLink

  INFO hdfs.DFSClient: Abandoning block blk_-1300529705803292651_37023

  WARN hdfs.DFSClient: DataStreamer Exception: java.io.IOException: Unable to create new block.

  解决方案是:

  1)关闭防火墙

 

service iptables stop

 

  2)禁用selinux

    编辑 "/etc/selinux/config"文件,设置"SELINUX=disabled"

 

5.5 安全模式致使的错误

  出现以下错误:

  org.apache.hadoop.dfs.SafeModeException: Cannot delete ..., Name node is in safe mode

  在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的状况下,文件系统中的内容不容许修改也不容许删除,直到安全模式结束。安全模式主要是为了系统启动的时候检查各个DataNode上数据块的有效性,同时根据策略必要的复制或者删除部分数据块。运行期经过命令也能够进入安全模式。在实践过程当中,系统启动的时候去修改和删除文件也会有安全模式不容许修改的出错提示,只须要等待一下子便可。

  解决方案是:关闭安全模式

 

hadoop dfsadmin -safemode leave

 

5.6 解决Exceeded MAX_FAILED_UNIQUE_FETCHES

  出现错误以下:

  Shuffle Error: Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out

  程序里面须要打开多个文件,进行分析,系统通常默认数量是1024,(用ulimit -a能够看到)对于正常使用是够了,可是对于程序来说,就太少了。

  解决方案是:修改2个文件。

  1)"/etc/security/limits.conf"

 

vim /etc/security/limits.conf

 

  加上:

 

soft nofile 102400

hard nofile 409600

 

  2)"/etc/pam.d/login"

 

vim /etc/pam.d/login

 

  添加:

 

session required /lib/security/pam_limits.so

 

  针对第一个问题我纠正下答案:

  这是reduce预处理阶段shuffle时获取已完成的map的输出失败次数超过上限形成的,上限默认为5。引发此问题的方式可能会有不少种,好比网络链接不正常,链接超时,带宽较差以及端口阻塞等。一般框架内网络状况较好是不会出现此错误的。

 

5.7 解决"Too many fetch-failures"

  出现这个问题主要是结点间的连通不够全面。

  解决方案是:

  1)检查"/etc/hosts"

  要求本机ip 对应 服务器名

  要求要包含全部的服务器ip +服务器名

  2)检查".ssh/authorized_keys"

  要求包含全部服务器(包括其自身)的public key

 

5.8 处理速度特别的慢

  出现map,可是reduce,并且反复出现"reduce=0%"。

  解决方案以下:

  结合解决方案5.7,而后修改"conf/hadoop-env.sh"中的"export HADOOP_HEAPSIZE=4000"

 

5.9解决hadoop OutOfMemoryError问题

  出现这种异常,明显是jvm内存不够得缘由。

  解决方案以下:要修改全部的datanode的jvm内存大小。

 

Java –Xms 1024m -Xmx 4096m

 

  通常jvm的最大内存使用应该为总内存大小的一半,咱们使用的8G内存,因此设置为4096m,这一值可能依旧不是最优的值。

 

5.10 Namenode in safe mode

  解决方案以下:

 

bin/hadoop dfsadmin -safemode leave

 

5.11 IO写操做出现问题

  0-1246359584298, infoPort=50075, ipcPort=50020):Got exception while serving blk_-5911099437886836280_1292 to /172.16.100.165:

  java.net.SocketTimeoutException: 480000 millis timeout while waiting for channel to be ready for write. ch : java.nio.channels.SocketChannel[connected local=/

  172.16.100.165:50010 remote=/172.16.100.165:50930]

  at org.apache.hadoop.net.SocketIOWithTimeout.waitForIO(SocketIOWithTimeout.java:185)

  at org.apache.hadoop.net.SocketOutputStream.waitForWritable(SocketOutputStream.java:159)

  ……

  It seems there are many reasons that it can timeout, the example given in HADOOP-3831 is a slow reading client.

    解决方案以下:

  在hadoop-site.xml中设置dfs.datanode.socket.write.timeout=0

 

5.12 status of 255 error

  错误类型:

  java.io.IOException: Task process exit with nonzero status of 255.

  at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:424)

 

  错误缘由:

  Set mapred.jobtracker.retirejob.interval and mapred.userlog.retain.hours to higher value. By default, their values are 24 hours. These might be the reason for failure, though I'm not sure restart.

  解决方案以下:单个datanode

  若是一个datanode 出现问题,解决以后须要从新加入cluster而不重启cluster,方法以下:

 

bin/hadoop-daemon.sh start datanode

bin/hadoop-daemon.sh start jobtracker

 

 

六、用到的Linux命令

 

6.1 chmod命令详解

  使用权限:全部使用者

  使用方式:chmod [-cfvR] [--help] [--version] mode file...

  说明:

  Linux/Unix 的档案存取权限分为三级 : 档案拥有者、群组、其余。利用 chmod 能够藉以控制档案如何被他人所存取。

  mode :权限设定字串,格式以下 :[ugoa...][[+-=][rwxX]...][,...],其中u 表示该档案的拥有者,g 表示与该档案的拥有者属于同一个群体(group)者,o 表示其余之外的人,a 表示这三者皆是。

 

+ 表示增长权限、- 表示取消权限、= 表示惟一设定权限。

r 表示可读取,w 表示可写入,x 表示可执行,X 表示只有当该档案是个子目录或者该档案已经被设定过为可执行。

 

-c : 若该档案权限确实已经更改,才显示其更改动做

-f : 若该档案权限没法被更改也不要显示错误讯息

-v : 显示权限变动的详细资料

-R : 对目前目录下的全部档案与子目录进行相同的权限变动(即以递回的方式逐个变动)

--help : 显示辅助说明

--version : 显示版本

 

  范例:

  将档案 file1.txt 设为全部人皆可读取

 

chmod ugo+r file1.txt

 

  将档案 file1.txt 设为全部人皆可读取

 

chmod a+r file1.txt

 

  将档案 file1.txt 与 file2.txt 设为该档案拥有者,与其所属同一个群体者可写入,但其余之外的人则不可写入

 

chmod ug+w,o-w file1.txt file2.txt

 

  将 ex1.py 设定为只有该档案拥有者能够执行

 

chmod u+x ex1.py

 

  将目前目录下的全部档案与子目录皆设为任何人可读取

 

chmod -R a+r *

 

  此外chmod也能够用数字来表示权限如 chmod 777 file

  语法为:chmod abc file

  其中a,b,c各为一个数字,分别表示User、Group、及Other的权限。

  r=4,w=2,x=1

  若要rwx属性则4+2+1=7;

  若要rw-属性则4+2=6;

  若要r-x属性则4+1=7。

  范例:

  chmod a=rwx file 和 chmod 777 file 效果相同

  chmod ug=rwx,o=x file 和 chmod 771 file 效果相同

  若用chmod 4755 filename可以使此程式具备root的权限

 

6.2 chown命令详解

  使用权限:root

  使用方式:chown [-cfhvR] [--help] [--version] user[:group] file...

  说明:

  Linux/Unix 是多人多工做业系统,全部的档案皆有拥有者。利用 chown 能够将档案的拥有者加以改变。通常来讲,这个指令只有是由系统管理者(root)所使用,通常使用者没有权限能够改变别人的档案拥有者,也没有权限能够本身的档案拥有者改设为别人。只有系统管理者(root)才有这样的权限。

 

user : 新的档案拥有者的使用者

IDgroup : 新的档案拥有者的使用者群体(group)

-c : 若该档案拥有者确实已经更改,才显示其更改动做

-f : 若该档案拥有者没法被更改也不要显示错误讯息

-h : 只对于连结(link)进行变动,而非该 link 真正指向的档案

-v : 显示拥有者变动的详细资料

-R : 对目前目录下的全部档案与子目录进行相同的拥有者变动(即以递回的方式逐个变动)

--help : 显示辅助说明

--version : 显示版本

 

  范例:

  将档案 file1.txt 的拥有者设为 users 群体的使用者 jessie

 

chown jessie:users file1.txt

 

  将目前目录下的全部档案与子目录的拥有者皆设为 users 群体的使用者 lamport

 

chown -R lamport:users *

 

-rw------- (600) -- 只有属主有读写权限。

-rw-r--r-- (644) -- 只有属主有读写权限;而属组用户和其余用户只有读权限。

-rwx------ (700) -- 只有属主有读、写、执行权限。

-rwxr-xr-x (755) -- 属主有读、写、执行权限;而属组用户和其余用户只有读、执行权限。

-rwx--x--x (711) -- 属主有读、写、执行权限;而属组用户和其余用户只有执行权限。

-rw-rw-rw- (666) -- 全部用户都有文件读、写权限。这种作法不可取。

-rwxrwxrwx (777) -- 全部用户都有读、写、执行权限。更不可取的作法。

 

  如下是对目录的两个普通设定:

 

drwx------ (700) - 只有属主可在目录中读、写。

drwxr-xr-x (755) - 全部用户可读该目录,但只有属主才能改变目录中的内容

 

  suid的表明数字是4,好比4755的结果是-rwsr-xr-x

  sgid的表明数字是2,好比6755的结果是-rwsr-sr-x

  sticky位表明数字是1,好比7755的结果是-rwsr-sr-t

 

6.3 scp命令详解

  scp是 secure copy的缩写,scp是linux系统下基于ssh登录进行安全的远程文件拷贝命令。linux的scp命令能够在linux服务器之间复制文件和目录。

  scp命令的用处:

  scp在网络上不一样的主机之间复制文件,它使用ssh安全协议传输数据,具备和ssh同样的验证机制,从而安全的远程拷贝文件。

  scp命令基本格式:

 

scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]

[-l limit] [-o ssh_option] [-P port] [-S program]

[[user@]host1:]file1 [...] [[user@]host2:]file2

 

  scp命令的参数说明:

 

-1    强制scp命令使用协议ssh1

-2    强制scp命令使用协议ssh2

-4    强制scp命令只使用IPv4寻址

-6    强制scp命令只使用IPv6寻址

-B    使用批处理模式(传输过程当中不询问传输口令或短语)

-C    容许压缩。(将-C标志传递给ssh,从而打开压缩功能)

-p 保留原文件的修改时间,访问时间和访问权限。

-q    不显示传输进度条。

-r    递归复制整个目录。

-v 详细方式显示输出。scp和ssh(1)会显示出整个过程的调试信息。这些信息用于调试链接,验证和配置问题。

-c cipher    以cipher将数据传输进行加密,这个选项将直接传递给ssh。

-F ssh_config    指定一个替代的ssh配置文件,此参数直接传递给ssh。

-i identity_file        从指定文件中读取传输时使用的密钥文件,此参数直接传递给ssh。

-l limit    限定用户所能使用的带宽,以Kbit/s为单位。

-o ssh_option    若是习惯于使用ssh_config(5)中的参数传递方式,

-P port 注意是大写的P, port是指定数据传输用到的端口号

-S program    指定加密传输时所使用的程序。此程序必须可以理解ssh(1)的选项。

 

  scp命令的实际应用

  1)从本地服务器复制到远程服务器    

  (1) 复制文件:

  命令格式:

 

scp local_file remote_username@remote_ip:remote_folder

  或者

scp local_file remote_username@remote_ip:remote_file

  或者

scp local_file remote_ip:remote_folder

  或者

scp local_file remote_ip:remote_file

 

  第1,2个指定了用户名,命令执行后须要输入用户密码,第1个仅指定了远程的目录,文件名字不变,第2个指定了文件名

  第3,4个没有指定用户名,命令执行后须要输入用户名和密码,第3个仅指定了远程的目录,文件名字不变,第4个指定了文件名

  实例:

 

scp /home/linux/soft/scp.zip root@www.mydomain.com:/home/linux/others/soft

scp /home/linux/soft/scp.zip root@www.mydomain.com:/home/linux/others/soft/scp2.zip

scp /home/linux/soft/scp.zip www.mydomain.com:/home/linux/others/soft

scp /home/linux/soft/scp.zip www.mydomain.com:/home/linux/others/soft/scp2.zip

 

  (2) 复制目录:

  命令格式:

 

scp -r local_folder remote_username@remote_ip:remote_folder

  或者

scp -r local_folder remote_ip:remote_folder

 

  第1个指定了用户名,命令执行后须要输入用户密码;

  第2个没有指定用户名,命令执行后须要输入用户名和密码;

 

  例子:

 

scp -r /home/linux/soft/ root@www.mydomain.com:/home/linux/others/

scp -r /home/linux/soft/ www.mydomain.com:/home/linux/others/

 

  上面 命令 将 本地 soft 目录 复制 到 远程 others 目录下,即复制后远程服务器上会有/home/linux/others/soft/ 目录。

 

  2)从远程服务器复制到本地服务器

  从远程复制到本地的scp命令与上面的命令雷同,只要将从本地复制到远程的命令后面2个参数互换顺序就好了。

  例如:

 

scp root@www.mydomain.com:/home/linux/soft/scp.zip /home/linux/others/scp.zip

scp www.mydomain.com:/home/linux/soft/ -r /home/linux/others/

 

  linux系统下scp命令中不少参数都和ssh1有关,还须要看到更原汁原味的参数信息,能够运行man scp 看到更细致的英文说明。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.5.rar

Hadoop集群(第5期副刊)_JDK和SSH无密码配置

 

一、Linux配置java环境变量

 

1.1 原文出处

    地址:http://blog.csdn.net/jiedushi/article/details/6672894

 

1.2 解压安装jdk

  在shell终端下进入jdk-6u14-linux-i586.bin文件所在目录,执行命令 ./jdk-6u14-linux-i586.bin 这时会出现一段协议,连继敲回车,当询问是否赞成的时候,输入yes,回车。以后会在当前目录下生成一个jdk1.6.0_14目录,你能够将它复制到 任何一个目录下。

 

1.3 须要配置的环境变量

  1)PATH环境变量

  做用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序。咱们须要把 jdk安装目录下的bin目录增长到现有的PATH变量中,bin目录中包含常常要用到的可执行文件如javac/java/javadoc等待,设置好 PATH变量后,就能够在任何目录下执行javac/java等工具了。

  2)CLASSPATH环境变量

  做用是指定类搜索路径,要使用已经编写好的类,前提固然是可以找到它们了,JVM就是经过CLASSPTH来寻找类的。咱们 须要把jdk安装目录下的lib子目录中的dt.jar和tools.jar设置到CLASSPATH中,固然,当前目录"."也必须加入到该变量中。

  3)JAVA_HOME环境变量

  它指向jdk的安装目录,Eclipse/NetBeans/Tomcat等软件就是经过搜索JAVA_HOME变量来找到并使用安装好的jdk。

 

1.4 三种配置环境变量的方法

  1)修改/etc/profile文件

  若是你的计算机仅仅做为开发使用时推荐使用这种方法,由于全部用户的shell都有权使用这些环境变量,可能会给系统带来安全性问题。

  • 用文本编辑器打开/etc/profile
  • 在profile文件末尾加入:

 

export JAVA_HOME=/usr/share/jdk1.6.0_14

export PATH=$JAVA_HOME/bin:$PATH

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

 

  • 从新登陆
  • 注解

 

a. 你要将 /usr/share/jdk1.6.0_14改成你的jdk安装目录

b. linux下用冒号":"来分隔路径

c. $PATH / $CLASSPATH / $JAVA_HOME 是用来引用原来的环境变量的值

在设置环境变量时特别要注意不能把原来的值给覆盖掉了,这是一种

常见的错误。

d. CLASSPATH中当前目录"."不能丢,把当前目录丢掉也是常见的错误。

e. export是把这三个变量导出为全局变量。

f. 大小写必须严格区分。

 

  2)修改.bash_profile文件

  这种方法更为安全,它能够把使用这些环境变量的权限控制到用户级别,若是你须要给某个用户权限使用这些环境变量,你只须要修改其我的用户主目录下的.bash_profile文件就能够了。

  • 用文本编辑器打开用户目录下的.bash_profile文件
  • 在.bash_profile文件末尾加入:

 

export JAVA_HOME=/usr/share/jdk1.6.0_14

export PATH=$JAVA_HOME/bin:$PATH

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

 

  • 从新登陆

 

  3)直接在shell下设置变量

  不同意使用这种方法,由于换个shell,你的设置就无效了,所以这种方法仅仅是临时使用,之后要使用的时候又要从新设置,比较麻烦。

  只需在shell终端执行下列命令:

 

export JAVA_HOME=/usr/share/jdk1.6.0_14

export PATH=$JAVA_HOME/bin:$PATH

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

 

 

  1.5 测试jdk

  1)用文本编辑器新建一个Test.java文件,在其中输入如下代码并保存:

 

public class test {

    public static void main(String args[]) {

        System.out.println("A new jdk test !");

    }

}

 

  2)编译:

  在shell终端执行命令 javac Test.java

  3)运行:

  在shell终端执行命令 java Test

   当shell下出现"A new jdk test !"字样则jdk运行正常。

 

1.6 卸载jdk

  • 找到jdk安装目录的_uninst子目录
  • 在shell终端执行命令./uninstall.sh便可卸载jdk。

 

二、配置OpenSSH无密码登录

 

2.1 原文出处

    地址:http://www.iteye.com/topic/421608

 

2.2 文章序言

  最近在搭建Hadoop环境须要设置无密码登录,所谓无密码登录实际上是指经过证书认证的方式登录,使用一种被称为"公私钥"认证的方式来进行ssh登陆。

   在linux系统中,ssh是远程登陆的默认工具,由于该工具的协议使用了RSA/DSA的加密算法.该工具作linux系统的远程管理是很是安全的。telnet,由于其不安全性,在linux系统中被搁置使用了。

  " 公私钥"认证方式简单的解释:首先在客户端上建立一对公私钥 (公钥文件:~/.ssh/id_rsa.pub; 私钥文件:~/.ssh/id_rsa)。而后把公钥放到服务器上(~/.ssh/authorized_keys), 本身保留好私钥.在使用ssh登陆时,ssh程序会发送私钥去和服务器上的公钥作匹配.若是匹配成功就能够登陆了。

  在Ubuntu和Cygwin 配置都很顺利,而在Centos系统中配置时遇到了不少问题。故此文以Centos(Centos5 ) 为例详细讲解如何配置证书验证登录,具体操做步骤以下:

 

2.3 确认系统已经安装好OpenSSH的server 和client

  安装步骤这里再也不讲述,不是本文的重点。

 

2.4 确认本机sshd的配置文件(root)

 

$ vi /etc/ssh/sshd_config

 

  找到如下内容,并去掉注释符"#"

 

RSAAuthentication yes

PubkeyAuthentication yes

AuthorizedKeysFile .ssh/authorized_keys

 

 

2.5 若是修改了配置文件须要重启sshd服务(root)

 

$ vi /sbin/service sshd restart

 

 

2.6 ssh登录系统 后执行测试命令

 

$ ssh localhost

 

  回车会提示你输入密码,由于此时咱们尚未生成证书。

 

2.7 生成证书公私钥的步骤

 

$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa

$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

 

2.8 测试登录 ssh localhost

 

$ ssh localhost

 

  正常状况下会登录成功,显示一些成功登录信息,若是失败请看下面的"通常调试步骤"。

 

2.9 通常调试步骤

  本人在配置时就失败了,按照以上步骤依旧提示要输入密码。因而用ssh -v 显示详细的登录信息查找缘由:

 

$ ssh -v localhost

 

  回车显示了详细的登录信息以下:

 

。。。。。。省略

debug1: Authentications that can continue: publickey,gssapi-with-mic,password

debug1: Next authentication method: gssapi-with-mic

debug1: Unspecified GSS failure. Minor code may provide more information

Unknown code krb5 195

debug1: Unspecified GSS failure. Minor code may provide more information

Unknown code krb5 195

debug1: Unspecified GSS failure. Minor code may provide more information

Unknown code krb5 195

debug1: Next authentication method: publickey

debug1: Trying private key: /home/huaxia/.ssh/identity

debug1: Trying private key: /home/huaxia/.ssh/id_rsa

debug1: Offering public key: /home/huaxia/.ssh/id_dsa

debug1: Authentications that can continue: publickey,gssapi-with-mic,password

debug1: Next authentication method: password

huaxia@localhost's password:

 

  同时用root用户登录查看系统的日志文件:

 

$tail /var/log/secure -n 20

 

。。。。。。省略

Jul 13 11:21:05 shnap sshd[3955]: Accepted password for huaxia from 192.168.8.253 port 51837 ssh2

Jul 13 11:21:05 shnap sshd[3955]: pam_unix(sshd:session): session opened for user huaxia by (uid=0)

Jul 13 11:21:47 shnap sshd[4024]: Connection closed by 127.0.0.1

Jul 13 11:25:28 shnap sshd[4150]: Authentication refused: bad ownership or modes for file /home/huaxia/.ssh/authorized_keys

Jul 13 11:25:28 shnap sshd[4150]: Authentication refused: bad ownership or modes for file /home/huaxia/.ssh/authorized_keys

Jul 13 11:26:30 shnap sshd[4151]: Connection closed by 127.0.0.1

。。。。。。省略

 

  从上面的日志信息中可知文件/home/huaxia/.ssh/authorized_keys 的权限有问题。

  查看/home/huaxia/.ssh/ 下文件的详细信息以下:

 

$ ls -lh ~/.ssh/

总计 16K

-rw-rw-r-- 1 huaxia huaxia 602 07-13 11:22 authorized_keys

-rw------- 1 huaxia huaxia 672 07-13 11:22 id_dsa

-rw-r--r-- 1 huaxia huaxia 602 07-13 11:22 id_dsa.pub

-rw-r--r-- 1 huaxia huaxia 391 07-13 11:21 known_hosts

 

  修改文件authorized_keys的权限(权限的设置很是重要,由于不安全的设置安全设置,会让你不能使用RSA功能 ):

 

$ chmod 600 ~/.ssh/authorized_keys

 

  再次测试登录以下:

 

$ ssh localhost

Last login: Wed Jul 13 14:04:06 2011 from 192.168.8.253

 

  看到这样的信息表示已经成功实现了本机的无密码登录。

 

2.10 认证登录远程服务器

  备注:远程服务器OpenSSH的服务固然要启动。

  拷贝本地生产的key到远程服务器端(两种方法)

  1)方法一:

 

$cat ~/.ssh/id_rsa.pub | ssh 远程用户名@远程服务器ip 'cat - >> ~/.ssh/authorized_keys'

 

  2)方法二:

  在本机上执行:

 

$ scp ~/.ssh/id_dsa.pub michael@192.168.8.148:/home/michael/

 

  登录远程服务器michael@192.168.8.148 后执行:

 

$ cat id_dsa.pub >> ~/.ssh/authorized_keys

 

  本机远程登录192.168.8.148的测试:

 

$ssh michael@192.168.8.148

Linux michael-VirtualBox 2.6.35-22-generic #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010 i686 GNU/Linux

Ubuntu 10.10

 

Welcome to Ubuntu!

* Documentation: https://help.ubuntu.com/

 

216 packages can be updated.

71 updates are security updates.

 

New release 'natty' available.

Run 'do-release-upgrade' to upgrade to it.

 

Last login: Wed Jul 13 14:46:37 2011 from michael-virtualbox

michael@michael-VirtualBox:~$

 

  可见已经成功登录。

  若是登录测试不成功,须要修改远程服务器192.168.8.148上的文件authorized_keys的权限(权限的设置很是重要,由于不安全的设置安全设置,会让你不能使用RSA功能

 

chmod 600 ~/.ssh/authorized_keys

 

   文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.5S.rar

Hadoop集群(第6期)_WordCount运行详解

 

一、MapReduce理论简介

 

1.1 MapReduce编程模型

  MapReduce采用"分而治之"的思想,把对大规模数据集的操做,分发给一个主节点管理下的各个分节点共同完成,而后经过整合各个节点的中间结果,获得最终结果。简单地说,MapReduce就是"任务的分解与结果的汇总"。

  在Hadoop中,用于执行MapReduce任务的机器角色有两个:一个是JobTracker;另外一个是TaskTracker,JobTracker是用于调度工做的,TaskTracker是用于执行工做的。一个Hadoop集群中只有一台JobTracker。

  在分布式计算中,MapReduce框架负责处理了并行编程中分布式存储、工做调度、负载均衡、容错均衡、容错处理以及网络通讯等复杂问题,把处理过程高度抽象为两个函数:map和reduce,map负责把任务分解成多个任务,reduce负责把分解后多任务处理的结果汇总起来。

  须要注意的是,用MapReduce来处理的数据集(或任务)必须具有这样的特色:待处理的数据集能够分解成许多小的数据集,并且每个小数据集均可以彻底并行地进行处理。

 

1.2 MapReduce处理过程

  在Hadoop中,每一个MapReduce任务都被初始化为一个Job,每一个Job又能够分为两种阶段:map阶段和reduce阶段。这两个阶段分别用两个函数表示,即map函数和reduce函数。map函数接收一个<key,value>形式的输入,而后一样产生一个<key,value>形式的中间输出,Hadoop函数接收一个如<key,(list of values)>形式的输入,而后对这个value集合进行处理,每一个reduce产生0或1个输出,reduce的输出也是<key,value>形式的。

 

 image

MapReduce处理大数据集的过程

 

 

二、运行WordCount程序

  单词计数是最简单也是最能体现MapReduce思想的程序之一,能够称为MapReduce版"Hello World",该程序的完整代码能够在Hadoop安装包的"src/examples"目录下找到。单词计数主要完成功能是:统计一系列文本文件中每一个单词出现的次数,以下图所示。

 

 image

 

2.1 准备工做

  如今以"hadoop"普通用户登陆"Master.Hadoop"服务器。

  1)建立本地示例文件

  首先在"/home/hadoop"目录下建立文件夹"file"。

 

 image

 

  接着建立两个文本文件file1.txt和file2.txt,使file1.txt内容为"Hello World",而file2.txt的内容为"Hello Hadoop"。

 

image

 

  2)在HDFS上建立输入文件夹

 

image

 

  3)上传本地file中文件到集群的input目录下

 

image

 

2.2 运行例子

  1)在集群上运行WordCount程序

  备注:以input做为输入目录,output目录做为输出目录。

  已经编译好的WordCount的Jar在"/usr/hadoop"下面,就是"hadoop-examples-1.0.0.jar",因此在下面执行命令时记得把路径写全了,否则会提示找不到该Jar包。

 

 image

 

  2)MapReduce执行过程显示信息

 

image

 

  Hadoop命令会启动一个JVM来运行这个MapReduce程序,并自动得到Hadoop的配置,同时把类的路径(及其依赖关系)加入到Hadoop的库中。以上就是Hadoop Job的运行记录,从这里能够看到,这个Job被赋予了一个ID号:job_201202292213_0002,并且得知输入文件有两个(Total input paths to process : 2),同时还能够了解map的输入输出记录(record数及字节数),以及reduce输入输出记录。好比说,在本例中,map的task数量是2个,reduce的task数量是一个。map的输入record数是2个,输出record数是4个等信息。

 

2.3 查看结果

  1)查看HDFS上output目录内容

 

image

 

  从上图中知道生成了三个文件,咱们的结果在"part-r-00000"中。

  2)查看结果输出文件内容

 

image

 

三、WordCount源码分析

 

3.1 特别数据类型介绍

  Hadoop提供了以下内容的数据类型,这些数据类型都实现了WritableComparable接口,以便用这些类型定义的数据能够被序列化进行网络传输和文件存储,以及进行大小比较。

 

    BooleanWritable:标准布尔型数值

    ByteWritable:单字节数值

    DoubleWritable:双字节数

    FloatWritable:浮点数

    IntWritable:整型数

    LongWritable:长整型数

    Text:使用UTF8格式存储的文本

    NullWritable:当<key,value>中的key或value为空时使用

 

3.2 旧的WordCount分析

  1)源代码程序

 

package org.apache.hadoop.examples;

import java.io.IOException;
import java.util.Iterator;
import java.util.StringTokenizer;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapred.TextInputFormat;
import org.apache.hadoop.mapred.TextOutputFormat;

public class WordCount {

    public static class Map extends MapReduceBase implements
            Mapper<LongWritable, Text, Text, IntWritable> {
        private final static IntWritable one = new IntWritable(1);
        private Text word = new Text();

        public void map(LongWritable key, Text value,
                OutputCollector<Text, IntWritable> output, Reporter reporter)
                throws IOException {
            String line = value.toString();
            StringTokenizer tokenizer = new StringTokenizer(line);
            while (tokenizer.hasMoreTokens()) {
                word.set(tokenizer.nextToken());
                output.collect(word, one);
            }
        }
    }

    public static class Reduce extends MapReduceBase implements
            Reducer<Text, IntWritable, Text, IntWritable> {
        public void reduce(Text key, Iterator<IntWritable> values,
                OutputCollector<Text, IntWritable> output, Reporter reporter)
                throws IOException {
            int sum = 0;
            while (values.hasNext()) {
                sum += values.next().get();
            }
            output.collect(key, new IntWritable(sum));
        }
    }

    public static void main(String[] args) throws Exception {
        JobConf conf = new JobConf(WordCount.class);
        conf.setJobName("wordcount");

        conf.setOutputKeyClass(Text.class);
        conf.setOutputValueClass(IntWritable.class);

        conf.setMapperClass(Map.class);
        conf.setCombinerClass(Reduce.class);
        conf.setReducerClass(Reduce.class);

        conf.setInputFormat(TextInputFormat.class);
        conf.setOutputFormat(TextOutputFormat.class);

        FileInputFormat.setInputPaths(conf, new Path(args[0]));
        FileOutputFormat.setOutputPath(conf, new Path(args[1]));

        JobClient.runJob(conf);
    }
}

 

  3)主方法Main分析

 

public static void main(String[] args) throws Exception {
    JobConf conf = new JobConf(WordCount.class);
    conf.setJobName("wordcount");

    conf.setOutputKeyClass(Text.class);
    conf.setOutputValueClass(IntWritable.class);

    conf.setMapperClass(Map.class);
    conf.setCombinerClass(Reduce.class);
    conf.setReducerClass(Reduce.class);

    conf.setInputFormat(TextInputFormat.class);
    conf.setOutputFormat(TextOutputFormat.class);

    FileInputFormat.setInputPaths(conf, new Path(args[0]));
    FileOutputFormat.setOutputPath(conf, new Path(args[1]));

    JobClient.runJob(conf);
}

 

  首先讲解一下Job初始化过程main函数调用Jobconf类来对MapReduce Job进行初始化,而后调用setJobName()方法命名这个Job。对Job进行合理的命名有助于更快地找到Job,以便在JobTracker和Tasktracker的页面中对其进行监视

 

JobConf conf = new JobConf(WordCount. class ); conf.setJobName("wordcount" );

 

  接着设置Job输出结果<key,value>的中key和value数据类型,由于结果是<单词,个数>,因此key设置为"Text"类型,至关于Java中String类型。Value设置为"IntWritable",至关于Java中的int类型。

 

conf.setOutputKeyClass(Text.class );

conf.setOutputValueClass(IntWritable.class );

 

  而后设置Job处理的Map(拆分)、Combiner(中间结果合并)以及Reduce(合并)的相关处理类。这里用Reduce类来进行Map产生的中间结果合并,避免给网络数据传输产生压力。

 

conf.setMapperClass(Map.class );

conf.setCombinerClass(Reduce.class );

conf.setReducerClass(Reduce.class );

 

  接着就是调用setInputPath()和setOutputPath()设置输入输出路径。

 

conf.setInputFormat(TextInputFormat.class );

conf.setOutputFormat(TextOutputFormat.class );

 

  (1)InputFormat和InputSplit

  InputSplit是Hadoop定义的用来传送给每一个单独map数据,InputSplit存储的并数据自己而是一个分片长度和一个记录数据位置数组生成InputSplit的方法能够经过InputFormat()设置

  当数据传送给map时,map会将输入分片传送到InputFormat,InputFormat则调用方法getRecordReader()生成RecordReaderRecordReader再经过creatKey()creatValue()方法建立可供map处理的<key,value>对。简而言之,InputFormat()方法是用来生成可供map处理的<key,value>对的。

  Hadoop预约义了多种方法将不一样类型的输入数据转化为map可以处理的<key,value>对,它们都继承自InputFormat,分别是:

 

    InputFormat

        |

        |---BaileyBorweinPlouffe.BbpInputFormat

        |---ComposableInputFormat

        |---CompositeInputFormat

        |---DBInputFormat

        |---DistSum.Machine.AbstractInputFormat

        |---FileInputFormat

            |---CombineFileInputFormat

            |---KeyValueTextInputFormat

            |---NLineInputFormat

            |---SequenceFileInputFormat

            |---TeraInputFormat

            |---TextInputFormat

 

  其中TextInputFormat是Hadoop默认的输入方法,在TextInputFormat中,每一个文件(或其一部分)都会单独地做为map的输入,而这个是继承自FileInputFormat的。以后,每行数据都会生成一条记录,每条记录则表示成<key,value>形式:

  • key值是每一个数据的记录在 数据分片字节偏移量,数据类型是 LongWritable;  

value值是每行的内容,数据类型是Text

  (2)OutputFormat

  每一种格式都有一种格式与其对应。默认的输出格式是TextOutputFormat,这种输出方式与输入相似,会将每条记录以一行的形式存入文本文件。不过,它的键和值能够是任意形式的,由于程序内容会调用toString()方法将键和值转换为String类型再输出。

 

  3)Map类中map方法分析

 

public static class Map extends MapReduceBase implements
        Mapper<LongWritable, Text, Text, IntWritable> {
    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(LongWritable key, Text value,
            OutputCollector<Text, IntWritable> output, Reporter reporter)
            throws IOException {
        String line = value.toString();
        StringTokenizer tokenizer = new StringTokenizer(line);
        while (tokenizer.hasMoreTokens()) {
            word.set(tokenizer.nextToken());
            output.collect(word, one);
        }
    }
}

 

  Map类继承自MapReduceBase,而且它实现了Mapper接口,此接口是一个规范类型,它有4种形式的参数,分别用来指定map的输入key值类型、输入value值类型、输出key值类型和输出value值类型。在本例中,由于使用的是TextInputFormat,它的输出key值是LongWritable类型,输出value值是Text类型,因此map的输入类型为<LongWritable,Text>。在本例中须要输出<word,1>这样的形式,所以输出的key值类型是Text,输出的value值类型是IntWritable。

  实现此接口类还须要实现map方法,map方法会具体负责对输入进行操做,在本例中,map方法对输入的行以空格为单位进行切分,而后使用OutputCollect收集输出的<word,1>。

 

  4)Reduce类中reduce方法分析

 

public static class Reduce extends MapReduceBase implements
        Reducer<Text, IntWritable, Text, IntWritable> {
    public void reduce(Text key, Iterator<IntWritable> values,
            OutputCollector<Text, IntWritable> output, Reporter reporter)
            throws IOException {
        int sum = 0;
        while (values.hasNext()) {
            sum += values.next().get();
        }
        output.collect(key, new IntWritable(sum));
    }
}

 

  Reduce类也是继承自MapReduceBase的,须要实现Reducer接口。Reduce类以map的输出做为输入,所以Reduce的输入类型是<Text,Intwritable>。而Reduce的输出是单词它的数目,所以,它的输出类型是<Text,IntWritable>。Reduce类也要实现reduce方法,在此方法中,reduce函数将输入的key值做为输出的key值,而后将得到多个value值加起来,做为输出的值。

 

3.3 新的WordCount分析

  1)源代码程序

 

package org.apache.hadoop.examples;

import java.io.IOException;

import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

public class WordCount {

  public static class TokenizerMapper

      extends Mapper<Object, Text, Text, IntWritable>{

      private final static IntWritable one = new IntWritable(1);

      private Text word = new Text();

 

      public void map(Object key, Text value, Context context)

        throws IOException, InterruptedException {

        StringTokenizer itr = new StringTokenizer(value.toString());

        while (itr.hasMoreTokens()) {

        word.set(itr.nextToken());

        context.write(word, one);

      }

    }

  }

  public static class IntSumReducer

      extends Reducer<Text,IntWritable,Text,IntWritable> {

      private IntWritable result = new IntWritable();

      public void reduce(Text key, Iterable<IntWritable> values,Context context)

           throws IOException, InterruptedException {

        int sum = 0;

        for (IntWritable val : values) {

           sum += val.get();

        }

      result.set(sum);

      context.write(key, result);

    }

  }

 

  public static void main(String[] args) throws Exception {

    Configuration conf = new Configuration();

    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

    if (otherArgs.length != 2) {

      System.err.println("Usage: wordcount <in> <out>");

      System.exit(2);

    }

    Job job = new Job(conf, "word count");

    job.setJarByClass(WordCount.class);

    job.setMapperClass(TokenizerMapper.class);

    job.setCombinerClass(IntSumReducer.class);

    job.setReducerClass(IntSumReducer.class);

    job.setOutputKeyClass(Text.class);

    job.setOutputValueClass(IntWritable.class);

    FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

    FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

    System.exit(job.waitForCompletion(true) ? 0 : 1);

}

}

 

   1)Map过程

 

public static class TokenizerMapper

  extends Mapper<Object, Text, Text, IntWritable>{

  private final static IntWritable one = new IntWritable(1);

  private Text word = new Text();

  public void map(Object key, Text value, Context context)

    throws IOException, InterruptedException {

    StringTokenizer itr = new StringTokenizer(value.toString());

    while (itr.hasMoreTokens()) {

      word.set(itr.nextToken());

      context.write(word, one);

  }

}

 

  Map过程须要继承org.apache.hadoop.mapreduce包中Mapper类,并重写其map方法。经过在map方法中添加两句把key值和value值输出到控制台的代码,能够发现map方法中value值存储的是文本文件中的一行(以回车符为行结束标记),而key值为该行的首字母相对于文本文件的首地址的偏移量。而后StringTokenizer类将每一行拆分红为一个个的单词,并将<word,1>做为map方法的结果输出,其他的工做都交有MapReduce框架处理。

 

  2)Reduce过程

 

public static class IntSumReducer

  extends Reducer<Text,IntWritable,Text,IntWritable> {

  private IntWritable result = new IntWritable();

  public void reduce(Text key, Iterable<IntWritable> values,Context context)

     throws IOException, InterruptedException {

    int sum = 0;

    for (IntWritable val : values) {

      sum += val.get();

    }

    result.set(sum);

    context.write(key, result);

  }

}

 

  Reduce过程须要继承org.apache.hadoop.mapreduce包中Reducer类,并重写其reduce方法。Map过程输出<key,values>中key为单个单词,而values是对应单词的计数值所组成的列表,Map的输出就是Reduce的输入,因此reduce方法只要遍历values并求和,便可获得某个单词的总次数。

 

    3)执行MapReduce任务

 

public static void main(String[] args) throws Exception {

  Configuration conf = new Configuration();

  String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

  if (otherArgs.length != 2) {

    System.err.println("Usage: wordcount <in> <out>");

    System.exit(2);

  }

  Job job = new Job(conf, "word count");

  job.setJarByClass(WordCount.class);

  job.setMapperClass(TokenizerMapper.class);

  job.setCombinerClass(IntSumReducer.class);

  job.setReducerClass(IntSumReducer.class);

  job.setOutputKeyClass(Text.class);

  job.setOutputValueClass(IntWritable.class);

  FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

  FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

  System.exit(job.waitForCompletion(true) ? 0 : 1);

}

 

  在MapReduce中,由Job对象负责管理和运行一个计算任务,并经过Job的一些方法对任务的参数进行相关的设置。此处设置了使用TokenizerMapper完成Map过程当中的处理和使用IntSumReducer完成Combine和Reduce过程当中的处理。还设置了Map过程和Reduce过程的输出类型:key的类型为Text,value的类型为IntWritable。任务的输出和输入路径则由命令行参数指定,并由FileInputFormat和FileOutputFormat分别设定。完成相应任务的参数设定后,便可调用job.waitForCompletion()方法执行任务。

 

四、WordCount处理过程

  本节将对WordCount进行更详细的讲解。详细执行步骤以下:

 

  1)将文件拆分红splits,因为测试用的文件较小,因此每一个文件为一个split,并将文件按行分割造成<key,value>对,如图4-1所示。这一步由MapReduce框架自动完成,其中偏移量(即key值)包括了回车所占的字符数(Windows和Linux环境会不一样)。

 

 image

图4-1 分割过程

 

  2)将分割好的<key,value>对交给用户定义的map方法进行处理,生成新的<key,value>对,如图4-2所示。

 

 image

图4-2 执行map方法

 

  3)获得map方法输出的<key,value>对后,Mapper会将它们按照key值进行排序,并执行Combine过程,将key至相同value值累加,获得Mapper的最终输出结果。如图4-3所示。

 

 image

图4-3 Map端排序及Combine过程

 

  4)Reducer先对从Mapper接收的数据进行排序,再交由用户自定义的reduce方法进行处理,获得新的<key,value>对,并做为WordCount的输出结果,如图4-4所示。

 

 image

图4-4 Reduce端排序及输出结果

 

五、MapReduce新旧改变

  Hadoop最新版本的MapReduce Release 0.20.0的API包括了一个全新的Mapreduce JAVA API,有时候也称为上下文对象。

  新的API类型上不兼容之前的API,因此,之前的应用程序须要重写才能使新的API发挥其做用 。

  新的API和旧的API之间有下面几个明显的区别。

  • 新的API倾向于使用抽象类,而不是接口,由于这更容易扩展。例如,你能够添加一个方法(用默认的实现)到一个抽象类而不需修改类以前的实现方法。在新的API中,Mapper和Reducer是抽象类。
  • 新的API是在org.apache.hadoop.mapreduce包(和子包)中的。以前版本的API则是放在org.apache.hadoop.mapred中的。
  • 新的API普遍使用context object(上下文对象),并容许用户代码与MapReduce系统进行通讯。例如,MapContext基本上充当着JobConf的OutputCollector和Reporter的角色。
  • 新的API同时支持"推"和"拉"式的迭代。在这两个新老API中,键/值记录对被推mapper中,但除此以外,新的API容许把记录从map()方法中拉出,这也适用于reducer。"拉"式的一个有用的例子是分批处理记录,而不是一个接一个。
  • 新的API统一了配置。旧的API有一个特殊的JobConf对象用于做业配置,这是一个对于Hadoop一般的Configuration对象的扩展。在新的API中,这种区别没有了,因此做业配置经过Configuration来完成。做业控制的执行由Job类来负责,而不是JobClient,它在新的API中已经荡然无存。

     

      文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.6.rar

Hadoop集群(第7期)_Eclipse开发环境设置

一、Hadoop开发环境简介

1.1 Hadoop集群简介

  Java版本:jdk-6u31-linux-i586.bin

  Linux系统:CentOS6.0

  Hadoop版本:hadoop-1.0.0.tar.gz

1.2 Windows开发简介

  Java版本:jdk-6u31-windows-i586.exe

  Win系统:Windows 7 旗舰版

  Eclipse软件:eclipse-jee-indigo-SR1-win32.zip | eclipse-jee-helios-SR2-win32.zip

  Hadoop软件:hadoop-1.0.0.tar.gz

  Hadoop Eclipse 插件:hadoop-eclipse-plugin-1.0.0.jar

  下载地址:http://download.csdn.net/detail/xia520pi/4113746

  备注:下面是网上收集的收集的"hadoop-eclipse-plugin-1.0.0.jar",除"版本2.0"是根据"V1.0"按照"常见问题FAQ_1"改的以外,剩余的"V3.0"、"V4.0"和"V5.0"和"V2.0"同样是别人已经弄好的,并且我已经都测试过,没有任何问题,能够放心使用。咱们这里选择第"V5.0"使用。记得在使用时从新命名为"hadoop-eclipse-plugin-1.0.0.jar"。

 

二、Hadoop Eclipse简介和使用

2.1 Eclipse插件介绍

  Hadoop是一个强大的并行框架,它容许任务在其分布式集群上并行处理。可是编写、调试Hadoop程序都有很大难度。正由于如此,Hadoop的开发者开发出了Hadoop Eclipse插件,它在Hadoop的开发环境中嵌入了Eclipse,从而实现了开发环境的图形化,下降了编程难度。在安装插件,配置Hadoop的相关信息以后,若是用户建立Hadoop程序,插件会自动导入Hadoop编程接口的JAR文件,这样用户就能够在Eclipse的图形化界面中编写、调试、运行Hadoop程序(包括单机程序和分布式程序),也能够在其中查看本身程序的实时状态、错误信息和运行结果,还能够查看、管理HDFS以及文件。总地来讲,Hadoop Eclipse插件安装简单,使用方便,功能强大,尤为是在Hadoop编程方面,是Hadoop入门和Hadoop编程必不可少的工具。

2.2 Hadoop工做目录简介

  为了之后方便开发,咱们按照下面把开发中用到的软件安装在此目录中,JDK安装除外,我这里把JDK安装在C盘的默认安装路径下,下面是个人工做目录:

 

    系统磁盘(E:)

        |---HadoopWorkPlat

            |--- eclipse

            |--- hadoop-1.0.0

            |--- workplace

            |---……

 

  按照上面目录把Eclipse和Hadoop解压到"E:\HadoopWorkPlat"下面,并建立"workplace"做为Eclipse的工做空间。

 

 

  备注:你们能够按照本身的状况,不必定按照个人结构来设计。

2.3 修改系统管理员名字

  通过两天屡次探索,为了使Eclipse能正常对Hadoop集群的HDFS上的文件能进行修改和删除,因此修改你工做时所用的Win7系统管理员名字,默认通常为"Administrator",把它修改成"hadoop",此用户名与Hadoop集群普通用户一致,你们应该记得咱们Hadoop集群中全部的机器都有一个普通用户——hadoop,并且Hadoop运行也是用这个用户进行的。为了避免至于为权限苦恼,咱们能够修改Win7上系统管理员的姓名,这样就避免出现该用户在Hadoop集群上没有权限等都疼问题,会致使在Eclipse中对Hadoop集群的HDFS建立和删除文件受影响。

  你能够作一下实验,查看Master.Hadoop机器上"/usr/hadoop/logs"下面的日志。发现权限不够,不能进行"Write"操做,网上有几种解决方案,可是对Hadoop1.0不起做用,详情见"常见问题FAQ_2"。下面咱们进行修改管理员名字。

  首先"右击"桌面上图标"个人电脑",选择"管理",弹出界面以下:

 

 

  接着选择"本地用户和组",展开"用户",找到系统管理员"Administrator",修改其为"hadoop",操做结果以下图:

 

 

  最后,把电脑进行"注销"或者"重启电脑",这样才能使管理员才能用这个名字。

2.4 Eclipse插件开发配置

  第一步:把咱们的"hadoop-eclipse-plugin-1.0.0.jar"放到Eclipse的目录的"plugins"中,而后从新Eclipse便可生效。

 

    系统磁盘(E:)

        |---HadoopWorkPlat

            |--- eclipse

                |--- plugins

                    |--- hadoop-eclipse-plugin-1.0.0.jar

 

  上面是个人"hadoop-eclipse-plugin"插件放置的地方。重启Eclipse以下图:

 

 

  细心的你从上图中左侧"Project Explorer"下面发现"DFS Locations",说明Eclipse已经识别刚才放入的Hadoop Eclipse插件了。

 

  第二步:选择"Window"菜单下的"Preference",而后弹出一个窗体,在窗体的左侧,有一列选项,里面会多出"Hadoop Map/Reduce"选项,点击此选项,选择Hadoop的安装目录(如个人Hadoop目录:E:\HadoopWorkPlat\hadoop-1.0.0)。结果以下图:

 

 

  第三步:切换"Map/Reduce"工做目录,有两种方法:

  1)选择"Window"菜单下选择"Open Perspective",弹出一个窗体,从中选择"Map/Reduce"选项便可进行切换。

 

 

  2)在Eclipse软件的右上角,点击图标""中的"",点击"Other"选项,也能够弹出上图,从中选择"Map/Reduce",而后点击"OK"便可肯定。

  切换到"Map/Reduce"工做目录下的界面以下图所示。

 

 

  第四步:创建与Hadoop集群的链接,在Eclipse软件下面的"Map/Reduce Locations"进行右击,弹出一个选项,选择"New Hadoop Location",而后弹出一个窗体。

 

 

 

  注意上图中的红色标注的地方,是须要咱们关注的地方。

  • Location Name:能够任意其,标识一个"Map/Reduce Location"
  • Map/Reduce Master
    Host:192.168.1.2( Master.Hadoop的IP地址)
    Port:9001
  • DFS Master
    Use M/R Master host:前面的 勾上。(由于咱们的NameNode和JobTracker都在一个机器上。)
    Port:9000
  • User name:hadoop(默认为Win系统管理员名字,由于咱们以前改了因此这里就变成了hadoop。)

 

 

  备注:这里面的Host、Port分别为你在mapred-site.xml、core-site.xml中配置的地址及端口。不清楚的能够参考"Hadoop集群_第5期_Hadoop安装配置_V1.0"进行查看。

   接着点击"Advanced parameters"从中找见"hadoop.tmp.dir",修改为为咱们Hadoop集群中设置的地址,咱们的Hadoop集群是"/usr/hadoop/tmp",这个参数在"core-site.xml"进行了配置。

 

 

  点击"finish"以后,会发现Eclipse软件下面的"Map/Reduce Locations"出现一条信息,就是咱们刚才创建的"Map/Reduce Location"。

 

    

  第五步:查看HDFS文件系统,并尝试创建文件夹和上传文件。点击Eclipse软件左侧的"DFS Locations"下面的"Win7ToHadoop",就会展现出HDFS上的文件结构。

 

    

  右击"Win7ToHadoopàuseràhadoop"能够尝试创建一个"文件夹--xiapi",而后右击刷新就能查看咱们刚才创建的文件夹。

 

 

  建立完以后,并刷新,显示结果以下:

 

 

  用SecureCRT远程登陆"Master.Hadoop"服务器,用下面命令查看是否已经创建一个"xiapi"的文件夹。

 

hadoop fs -ls

 

    

  到此为止,咱们的Hadoop Eclipse开发环境已经配置完毕,不尽兴的同窗能够上传点本地文件到HDFS分布式文件上,能够互相对比意见文件是否已经上传成功。

三、Eclipse运行WordCount程序

3.1 配置Eclipse的JDK

  若是电脑上不只仅安装的JDK6.0,那么要肯定一下Eclipse的平台的默认JDK是否6.0。从"Window"菜单下选择"Preference",弹出一个窗体,从窗体的左侧找见"Java",选择"Installed JREs",而后添加JDK6.0。下面是个人默认选择JRE。

 

 

  下面是没有添加以前的设置以下:

 

 

  下面是添加完JDK6.0以后结果以下:

 

 

  接着设置Complier。

 

 

3.2 设置Eclipse的编码为UTF-8

 

 

3.3 建立MapReduce项目

   从"File"菜单,选择"Other",找到"Map/Reduce Project",而后选择它。

 

    

  接着,填写MapReduce工程的名字为"WordCountProject",点击"finish"完成。

 

 

  目前为止咱们已经成功建立了MapReduce项目,咱们发如今Eclipse软件的左侧多了咱们的刚才创建的项目。

 

 

3.4 建立WordCount类

  选择"WordCountProject"工程,右击弹出菜单,而后选择"New",接着选择"Class",而后填写以下信息:

 

 

  由于咱们直接用Hadoop1.0.0自带的WordCount程序,因此报名须要和代码中的一致为"org.apache.hadoop.examples",类名也必须一致为"WordCount"。这个代码放在以下的结构中。

 

    hadoop-1.0.0

        |---src

            |---examples

                |---org

                    |---apache

                        |---hadoop

                            |---examples

 

  从上面目录中找见"WordCount.java"文件,用记事本打开,而后把代码复制到刚才创建的java文件中。固然源码有些变更,变更的红色已经标记出。

 

?
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package org.apache.hadoop.examples;
 
import java.io.IOException;
import java.util.StringTokenizer;
 
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
 
public class WordCount {
 
   public static class TokenizerMapper
        extends Mapper<Object, Text, Text, IntWritable>{
     
     private final static IntWritable one = new IntWritable( 1 );
     private Text word = new Text();
       
     public void map(Object key, Text value, Context context
                     ) throws IOException, InterruptedException {
       StringTokenizer itr = new StringTokenizer(value.toString());
       while (itr.hasMoreTokens()) {
         word.set(itr.nextToken());
         context.write(word, one);      }
     }
   }
   
   public static class IntSumReducer
        extends Reducer<Text,IntWritable,Text,IntWritable> {
     private IntWritable result = new IntWritable();
 
     public void reduce(Text key, Iterable values,
                        Context context
                        ) throws IOException, InterruptedException {
       int sum = 0 ;
       for (IntWritable val : values) {
         sum += val.get();
       }
       result.set(sum);
       context.write(key, result);
     }
   }
 
   public static void main(String[] args) throws Exception {
     Configuration conf = new Configuration();
     conf.set( "mapred.job.tracker" , "192.168.1.2:9001" );
     String[] ars= new String[]{ "input" , "newout" };
     String[] otherArgs = new GenericOptionsParser(conf, ars).getRemainingArgs();
     if (otherArgs.length != 2 ) {
       System.err.println( "Usage: wordcount  " );
       System.exit( 2 );
     }
     Job job = new Job(conf, "word count" );
     job.setJarByClass(WordCount. class );
     job.setMapperClass(TokenizerMapper. class );
     job.setCombinerClass(IntSumReducer. class );
     job.setReducerClass(IntSumReducer. class );
     job.setOutputKeyClass(Text. class );
     job.setOutputValueClass(IntWritable. class );
     FileInputFormat.addInputPath(job, new Path(otherArgs[ 0 ]));
     FileOutputFormat.setOutputPath(job, new Path(otherArgs[ 1 ]));
     System.exit(job.waitForCompletion( true ) ? 0 : 1 );
   }
}

 

  备注:若是不加"conf.set("mapred.job.tracker", "192.168.1.2:9001");",将提示你的权限不够,其实照成这样的缘由是刚才设置的"Map/Reduce Location"其中的配置不是彻底起做用,而是在本地的磁盘上创建了文件,并尝试运行,显然是不行的。咱们要让Eclipse提交做业到Hadoop集群上,因此咱们这里手动添加Job运行地址。详细参考"常见问题FAQ_3"。

3.5 运行WordCount程序

  选择"Wordcount.java"程序,右击一次按照"Run ASàRun on Hadoop"运行。而后会弹出以下图,按照下图进行操做。

 

 

  运行结果以下:

 

 

  从上图中咱们得知咱们的程序已经运行成功了。

3.6 查看WordCount运行结果

  查看Eclipse软件左侧,右击"DFS LocationsàWin7ToHadoopàuseràhadoop",点击刷新按钮"Refresh",咱们刚才出现的文件夹"newoutput"会出现。记得"newoutput"文件夹是运行程序时自动建立的,若是已经存在相同的的文件夹,要么程序换个新的输出文件夹,要么删除HDFS上的那个重名文件夹,否则会出错。

 

 

  打开"newoutput"文件夹,打开"part-r-00000"文件,能够看见执行后的结果。

 

 

  到此为止,Eclipse开发环境设置已经完毕,而且成功运行Wordcount程序,下一步咱们真正开始Hadoop之旅。

四、常见问题FAQ

4.1 "error: failure to login"问题

  下面以网上找的"hadoop-0.20.203.0"为例,我在使用"V1.0"时也出现这样的状况,缘由就是那个"hadoop-eclipse-plugin-1.0.0_V1.0.jar",是直接把源码编译而成,故而缺乏相应的Jar包。具体状况以下

  详细地址:http://blog.csdn.net/chengfei112233/article/details/7252404

  在我实践尝试中,发现hadoop-0.20.203.0版本的该包若是直接复制到eclipse的插件目录中,在链接DFS时会出现错误,提示信息为: "error: failure to login"。

  弹出的错误提示框内容为"An internal error occurred during: "Connecting to DFS hadoop".org/apache/commons/configuration/Configuration". 通过察看Eclipse的log,发现是缺乏jar包致使的。进一步查找资料后,发现直接复制hadoop-eclipse-plugin-0.20.203.0.jar,该包中lib目录下缺乏了jar包。

  通过网上资料搜集,此处给出正确的安装方法:

  首先要对hadoop-eclipse-plugin-0.20.203.0.jar进行修改。用归档管理器打开该包,发现只有commons-cli-1.2.jar 和hadoop-core.jar两个包。将hadoop/lib目录下的:

  • commons-configuration-1.6.jar ,
  • commons-httpclient-3.0.1.jar ,
  • commons-lang-2.4.jar ,
  • jackson-core-asl-1.0.1.jar
  • jackson-mapper-asl-1.0.1.jar

一共5个包复制到hadoop-eclipse-plugin-0.20.203.0.jar的lib目录下,以下图:

 

 

  而后,修改该包META-INF目录下的MANIFEST.MF,将classpath修改成一下内容:

 

Bundle-ClassPath:classes/,lib/hadoop-core.jar,lib/commons-cli-1.2.jar,lib/commons-httpclient-3.0.1.jar,lib/jackson-core-asl-1.0.1.jar,lib/jackson-mapper-asl-1.0.1.jar,lib/commons-configuration-1.6.jar,lib/commons-lang-2.4.jar

 

 

  这样就完成了对hadoop-eclipse-plugin-0.20.203.0.jar的修改。

  最后,将hadoop-eclipse-plugin-0.20.203.0.jar复制到Eclipse的plugins目录下。

  备注:上面的操做对"hadoop-1.0.0"同样适用。

4.2 "Permission denied"问题

  网上试了不少,有提到"hadoop fs -chmod 777 /user/hadoop ",有提到"dfs.permissions 的配置项,将value值改成 false",有提到"hadoop.job.ugi",可是统统没有效果。

  参考文献:

        地址1:http://www.cnblogs.com/acmy/archive/2011/10/28/2227901.html

        地址2:http://sunjun041640.blog.163.com/blog/static/25626832201061751825292/

    错误类型:org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=*********, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-x

    解决方案:

    个人解决方案直接把系统管理员的名字改为你的Hadoop集群运行hadoop的那个用户。

4.3 "Failed to set permissions of path"问题

   参考文献:https://issues.apache.org/jira/browse/HADOOP-8089

   错误信息以下:

    ERROR security.UserGroupInformation: PriviledgedActionException as: hadoop cause:java.io.IOException Failed to set permissions of path:\usr\hadoop\tmp\mapred\staging\hadoop753422487\.staging to 0700 Exception in thread "main" java.io.IOException: Failed to set permissions of path: \usr\hadoop\tmp \mapred\staging\hadoop753422487\.staging to 0700

   解决方法:

 

Configuration conf = new Configuration();

conf.set("mapred.job.tracker", "[server]:9001");

 

   "[server]:9001"中的"[server]"为Hadoop集群Master的IP地址。

4.4 "hadoop mapred执行目录文件权"限问题

   参考文献:http://blog.csdn.net/azhao_dn/article/details/6921398

   错误信息以下:

   job Submission failed with exception 'java.io.IOException(The ownership/permissions on the staging directory /tmp/hadoop-hadoop-user1/mapred/staging/hadoop-user1/.staging is not as expected. It is owned by hadoop-user1 and permissions are rwxrwxrwx. The directory must be owned by the submitter hadoop-user1 or by hadoop-user1 and permissions must be rwx------)

   修改权限:

 

 

  这样就能解决问题。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.7.rar




Hadoop集群(第8期)_HDFS初探之旅

一、HDFS简介

  HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,能够运行于廉价的商用服务器上。它所具备的高容错、高可靠性、高可扩展性、高得到性、高吞吐率等特征为海量数据提供了不怕故障的存储,为超大数据集(Large Data Set)的应用处理带来了不少便利。

  Hadoop整合了众多文件系统,在其中有一个综合性的文件系统抽象,它提供了文件系统实现的各种接口,HDFS只是这个抽象文件系统的一个实例。提供了一个高层的文件系统抽象类org.apache.hadoop.fs.FileSystem,这个抽象类展现了一个分布式文件系统,并有几个具体实现,以下表1-1所示。

表1-1 Hadoop的文件系统

文件系统

URI方案

Java实现

org.apache.hadoop

定义

Local

file

fs.LocalFileSystem

支持有客户端校验和本地文件系统。带有校验和的本地系统文件在fs.RawLocalFileSystem中实现。

HDFS

hdfs

hdfs.DistributionFileSystem

Hadoop的分布式文件系统。

HFTP

hftp

hdfs.HftpFileSystem

支持经过HTTP方式以只读的方式访问HDFSdistcp常常用在不一样HDFS集群间复制数据。

HSFTP

hsftp

hdfs.HsftpFileSystem

支持经过HTTPS方式以只读的方式访问HDFS

HAR

har

fs.HarFileSystem

构建在Hadoop文件系统之上,对文件进行归档。Hadoop归档文件主要用来减小NameNode内存使用

KFS

kfs

fs.kfs.KosmosFileSystem

Cloudstore(其前身是Kosmos文件系统)文件系统是相似于HDFSGoogleGFS文件系统,使用C++编写。

FTP

ftp

fs.ftp.FtpFileSystem

FTP服务器支持的文件系统。

S3(本地)

s3n

fs.s3native.NativeS3FileSystem

基于Amazon S3的文件系统。

S3(基于块)

s3 

fs.s3.NativeS3FileSystem

基于Amazon S3的文件系统,以块格式存储解决了S35GB文件大小的限制。

  Hadoop提供了许多文件系统的接口,用户能够使用URI方案选取合适的文件系统来实现交互。

二、HDFS基础概念

2.1 数据块(block)

  • HDFS(Hadoop Distributed File System)默认的最基本的存储单位是64M的数据块。
  • 和普通文件系统相同的是,HDFS中的文件是被分红64M一块的数据块存储的。
  • 不一样于普通文件系统的是,HDFS中,若是一个文件小于一个数据块的大小,并不占用整个数据块存储空间。

2.2 NameNode和DataNode

  HDFS体系结构中有两类节点,一类是NameNode,又叫"元数据节点";另外一类是DataNode,又叫"数据节点"。这两类节点分别承担Master和Worker具体任务的执行节点。

  1)元数据节点用来管理文件系统的命名空间

  • 其将全部的文件和文件夹的元数据保存在一个文件系统树中。
  • 这些信息也会在硬盘上保存成如下文件:命名空间镜像(namespace image)及修改日志(edit log)
  • 其还保存了一个文件包括哪些数据块,分布在哪些数据节点上。然而这些信息并不存储在硬盘上,而是在系统启动的时候从数据节点收集而成的。

  2)数据节点是文件系统中真正存储数据的地方。

  • 客户端(client)或者元数据信息(namenode)能够向数据节点请求写入或者读出数据块。
  • 其周期性的向元数据节点回报其存储的数据块信息。

  3)从元数据节点(secondary namenode)

  • 从元数据节点并非元数据节点出现问题时候的备用节点,它和元数据节点负责不一样的事情。
  • 其主要功能就是周期性将元数据节点的命名空间镜像文件和修改日志合并,以防日志文件过大。这点在下面会相信叙述。
  • 合并事后的命名空间镜像文件也在从元数据节点保存了一份,以防元数据节点失败的时候,能够恢复。

2.3 元数据节点目录结构

 

  

 

  VERSION文件是java properties文件,保存了HDFS的版本号。

  • layoutVersion是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。
  • namespaceID是文件系统的惟一标识符,是在文件系统初次格式化时生成的。
  • cTime此处为0
  • storageType表示此文件夹中保存的是元数据节点的数据结构。

 

namespaceID=1232737062

cTime=0

storageType=NAME_NODE

layoutVersion=-18

 

2.4 数据节点的目录结构

 

  

  • 数据节点的VERSION文件格式以下:

 

namespaceID=1232737062

storageID=DS-1640411682-127.0.1.1-50010-1254997319480

cTime=0

storageType=DATA_NODE

layoutVersion=-18

 

  • blk_<id>保存的是HDFS的数据块,其中保存了具体的二进制数据。
  • blk_<id>.meta保存的是数据块的属性信息:版本信息,类型信息,和checksum
  • 当一个目录中的数据块到达必定数量的时候,则建立子文件夹来保存数据块及数据块属性信息。

2.5 文件系统命名空间映像文件及修改日志

  • 当文件系统客户端(client)进行写操做时,首先把它记录在修改日志中(edit log)
  • 元数据节点在内存中保存了文件系统的元数据信息。在记录了修改日志后,元数据节点则修改内存中的数据结构。
  • 每次的写操做成功以前,修改日志都会同步(sync)到文件系统。
  • fsimage文件,也即命名空间映像文件,是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不可以在硬盘上直接修改。
  • 同数据的机制类似,当元数据节点失败时,则最新checkpoint的元数据信息从fsimage加载到内存中,而后逐一从新执行修改日志中的操做。
  • 从元数据节点就是用来帮助元数据节点将内存中的元数据信息checkpoint到硬盘上的
  • checkpoint的过程以下:
    • 从元数据节点通知元数据节点生成新的日志文件,之后的日志都写到新的日志文件中。
    • 从元数据节点用http get从元数据节点得到fsimage文件及旧的日志文件。
    • 从元数据节点将fsimage文件加载到内存中,并执行日志文件中的操做,而后生成新的fsimage文件。
    • 从元数据节点奖新的fsimage文件用http post传回元数据节点
    • 元数据节点能够将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生成的),而后更新fstime文件,写入这次checkpoint的时间。
    • 这样元数据节点中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也从新开始,不会变的很大了。

 

 

三、HDFS体系结构

  HDFS是一个主/从(Mater/Slave)体系结构,从最终用户的角度来看,它就像传统的文件系统同样,能够经过目录路径对文件执行CRUD(Create、Read、Update和Delete)操做。但因为分布式存储的性质,HDFS集群拥有一个NameNode和一些DataNode。NameNode管理文件系统的元数据,DataNode存储实际的数据。客户端经过同NameNode和DataNodes的交互访问文件系统。客户端联系NameNode以获取文件的元数据,而真正的文件I/O操做是直接和DataNode进行交互的。

 

图3.1 HDFS整体结构示意图

 

  1)NameNode、DataNode和Client

  • NameNode能够看做是分布式文件系统中的管理者,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等。NameNode会将文件系统的Meta-data存储在内存中,这些信息主要包括了文件信息、每个文件对应的文件块的信息和每个文件块在DataNode的信息等。
  • DataNode是文件存储的基本单元,它将Block存储在本地文件系统中,保存了Block的Meta-data,同时周期性地将全部存在的Block信息发送给NameNode。
  • Client就是须要获取分布式文件系统文件的应用程序。

  2)文件写入

  • Client向NameNode发起文件写入的请求。
  • NameNode根据文件大小和文件块配置状况,返回给Client它所管理部分DataNode的信息。
  • Client将文件划分为多个Block,根据DataNode的地址信息,按顺序写入到每个DataNode块中。

  3)文件读取

  • Client向NameNode发起文件读取的请求。
  • NameNode返回文件存储的DataNode的信息。
  • Client读取文件信息。

 

  HDFS典型的部署是在一个专门的机器上运行NameNode,集群中的其余机器各运行一个DataNode;也能够在运行NameNode的机器上同时运行DataNode,或者一台机器上运行多个DataNode。一个集群只有一个NameNode的设计大大简化了系统架构。

四、HDFS的优缺点

4.1 HDFS的优势

  1)处理超大文件

  这里的超大文件一般是指百MB、设置数百TB大小的文件。目前在实际应用中,HDFS已经能用来存储管理PB级的数据了。

  2)流式的访问数据

  HDFS的设计创建在更多地响应"一次写入、屡次读写"任务的基础上。这意味着一个数据集一旦由数据源生成,就会被复制分发到不一样的存储节点中,而后响应各类各样的数据分析任务请求。在多数状况下,分析任务都会涉及数据集中的大部分数据,也就是说,对HDFS来讲,请求读取整个数据集要比读取一条记录更加高效

  3)运行于廉价的商用机器集群上

  Hadoop设计对硬件需求比较,只须运行在低廉的商用硬件集群上,而无需昂贵的高可用性机器上。廉价的商用机也就意味着大型集群中出现节点故障状况的几率很是高。这就要求设计HDFS时要充分考虑数据的可靠性,安全性及高可用性。

4.2 HDFS的缺点

  1)不适合低延迟数据访问

  若是要处理一些用户要求时间比较短的低延迟应用请求,则HDFS不适合。HDFS是为了处理大型数据集分析任务的,主要是为达到数据吞吐量而设计的,这就可能要求以高延迟做为代价。

  改进策略:对于那些有低延时要求的应用程序,HBase是一个更好的选择。经过上层数据管理项目来尽量地弥补这个不足。在性能上有了很大的提高,它的口号就是goes real time。使用缓存或多master设计能够下降client的数据请求压力,以减小延时。还有就是对HDFS系统内部的修改,这就得权衡大吞吐量与低延时了,HDFS不是万能的银弹。

  2)没法高效存储大量小文件

  由于Namenode把文件系统的元数据放置在内存中,因此文件系统所能容纳的文件数目是由Namenode的内存大小来决定。通常来讲,每个文件文件夹Block须要占据150字节左右的空间,因此,若是你有100万个文件,每个占据一个Block,你就至少须要300MB内存。当前来讲,数百万的文件仍是可行的,当扩展到数十亿时,对于当前的硬件水平来讲就无法实现了。还有一个问题就是,由于Map task的数量是由splits来决定的,因此用MR处理大量的小文件时,就会产生过多的Maptask,线程管理开销将会增长做业时间。举个例子,处理10000M的文件,若每一个split为1M,那就会有10000个Maptasks,会有很大的线程开销;若每一个split为100M,则只有100个Maptasks,每一个Maptask将会有更多的事情作,而线程的管理开销也将减少不少。

  改进策略:要想让HDFS能处理好小文件,有很多方法。

  • 利用SequenceFile、MapFile、Har等方式归档小文件,这个方法的原理就是把小文件归档起来管理,HBase就是基于此的。对于这种方法,若是想找回原来的小文件内容,那就必须得知道与归档文件的映射关系。
  • 横向扩展,一个Hadoop集群能管理的小文件有限,那就把几个Hadoop集群拖在一个虚拟服务器后面,造成一个大的Hadoop集群。google也是这么干过的。
  • 多Master设计,这个做用显而易见了。正在研发中的GFS II也要改成分布式多Master设计,还支持Master的Failover,并且Block大小改成1M,有意要调优处理小文件啊。
  • 附带个Alibaba DFS的设计,也是多Master设计,它把Metadata的映射存储和管理分开了,由多个Metadata存储节点和一个查询Master节点组成。

  3)不支持多用户写入及任意修改文件

  在HDFS的一个文件中只有一个写入者,并且写操做只能在文件末尾完成,即只能执行追加操做。目前HDFS还不支持多个用户同一文件操做,以及在文件任意位置进行修改。

五、HDFS经常使用操做

  先说一下"hadoop fshadoop dfs的区别",看两本Hadoop书上各有用到,但效果同样,求证与网络发现下面一解释比较中肯。

  粗略的讲,fs是个比较抽象的层面,在分布式环境中,fs就是dfs,但在本地环境中,fs是local file system,这个时候dfs就不能用。

5.1 文件操做

  1)列出HDFS文件

  此处为你展现如何经过"-ls"命令列出HDFS下的文件:

 

hadoop fs -ls

 

  执行结果如图5-1-1所示。在这里须要注意:在HDFS中未带参数的"-ls"命名没有返回任何值,它默认返回HDFS的"home"目录下的内容。在HDFS中,当前目录这样一个概念,也cd这个命令。

 

  

图5-1-1 列出HDFS文件

  2)列出HDFS目录下某个文档中的文件

  此处为你展现如何经过"-ls 文件名"命令浏览HDFS下名为"input"的文档中文件:

 

hadoop fs –ls input

 

  执行结果如图5-1-2所示。

 

  

图5-1-2 列出HDFS下名为input的文档下的文件

  3)上传文件到HDFS

  此处为你展现如何经过"-put 文件1 文件2"命令将"Master.Hadoop"机器下的"/home/hadoop"目录下的file文件上传到HDFS上并重命名test

 

hadoop fs –put ~/file test

 

  执行结果如图5-1-3所示。在执行"-put"时两种可能,便是执行成功执行失败。在上传文件时,文件首先复制到DataNode上。只有全部的DataNode都成功接收完数据,文件上传才是成功的。其余状况(如文件上传终端等)对HDFS来讲都是作了无用功。

 

  

图5-1-3 成功上传file到HDFS

  4)将HDFS中文件复制本地系统

  此处为你展现如何经过"-get 文件1 文件2"命令将HDFS中的"output"文件复制到本地系统并命名为"getout"。

 

hadoop fs –get output getout

 

  执行结果如图5-1-4所示。

 

  

图5-1-4 成功将HDFS中output文件复制到本地系统

  备注:与"-put"命令同样,"-get"操做既能够操做文件,也能够操做目录

  5)删除HDFS下的文档

  此处为你展现如何经过"-rmr 文件"命令删除HDFS下名为"newoutput"的文档:

 

hadoop fs –rmr newoutput

 

  执行结果如图5-1-5所示。

 

  

图5-1-5 成功删除HDFS下的newoutput文档

  6)查看HDFS下某个文件

  此处为你展现如何经过"-cat 文件"命令查看HDFS下input文件中内容:

 

hadoop fs -cat input/*

 

  执行结果如图5-1-6所示。

 

  

图5-1-6 HDFS下input文件的内容

  "hadoop fs"的命令远不止这些,本小节介绍的命令已能够在HDFS上完成大多数常规操做。对于其余操做,能够经过"-help commandName"命令所列出的清单来进一步学习与探索。

5.2 管理与更新

  1)报告HDFS的基本统计状况

  此处为你展现经过"-report"命令如何查看HDFS的基本统计信息:

 

hadoop dfsadmin -report

 

  执行结果如图5-2-1所示。

 

  

图5-2-1 HDFS基本统计信息

  2)退出安全模式

  NameNode在启动时自动进入安全模式。安全模式是NameNode的一种状态,在这个阶段,文件系统不容许有任何修改。安全模式的目的是在系统启动时检查各个DataNode上数据块的有效性,同时根据策略对数据块进行必要的复制删除,当数据块最小百分比数知足的最小副本数条件时,会自动退出安全模式。

  系统显示"Name node is in safe mode",说明系统正处于安全模式,这时只须要等待17秒便可,也能够经过下面的命令退出安全模式:

 

hadoop dfsadmin –safemode enter

 

  成功退出安全模式结果如图5-2-2所示。

 

  

图5-2-2 成功退出安全模式

  3)进入安全模式

  在必要状况下,能够经过如下命令把HDFS置于安全模式:

 

hadoop dfsadmin –safemode enter

 

  执行结果如图5-2-3所示。

 

  

图5-2-3 进入HDFS安全模式

  4)添加节点

  可扩展性是HDFS的一个重要特性,向HDFS集群中添加节点是很容易实现的。添加一个新的DataNode节点,首先在新加节点上安装好Hadoop,要和NameNode使用相同的配置(能够直接从NameNode复制),修改"/usr/hadoop/conf/master"文件,加入NameNode主机名。而后在NameNode节点上修改"/usr/hadoop/conf/slaves"文件,加入新节点主机名,再创建到新加点无密码的SSH链接,运行启动命令:

 

start-all.sh

 

  5)负载均衡

  HDFS的数据在各个DataNode中的分布肯能很不均匀,尤为是在DataNode节点出现故障新增DataNode节点时。新增数据块时NameNode对DataNode节点的选择策略也有可能致使数据块分布的不均匀。用户能够使用命令从新平衡DataNode上的数据块的分布:

 

start-balancer.sh

 

  执行命令前,DataNode节点上数据分布状况如图5-2-4所示。

 

  

 

  负载均衡完毕后,DataNode节点上数据的分布状况如图5-2-5所示。

 

  

 

  执行负载均衡命令如图5-2-6所示。

 

  

 

六、HDFS API详解

  Hadoop中关于文件操做类基本上所有是在"org.apache.hadoop.fs"包中,这些API可以支持的操做包含:打开文件,读写文件,删除文件等。

Hadoop类库中最终面向用户提供的接口类FileSystem,该类是个抽象类,只能经过来类的get方法获得具体类。get方法存在几个重载版本,经常使用的是这个:

 

static FileSystem get(Configuration conf);

 

  该类封装了几乎全部的文件操做,例如mkdir,delete等。综上基本上能够得出操做文件的程序库框架:

 

operator()

{

    获得Configuration对象

    获得FileSystem对象

    进行文件操做

}

 

6.1 上传本地文件

  经过"FileSystem.copyFromLocalFile(Path src,Patch dst)"可将本地文件上传HDFS的制定位置上,其中src和dst均为文件的完整路径。具体事例以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileStatus;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class CopyFile {

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

       

        //本地文件

        Path src =new Path("D:\\HebutWinOS");

        //HDFS为止

        Path dst =new Path("/");

       

        hdfs.copyFromLocalFile(src, dst);

        System.out.println("Upload to"+conf.get("fs.default.name"));

       

        FileStatus files[]=hdfs.listStatus(dst);

        for(FileStatus file:files){

            System.out.println(file.getPath());

        }

    }

}

 

  运行结果能够经过控制台、项目浏览器和SecureCRT查看,如图6-1-一、图6-1-二、图6-1-3所示。

  1)控制台结果

 

  

图6-1-1 运行结果(1)

  2)项目浏览器

 

  

图6-1-2 运行结果(2)

  3)SecureCRT结果

 

  

图6-1-3 运行结果(3)

6.2 建立HDFS文件

  经过"FileSystem.create(Path f)"可在HDFS上建立文件,其中f为文件的完整路径。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FSDataOutputStream;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class CreateFile {

 

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

       

        byte[] buff="hello hadoop world!\n".getBytes();

       

        Path dfs=new Path("/test");

       

        FSDataOutputStream outputStream=hdfs.create(dfs);

        outputStream.write(buff,0,buff.length);

       

    }

}

 

  运行结果如图6-2-1和图6-2-2所示。

  1)项目浏览器

 

  

图6-2-1 运行结果(1)

  2)SecureCRT结果

 

  

图6-2-2 运行结果(2)

6.3 建立HDFS目录

  经过"FileSystem.mkdirs(Path f)"可在HDFS上建立文件夹,其中f为文件夹的完整路径。具体实现以下:

 

package com.hebut.dir;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class CreateDir {

 

    public static void main(String[] args) throws Exception{

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

       

        Path dfs=new Path("/TestDir");

       

        hdfs.mkdirs(dfs);

 

    }

}

 

  运行结果如图6-3-1和图6-3-2所示。

  1)项目浏览器

 

  

图6-3-1 运行结果(1)

  2)SecureCRT结果

 

  

图6-3-2 运行结果(2)

6.4 重命名HDFS文件

  经过"FileSystem.rename(Path src,Path dst)"可为指定的HDFS文件重命名,其中src和dst均为文件的完整路径。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class Rename{

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

     

        Path frpaht=new Path("/test");    //旧的文件名

        Path topath=new Path("/test1");    //新的文件名

       

        boolean isRename=hdfs.rename(frpaht, topath);

       

        String result=isRename?"成功":"失败";

        System.out.println("文件重命名结果为:"+result);

       

    }

}

 

  运行结果如图6-4-1和图6-4-2所示。

  1)项目浏览器

 

  

图6-4-1 运行结果(1)

    2)SecureCRT结果

 

  

图6-4-2 运行结果(2)

6.5 删除HDFS上的文件

  经过"FileSystem.delete(Path f,Boolean recursive)"可删除指定的HDFS文件,其中f为须要删除文件的完整路径,recuresive用来肯定是否进行递归删除。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class DeleteFile {

 

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

       

        Path delef=new Path("/test1");

       

        boolean isDeleted=hdfs.delete(delef,false);

        //递归删除

        //boolean isDeleted=hdfs.delete(delef,true);

        System.out.println("Delete?"+isDeleted);

    }

}

 

  运行结果如图6-5-1和图6-5-2所示。

  1)控制台结果

 

  

图6-5-1 运行结果(1)

    2)项目浏览器

  

图6-5-2 运行结果(2)

6.6 删除HDFS上的目录

  同删除文件代码同样,只是换成删除目录路径便可,若是目录下有文件,要进行递归删除。

6.7 查看某个HDFS文件是否存在

  经过"FileSystem.exists(Path f)"可查看指定HDFS文件是否存在,其中f为文件的完整路径。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class CheckFile {

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

        Path findf=new Path("/test1");

        boolean isExists=hdfs.exists(findf);

        System.out.println("Exist?"+isExists);

    }

}

 

  运行结果如图6-7-1和图6-7-2所示。

  1)控制台结果

 

  

图6-7-1 运行结果(1)

  2)项目浏览器

 

  

图6-7-2 运行结果(2)

6.8 查看HDFS文件的最后修改时间

  经过"FileSystem.getModificationTime()"可查看指定HDFS文件的修改时间。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileStatus;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class GetLTime {

 

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

       

        Path fpath =new Path("/user/hadoop/test/file1.txt");

       

        FileStatus fileStatus=hdfs.getFileStatus(fpath);

        long modiTime=fileStatus.getModificationTime();

       

        System.out.println("file1.txt的修改时间是"+modiTime);

    }

}

 

  运行结果如图6-8-1所示。

 

  

图6-8-1 控制台结果

6.9 读取HDFS某个目录下的全部文件

  经过"FileStatus.getPath()"可查看指定HDFS中某个目录下全部文件。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileStatus;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class ListAllFile {

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

       

        Path listf =new Path("/user/hadoop/test");

       

        FileStatus stats[]=hdfs.listStatus(listf);

        for(int i = 0; i < stats.length; ++i)

     {

       System.out.println(stats[i].getPath().toString());

     }

        hdfs.close();

    }

}

 

  运行结果如图6-9-1和图6-9-2所示。

  1)控制台结果

 

  

图6-9-1 运行结果(1)

 

  2)项目浏览器

 

  

图6-9-2 运行结果(2)

6.10 查找某个文件在HDFS集群的位置

  经过"FileSystem.getFileBlockLocation(FileStatus file,long start,long len)"可查找指定文件在HDFS集群上的位置,其中file为文件的完整路径,start和len来标识查找文件的路径。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.BlockLocation;

import org.apache.hadoop.fs.FileStatus;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.fs.Path;

 

public class FileLoc {

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem hdfs=FileSystem.get(conf);

        Path fpath=new Path("/user/hadoop/cygwin");

       

        FileStatus filestatus = hdfs.getFileStatus(fpath);

        BlockLocation[] blkLocations = hdfs.getFileBlockLocations(filestatus, 0, filestatus.getLen());

 

        int blockLen = blkLocations.length;

        for(int i=0;i<blockLen;i++){

            String[] hosts = blkLocations[i].getHosts();

            System.out.println("block_"+i+"_location:"+hosts[0]);

        }

    }

}

 

  运行结果如图6-10-1和6.10.2所示。

  1)控制台结果

 

  

图6-10-1 运行结果(1)

  2)项目浏览器

 

  

图6-10-2 运行结果(2)

6.11 获取HDFS集群上全部节点名称信息

  经过"DatanodeInfo.getHostName()"可获取HDFS集群上的全部节点名称。具体实现以下:

 

package com.hebut.file;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.FileSystem;

import org.apache.hadoop.hdfs.DistributedFileSystem;

import org.apache.hadoop.hdfs.protocol.DatanodeInfo;

 

public class GetList {

 

    public static void main(String[] args) throws Exception {

        Configuration conf=new Configuration();

        FileSystem fs=FileSystem.get(conf);

       

        DistributedFileSystem hdfs = (DistributedFileSystem)fs;

        DatanodeInfo[] dataNodeStats = hdfs.getDataNodeStats();

       

        for(int i=0;i<dataNodeStats.length;i++){

            System.out.println("DataNode_"+i+"_Name:"+dataNodeStats[i].getHostName());

        }

    }

}

 

  运行结果如图6-11-1所示。

 

  

图6-11-1 控制台结果

七、HDFS的读写数据流

7.1 文件的读取剖析

  

 

  文件读取的过程以下:

  1)解释一

  • 客户端(client)用FileSystem的open()函数打开文件。
  • DistributedFileSystem用RPC调用元数据节点,获得文件的数据块信息。
  • 对于每个数据块,元数据节点返回保存数据块的数据节点的地址。
  • DistributedFileSystem返回FSDataInputStream给客户端,用来读取数据。
  • 客户端调用stream的read()函数开始读取数据。
  • DFSInputStream链接保存此文件第一个数据块的最近的数据节点。
  • Data从数据节点读到客户端(client)。
  • 当此数据块读取完毕时,DFSInputStream关闭和此数据节点的链接,而后链接此文件下一个数据块的最近的数据节点。
  • 当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。
  • 在读取数据的过程当中,若是客户端在与数据节点通讯出现错误,则尝试链接包含此数据块的下一个数据节点。
  • 失败的数据节点将被记录,之后再也不链接。

  2)解释二

  • 使用HDFS提供的客户端开发库,向远程的Namenode发起RPC请求;
  • Namenode会视状况返回文件的部分或者所有block列表,对于每一个block,Namenode都会返回有该block拷贝的datanode地址;
  • 客户端开发库会选取离客户端最接近的datanode来读取block;
  • 读取完当前block的数据后,关闭与当前的datanode链接,并为读取下一个block寻找最佳的datanode;
  • 当读完列表的block后,且文件读取尚未结束,客户端开发库会继续向Namenode获取下一批的block列表。
  • 读取完一个block都会进行checksum验证,若是读取datanode时出现错误,客户端会通知Namenode,而后再从下一个拥有该block拷贝的datanode继续读。

7.2 文件的写入剖析

  

 

  写入文件的过程比读取较为复杂:

  1)解释一

  • 客户端调用create()来建立文件
  • DistributedFileSystem用RPC调用元数据节点,在文件系统的命名空间中建立一个新的文件。
  • 元数据节点首先肯定文件原来不存在,而且客户端有建立文件的权限,而后建立新文件。
  • DistributedFileSystem返回DFSOutputStream,客户端用于写数据。
  • 客户端开始写入数据,DFSOutputStream将数据分红块,写入data queue。
  • Data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。
  • Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。
  • DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。
  • 若是数据节点在写入的过程当中失败:
    • 关闭pipeline,将ack queue中的数据块放入data queue的开始。
    • 当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后可以察觉其数据块是过期的,会被删除。
    • 失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。
    • 元数据节点则被通知此数据块是复制块数不足,未来会再建立第三份备份。
  • 当客户端结束写入数据,则调用stream的close函数。此操做将全部的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。

  2)解释二

  • 使用HDFS提供的客户端开发库,向远程的Namenode发起RPC请求;
  • Namenode会检查要建立的文件是否已经存在,建立者是否有权限进行操做,成功则会为文件建立一个记录,不然会让客户端抛出异常;
  • 当客户端开始写入文件的时候,开发库会将文件切分红多个packets,并在内部以"data queue"的形式管理这些packets,并向Namenode申请新的blocks,获取用来存储replicas的合适的datanodes列表,列表的大小根据在Namenode中对replication的设置而定。
  • 开始以pipeline(管道)的形式将packet写入全部的replicas中。开发库把packet以流的方式写入第一个datanode,该datanode把该packet存储以后,再将其传递给在此pipeline中的下一个datanode,直到最后一个datanode,这种写数据的方式呈流水线的形式。
  • 最后一个datanode成功存储以后会返回一个ack packet,在pipeline里传递至客户端,在客户端的开发库内部维护着"ack queue",成功收到datanode返回的ack packet后会从"ack queue"移除相应的packet。
  • 若是传输过程当中,有某个datanode出现了故障,那么当前的pipeline会被关闭,出现故障的datanode会从当前的pipeline中移除,剩余的block会继续剩下的datanode中继续以pipeline的形式传输,同时Namenode会分配一个新的datanode,保持replicas设定的数量。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.8.rar


Hadoop集群(第9期)_MapReduce初级案例

一、数据去重

   "数据去重"主要是为了掌握和利用并行化思想来对数据进行有意义筛选统计大数据集上的数据种类个数从网站日志中计算访问地等这些看似庞杂的任务都会涉及数据去重。下面就进入这个实例的MapReduce程序设计。

1.1 实例描述

  对数据文件中的数据进行去重。数据文件中的每行都是一个数据。

  样例输入以下所示:

     1)file1:

 

2012-3-1 a

2012-3-2 b

2012-3-3 c

2012-3-4 d

2012-3-5 a

2012-3-6 b

2012-3-7 c

2012-3-3 c

 

     2)file2:

 

2012-3-1 b

2012-3-2 a

2012-3-3 b

2012-3-4 d

2012-3-5 a

2012-3-6 c

2012-3-7 d

2012-3-3 c

 

     样例输出以下所示:

 

2012-3-1 a

2012-3-1 b

2012-3-2 a

2012-3-2 b

2012-3-3 b

2012-3-3 c

2012-3-4 d

2012-3-5 a

2012-3-6 b

2012-3-6 c

2012-3-7 c

2012-3-7 d

 

1.2 设计思路

  数据去重最终目标是让原始数据出现次数超过一次数据输出文件出现一次咱们天然而然会想到将同一个数据的全部记录都交给一台reduce机器,不管这个数据出现多少次,只要在最终结果中输出一次就能够了。具体就是reduce的输入应该以数据做为key,而对value-list则没有要求。当reduce接收到一个<key,value-list>时就直接将key复制到输出的key中,并将value设置成空值

  在MapReduce流程中,map的输出<key,value>通过shuffle过程汇集成<key,value-list>后会交给reduce。因此从设计好的reduce输入能够反推出map的输出key应为数据,value任意。继续反推,map输出数据的key为数据,而在这个实例中每一个数据表明输入文件中的一行内容,因此map阶段要完成的任务就是在采用Hadoop默认的做业输入方式以后,将value设置为key,并直接输出(输出中的value任意)。map中的结果通过shuffle过程以后交给reduce。reduce阶段不会管每一个key有多少个value,它直接将输入的key复制为输出的key,并输出就能够了(输出中的value被设置成空了)。

1.3 程序代码

     程序代码以下所示:

 

package com.hebut.mr;

 

import java.io.IOException;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

 

public class Dedup {

 

    //map将输入中的value复制到输出数据的key上,并直接输出

    public static class Map extends Mapper<Object,Text,Text,Text>{

        private static Text line=new Text();//每行数据

       

        //实现map函数

        public void map(Object key,Text value,Context context)

                throws IOException,InterruptedException{

            line=value;

            context.write(line, new Text(""));

        }

       

    }

   

    //reduce将输入中的key复制到输出数据的key上,并直接输出

    public static class Reduce extends Reducer<Text,Text,Text,Text>{

        //实现reduce函数

        public void reduce(Text key,Iterable<Text> values,Context context)

                throws IOException,InterruptedException{

            context.write(key, new Text(""));

        }

       

    }

   

    public static void main(String[] args) throws Exception{

        Configuration conf = new Configuration();

        //这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

       

        String[] ioArgs=new String[]{"dedup_in","dedup_out"};

     String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();

     if (otherArgs.length != 2) {

     System.err.println("Usage: Data Deduplication <in> <out>");

     System.exit(2);

     }

     

     Job job = new Job(conf, "Data Deduplication");

     job.setJarByClass(Dedup.class);

     

     //设置MapCombineReduce处理类

     job.setMapperClass(Map.class);

     job.setCombinerClass(Reduce.class);

     job.setReducerClass(Reduce.class);

     

     //设置输出类型

     job.setOutputKeyClass(Text.class);

     job.setOutputValueClass(Text.class);

     

     //设置输入和输出目录

     FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

     FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

     System.exit(job.waitForCompletion(true) ? 0 : 1);

     }

}

 

1.4 代码结果

     1)准备测试数据

     经过Eclipse下面的"DFS Locations"在"/user/hadoop"目录下建立输入文件"dedup_in"文件夹(备注:"dedup_out"不须要建立。)如图1.4-1所示,已经成功建立。

        

图1.4-1 建立"dedup_in"                                   图1.4.2 上传"file*.txt"

 

     而后在本地创建两个txt文件,经过Eclipse上传到"/user/hadoop/dedup_in"文件夹中,两个txt文件的内容如"实例描述"那两个文件同样。如图1.4-2所示,成功上传以后。

     从SecureCRT远处查看"Master.Hadoop"的也能证明咱们上传的两个文件。

 

 

    查看两个文件的内容如图1.4-3所示:

 

图1.4-3 文件"file*.txt"内容

2)查看运行结果

     这时咱们右击Eclipse的"DFS Locations"中"/user/hadoop"文件夹进行刷新,这时会发现多出一个"dedup_out"文件夹,且里面有3个文件,而后打开双其"part-r-00000"文件,会在Eclipse中间把内容显示出来。如图1.4-4所示。

 

图1.4-4 运行结果

 

    此时,你能够对比一下和咱们以前预期的结果是否一致。

二、数据排序

  "数据排序"是许多实际任务执行时要完成的第一项工做,好比学生成绩评比数据创建索引等。这个实例和数据去重相似,都是原始数据进行初步处理,为进一步的数据操做打好基础。下面进入这个示例。

2.1 实例描述

    对输入文件中数据进行排序。输入文件中的每行内容均为一个数字即一个数据。要求在输出中每行有两个间隔的数字,其中,第一个表明原始数据在原始数据集中的位次第二个表明原始数据

    样例输入

    1)file1:

 

2

32

654

32

15

756

65223

 

    2)file2:

 

5956

22

650

92

 

    3)file3:

 

26

54

6

 

    样例输出

 

1    2

2    6

3    15

4    22

5    26

6    32

7    32

8    54

9    92

10    650

11    654

12    756

13    5956

14    65223

 

2.2 设计思路

  这个实例仅仅要求对输入数据进行排序,熟悉MapReduce过程的读者会很快想到在MapReduce过程当中就有排序,是否能够利用这个默认的排序,而不须要本身再实现具体的排序呢?答案是确定的。

  可是在使用以前首先须要了解它的默认排序规则。它是按照key值进行排序的,若是key为封装int的IntWritable类型,那么MapReduce按照数字大小对key排序,若是key为封装为String的Text类型,那么MapReduce按照字典顺序对字符串排序。

  了解了这个细节,咱们就知道应该使用封装int的IntWritable型数据结构了。也就是在map中将读入的数据转化成IntWritable型,而后做为key值输出(value任意)。reduce拿到<key,value-list>以后,将输入的key做为value输出,并根据value-list元素个数决定输出的次数。输出的key(即代码中的linenum)是一个全局变量,它统计当前key的位次。须要注意的是这个程序中没有配置Combiner,也就是在MapReduce过程当中不使用Combiner。这主要是由于使用map和reduce就已经可以完成任务了。

2.3 程序代码

    程序代码以下所示:

 

package com.hebut.mr;

 

import java.io.IOException;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

 

public class Sort {

 

    //map将输入中的value化成IntWritable类型,做为输出的key

    public static class Map extends

        Mapper<Object,Text,IntWritable,IntWritable>{

        private static IntWritable data=new IntWritable();

       

        //实现map函数

        public void map(Object key,Text value,Context context)

                throws IOException,InterruptedException{

            String line=value.toString();

            data.set(Integer.parseInt(line));

            context.write(data, new IntWritable(1));

        }

       

    }

   

    //reduce将输入中的key复制到输出数据的key上,

    //而后根据输入的value-list中元素的个数决定key的输出次数

    //用全局linenum来表明key的位次

    public static class Reduce extends

            Reducer<IntWritable,IntWritable,IntWritable,IntWritable>{

       

        private static IntWritable linenum = new IntWritable(1);

       

        //实现reduce函数

        public void reduce(IntWritable key,Iterable<IntWritable> values,Context context)

                throws IOException,InterruptedException{

            for(IntWritable val:values){

                context.write(linenum, key);

                linenum = new IntWritable(linenum.get()+1);

            }

           

        }

 

    }

   

    public static void main(String[] args) throws Exception{

        Configuration conf = new Configuration();

        //这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

       

        String[] ioArgs=new String[]{"sort_in","sort_out"};

     String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();

     if (otherArgs.length != 2) {

     System.err.println("Usage: Data Sort <in> <out>");

         System.exit(2);

     }

     

     Job job = new Job(conf, "Data Sort");

     job.setJarByClass(Sort.class);

     

     //设置MapReduce处理类

     job.setMapperClass(Map.class);

     job.setReducerClass(Reduce.class);

     

     //设置输出类型

     job.setOutputKeyClass(IntWritable.class);

     job.setOutputValueClass(IntWritable.class);

     

     //设置输入和输出目录

     FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

     FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

     System.exit(job.waitForCompletion(true) ? 0 : 1);

     }

}

 

2.4 代码结果

1)准备测试数据

    经过Eclipse下面的"DFS Locations"在"/user/hadoop"目录下建立输入文件"sort_in"文件夹(备注:"sort_out"不须要建立。)如图2.4-1所示,已经成功建立。

              

图2.4-1 建立"sort_in"                                                  图2.4.2 上传"file*.txt"

 

    而后在本地创建三个txt文件,经过Eclipse上传到"/user/hadoop/sort_in"文件夹中,三个txt文件的内容如"实例描述"那三个文件同样。如图2.4-2所示,成功上传以后。

    从SecureCRT远处查看"Master.Hadoop"的也能证明咱们上传的三个文件。

 

 

查看两个文件的内容如图2.4-3所示:

 

图2.4-3 文件"file*.txt"内容

2)查看运行结果

    这时咱们右击Eclipse的"DFS Locations"中"/user/hadoop"文件夹进行刷新,这时会发现多出一个"sort_out"文件夹,且里面有3个文件,而后打开双其"part-r-00000"文件,会在Eclipse中间把内容显示出来。如图2.4-4所示。

 

图2.4-4 运行结果

三、平均成绩

    "平均成绩"主要目的仍是在重温经典"WordCount"例子,能够说是在基础上的微变化版,该实例主要就是实现一个计算学平生均成绩的例子。

3.1 实例描述

  对输入文件中数据进行就算学平生均成绩。输入文件中的每行内容均为一个学生姓名和他相应的成绩,若是有多门学科,则每门学科为一个文件。要求在输出中每行有两个间隔的数据,其中,第一个表明学生的姓名第二个表明其平均成绩

    样本输入

    1)math:

 

张三    88

李四    99

王五    66

赵六    77

 

    2)china:

 

张三    78

李四    89

王五    96

赵六    67

 

    3)english:

 

张三    80

李四    82

王五    84

赵六    86

 

    样本输出

 

张三    82

李四    90

王五    82

赵六    76

 

3.2 设计思路

    计算学平生均成绩是一个仿"WordCount"例子,用来重温一下开发MapReduce程序的流程。程序包括两部分的内容:Map部分和Reduce部分,分别实现了map和reduce的功能。

    Map处理的是一个纯文本文件,文件中存放的数据时每一行表示一个学生的姓名和他相应一科成绩。Mapper处理的数据是由InputFormat分解过的数据集,其中InputFormat的做用是将数据集切割成小数据集InputSplit,每个InputSlit将由一个Mapper负责处理。此外,InputFormat中还提供了一个RecordReader的实现,并将一个InputSplit解析成<key,value>对提供给了map函数。InputFormat的默认值是TextInputFormat,它针对文本文件,按行将文本切割成InputSlit,并用LineRecordReader将InputSplit解析成<key,value>对,key是行在文本中的位置,value是文件中的一行。

    Map的结果会经过partion分发到Reducer,Reducer作完Reduce操做后,将经过以格式OutputFormat输出。

    Mapper最终处理的结果对<key,value>,会送到Reducer中进行合并,合并的时候,有相同key的键/值对则送到同一个Reducer上。Reducer是全部用户定制Reducer类地基础,它的输入是key和这个key对应的全部value的一个迭代器,同时还有Reducer的上下文。Reduce的结果由Reducer.Context的write方法输出到文件中。

3.3 程序代码

    程序代码以下所示:

 

package com.hebut.mr;

 

import java.io.IOException;

import java.util.Iterator;

import java.util.StringTokenizer;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

 

public class Score {

 

    public static class Map extends

            Mapper<LongWritable, Text, Text, IntWritable> {

 

        // 实现map函数

        public void map(LongWritable key, Text value, Context context)

                throws IOException, InterruptedException {

            // 将输入的纯文本文件的数据转化成String

            String line = value.toString();

 

            // 将输入的数据首先按行进行分割

            StringTokenizer tokenizerArticle = new StringTokenizer(line, "\n");

 

            // 分别对每一行进行处理

            while (tokenizerArticle.hasMoreElements()) {

                // 每行按空格划分

                StringTokenizer tokenizerLine = new StringTokenizer(tokenizerArticle.nextToken());

 

                String strName = tokenizerLine.nextToken();// 学生姓名部分

                String strScore = tokenizerLine.nextToken();// 成绩部分

 

                Text name = new Text(strName);

                int scoreInt = Integer.parseInt(strScore);

                // 输出姓名和成绩

                context.write(name, new IntWritable(scoreInt));

            }

        }

 

    }

 

    public static class Reduce extends

            Reducer<Text, IntWritable, Text, IntWritable> {

        // 实现reduce函数

        public void reduce(Text key, Iterable<IntWritable> values,

                Context context) throws IOException, InterruptedException {

 

            int sum = 0;

            int count = 0;

 

            Iterator<IntWritable> iterator = values.iterator();

            while (iterator.hasNext()) {

                sum += iterator.next().get();// 计算总分

                count++;// 统计总的科目数

            }

 

            int average = (int) sum / count;// 计算平均成绩

            context.write(key, new IntWritable(average));

        }

 

    }

 

    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();

        // 这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

 

        String[] ioArgs = new String[] { "score_in", "score_out" };

        String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();

        if (otherArgs.length != 2) {

            System.err.println("Usage: Score Average <in> <out>");

            System.exit(2);

        }

 

        Job job = new Job(conf, "Score Average");

        job.setJarByClass(Score.class);

 

        // 设置MapCombineReduce处理类

        job.setMapperClass(Map.class);

        job.setCombinerClass(Reduce.class);

        job.setReducerClass(Reduce.class);

 

        // 设置输出类型

        job.setOutputKeyClass(Text.class);

        job.setOutputValueClass(IntWritable.class);

 

        // 将输入的数据集分割成小数据块splites,提供一个RecordReder的实现

        job.setInputFormatClass(TextInputFormat.class);

        // 提供一个RecordWriter的实现,负责数据输出

        job.setOutputFormatClass(TextOutputFormat.class);

 

        // 设置输入和输出目录

        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);

    }

}

 

3.4 代码结果

1)准备测试数据

    经过Eclipse下面的"DFS Locations"在"/user/hadoop"目录下建立输入文件"score_in"文件夹(备注:"score_out"不须要建立。)如图3.4-1所示,已经成功建立。

 

            

图3.4-1 建立"score_in"                                                       图3.4.2 上传三门分数

 

    而后在本地创建三个txt文件,经过Eclipse上传到"/user/hadoop/score_in"文件夹中,三个txt文件的内容如"实例描述"那三个文件同样。如图3.4-2所示,成功上传以后。

    备注:文本文件的编码为"UTF-8",默认为"ANSI",能够另存为时选择,否则中文会出现乱码

    从SecureCRT远处查看"Master.Hadoop"的也能证明咱们上传的三个文件。

 

 

查看三个文件的内容如图3.4-3所示:

 

图3.4.3 三门成绩的内容

2)查看运行结果

    这时咱们右击Eclipse的"DFS Locations"中"/user/hadoop"文件夹进行刷新,这时会发现多出一个"score_out"文件夹,且里面有3个文件,而后打开双其"part-r-00000"文件,会在Eclipse中间把内容显示出来。如图3.4-4所示。

 

图3.4-4 运行结果

四、单表关联

    前面的实例都是在数据上进行一些简单的处理,为进一步的操做打基础。"单表关联"这个实例要求给出的数据寻找关心的数据,它是对原始数据所包含信息的挖掘。下面进入这个实例。

4.1 实例描述

    实例中给出child-parent(孩子——父母)表,要求输出grandchild-grandparent(孙子——爷奶)表。

    样例输入以下所示。

    file:

 

child        parent

Tom        Lucy

Tom        Jack

Jone        Lucy

Jone        Jack

Lucy        Mary

Lucy        Ben

Jack        Alice

Jack        Jesse

Terry        Alice

Terry        Jesse

Philip        Terry

Philip        Alma

Mark        Terry

Mark        Alma

 

    家族树状关系谱:

 

 image

图4.2-1 家族谱

    样例输出以下所示。

    file:

 

grandchild        grandparent

Tom              Alice

Tom              Jesse

Jone              Alice

Jone              Jesse

Tom              Mary

Tom              Ben

Jone              Mary

Jone              Ben

Philip              Alice

Philip              Jesse

Mark              Alice

Mark              Jesse

 

4.2 设计思路

       分析这个实例,显然须要进行单表链接,链接的是左表parent列和右表child列,且左表右表同一个表

  链接结果除去链接的两列就是所须要的结果——"grandchild--grandparent"表。要用MapReduce解决这个实例,首先应该考虑如何实现自链接其次就是链接列设置最后结果整理

      考虑到MapReduce的shuffle过程会将相同的key会链接在一块儿,因此能够将map结果的key设置成待链接,而后列中相同的值就天然会链接在一块儿了。再与最开始的分析联系起来:

  要链接的是左表的parent列和右表的child列,且左表和右表是同一个表,因此在map阶段读入数据分割childparent以后,会将parent设置成keychild设置成value进行输出,并做为左表再将同一对childparent中的child设置成keyparent设置成value进行输出,做为右表。为了区分输出中的左右表,须要在输出的value加上左右表信息,好比在value的String最开始处加上字符1表示左表,加上字符2表示右表。这样在map的结果中就造成了左表和右表,而后在shuffle过程当中完成链接。reduce接收到链接的结果,其中每一个key的value-list就包含了"grandchild--grandparent"关系。取出每一个key的value-list进行解析,将左表中的child放入一个数组右表中的parent放入一个数组,而后对两个数组求笛卡尔积就是最后的结果了。

4.3 程序代码

    程序代码以下所示。

 

package com.hebut.mr;

 

import java.io.IOException;

import java.util.*;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

 

public class STjoin {

 

    public static int time = 0;

 

    /*

     * map将输出分割childparent,而后正序输出一次做为右表,

     * 反序输出一次做为左表,须要注意的是在输出的value中必须

     * 加上左右表的区别标识。

     */

    public static class Map extends Mapper<Object, Text, Text, Text> {

 

        // 实现map函数

        public void map(Object key, Text value, Context context)

                throws IOException, InterruptedException {

            String childname = new String();// 孩子名称

            String parentname = new String();// 父母名称

            String relationtype = new String();// 左右表标识

 

            // 输入的一行预处理文本

            StringTokenizer itr=new StringTokenizer(value.toString());

            String[] values=new String[2];

            int i=0;

            while(itr.hasMoreTokens()){

                values[i]=itr.nextToken();

                i++;

            }

           

            if (values[0].compareTo("child") != 0) {

                childname = values[0];

                parentname = values[1];

 

                // 输出左表

                relationtype = "1";

                context.write(new Text(values[1]), new Text(relationtype +

                        "+"+ childname + "+" + parentname));

 

                // 输出右表

                relationtype = "2";

                context.write(new Text(values[0]), new Text(relationtype +

                        "+"+ childname + "+" + parentname));

            }

        }

 

    }

 

    public static class Reduce extends Reducer<Text, Text, Text, Text> {

 

        // 实现reduce函数

        public void reduce(Text key, Iterable<Text> values, Context context)

                throws IOException, InterruptedException {

 

            // 输出表头

            if (0 == time) {

                context.write(new Text("grandchild"), new Text("grandparent"));

                time++;

            }

 

            int grandchildnum = 0;

            String[] grandchild = new String[10];

            int grandparentnum = 0;

            String[] grandparent = new String[10];

 

            Iterator ite = values.iterator();

            while (ite.hasNext()) {

                String record = ite.next().toString();

                int len = record.length();

                int i = 2;

                if (0 == len) {

                    continue;

                }

 

                // 取得左右表标识

                char relationtype = record.charAt(0);

                // 定义孩子和父母变量

                String childname = new String();

                String parentname = new String();

 

                // 获取value-listvaluechild

                while (record.charAt(i) != '+') {

                    childname += record.charAt(i);

                    i++;

                }

 

                i = i + 1;

 

                // 获取value-listvalueparent

                while (i < len) {

                    parentname += record.charAt(i);

                    i++;

                }

 

                // 左表,取出child放入grandchildren

                if ('1' == relationtype) {

                    grandchild[grandchildnum] = childname;

                    grandchildnum++;

                }

 

                // 右表,取出parent放入grandparent

                if ('2' == relationtype) {

                    grandparent[grandparentnum] = parentname;

                    grandparentnum++;

                }

            }

 

            // grandchildgrandparent数组求笛卡尔儿积

            if (0 != grandchildnum && 0 != grandparentnum) {

                for (int m = 0; m < grandchildnum; m++) {

                    for (int n = 0; n < grandparentnum; n++) {

                        // 输出结果

                        context.write(new Text(grandchild[m]), new Text(grandparent[n]));

                    }

                }

            }

        }

    }

 

    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();

        // 这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

 

        String[] ioArgs = new String[] { "STjoin_in", "STjoin_out" };

        String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();

        if (otherArgs.length != 2) {

            System.err.println("Usage: Single Table Join <in> <out>");

            System.exit(2);

        }

 

        Job job = new Job(conf, "Single Table Join");

        job.setJarByClass(STjoin.class);

 

        // 设置MapReduce处理类

        job.setMapperClass(Map.class);

        job.setReducerClass(Reduce.class);

 

        // 设置输出类型

        job.setOutputKeyClass(Text.class);

        job.setOutputValueClass(Text.class);

 

        // 设置输入和输出目录

        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);

    }

}

 

4.4 代码结果

1)准备测试数据

    经过Eclipse下面的"DFS Locations"在"/user/hadoop"目录下建立输入文件"STjoin_in"文件夹(备注:"STjoin_out"不须要建立。)如图4.4-1所示,已经成功建立。

 

                  

图4.4-1 建立"STjoin_in"                                       图4.4.2 上传"child-parent"表

 

    而后在本地创建一个txt文件,经过Eclipse上传到"/user/hadoop/STjoin_in"文件夹中,一个txt文件的内容如"实例描述"那个文件同样。如图4.4-2所示,成功上传以后。

    从SecureCRT远处查看"Master.Hadoop"的也能证明咱们上传的文件,显示其内容如图4.4-3所示:

 

图4.4-3 表"child-parent"内容

    2)运行详解

    (1)Map处理:

    map函数输出结果以下所示。

 

child        parent                àà                    忽略此行

Tom        Lucy                   àà                <Lucy,1+Tom+Lucy>

                                                    <Tom,2+Tom+Lucy >

Tom        Jack                    àà                <Jack,1+Tom+Jack>

                                                    <Tom,2+Tom+Jack>

Jone        Lucy                 àà                <Lucy,1+Jone+Lucy>

                                                    <Jone,2+Jone+Lucy>

Jone        Jack                    àà                <Jack,1+Jone+Jack>

                                                    <Jone,2+Jone+Jack>

Lucy        Mary                   àà                <Mary,1+Lucy+Mary>

                                                    <Lucy,2+Lucy+Mary>

Lucy        Ben                    àà                <Ben,1+Lucy+Ben>

                                                     <Lucy,2+Lucy+Ben>

Jack        Alice                    àà                <Alice,1+Jack+Alice>

                                                      <Jack,2+Jack+Alice>

Jack        Jesse                   àà                <Jesse,1+Jack+Jesse>

                                                      <Jack,2+Jack+Jesse>

Terry        Alice                   àà                <Alice,1+Terry+Alice>

                                                      <Terry,2+Terry+Alice>

Terry        Jesse                  àà                <Jesse,1+Terry+Jesse>

                                                      <Terry,2+Terry+Jesse>

Philip        Terry                  àà                <Terry,1+Philip+Terry>

                                                      <Philip,2+Philip+Terry>

Philip        Alma                   àà                <Alma,1+Philip+Alma>

                                                      <Philip,2+Philip+Alma>

Mark        Terry                   àà                <Terry,1+Mark+Terry>

                                                      <Mark,2+Mark+Terry>

Mark        Alma                 àà                <Alma,1+Mark+Alma>

                                                      <Mark,2+Mark+Alma>

 

    (2)Shuffle处理

    在shuffle过程当中完成链接。

 

map函数输出

排序结果

shuffle链接

<Lucy1+Tom+Lucy>

<Tom2+Tom+Lucy>

<Jack1+Tom+Jack>

<Tom2+Tom+Jack>

<Lucy1+Jone+Lucy>

<Jone2+Jone+Lucy>

<Jack1+Jone+Jack>

<Jone2+Jone+Jack>

<Mary1+Lucy+Mary>

<Lucy2+Lucy+Mary>

<Ben1+Lucy+Ben>

<Lucy2+Lucy+Ben>

<Alice1+Jack+Alice>

<Jack2+Jack+Alice>

<Jesse1+Jack+Jesse>

<Jack2+Jack+Jesse>

<Alice1+Terry+Alice>

<Terry2+Terry+Alice>

<Jesse1+Terry+Jesse>

<Terry2+Terry+Jesse>

<Terry1+Philip+Terry>

<Philip2+Philip+Terry>

<Alma1+Philip+Alma>

<Philip2+Philip+Alma>

<Terry1+Mark+Terry>

<Mark2+Mark+Terry>

<Alma1+Mark+Alma>

<Mark2+Mark+Alma>

<Alice1+Jack+Alice>

<Alice1+Terry+Alice>

<Alma1+Philip+Alma>

<Alma1+Mark+Alma>

<Ben1+Lucy+Ben>

<Jack1+Tom+Jack>

<Jack1+Jone+Jack>

<Jack2+Jack+Alice>

<Jack2+Jack+Jesse>

<Jesse1+Jack+Jesse>

<Jesse1+Terry+Jesse>

<Jone2+Jone+Lucy>

<Jone2+Jone+Jack>

<Lucy1+Tom+Lucy>

<Lucy1+Jone+Lucy>

<Lucy2+Lucy+Mary>

<Lucy2+Lucy+Ben>

<Mary1+Lucy+Mary>

<Mark2+Mark+Terry>

<Mark2+Mark+Alma>

<Philip2+Philip+Terry>

<Philip2+Philip+Alma>

<Terry2+Terry+Alice>

<Terry2+Terry+Jesse>

<Terry1+Philip+Terry>

<Terry1+Mark+Terry>

<Tom2+Tom+Lucy>

<Tom2+Tom+Jack>

<Alice1+Jack+Alice

        1+Terry+Alice

        1+Philip+Alma

        1+Mark+Alma >

<Ben1+Lucy+Ben>

<Jack1+Tom+Jack

        1+Jone+Jack

        2+Jack+Alice

        2+Jack+Jesse >

<Jesse1+Jack+Jesse

        1+Terry+Jesse >

<Jone2+Jone+Lucy

        2+Jone+Jack>

<Lucy1+Tom+Lucy

        1+Jone+Lucy

        2+Lucy+Mary

        2+Lucy+Ben>

<Mary1+Lucy+Mary

        2+Mark+Terry

        2+Mark+Alma>

<Philip2+Philip+Terry

        2+Philip+Alma>

<Terry2+Terry+Alice

        2+Terry+Jesse

        1+Philip+Terry

        1+Mark+Terry>

<Tom2+Tom+Lucy

        2+Tom+Jack>

 

    (3)Reduce处理

    首先由语句"0 != grandchildnum && 0 != grandparentnum"得知,只要在"value-list"中没有左表或者右表,则不会作处理,能够根据这条规则去除无效shuffle链接

 

无效shuffle链接

有效shuffle链接

<Alice1+Jack+Alice

        1+Terry+Alice

        1+Philip+Alma

        1+Mark+Alma >

<Ben1+Lucy+Ben>

<Jesse1+Jack+Jesse

        1+Terry+Jesse >

<Jone2+Jone+Lucy

        2+Jone+Jack>

<Mary1+Lucy+Mary

        2+Mark+Terry

        2+Mark+Alma>

<Philip2+Philip+Terry

        2+Philip+Alma>

<Tom2+Tom+Lucy

        2+Tom+Jack>

<Jack1+Tom+Jack

        1+Jone+Jack

        2+Jack+Alice

        2+Jack+Jesse >

<Lucy1+Tom+Lucy

        1+Jone+Lucy

        2+Lucy+Mary

        2+Lucy+Ben>

<Terry2+Terry+Alice

        2+Terry+Jesse

        1+Philip+Terry

        1+Mark+Terry>

    而后根据下面语句进一步对有效的shuffle链接作处理。

 

// 左表,取出child放入grandchildren

if ('1' == relationtype) {

    grandchild[grandchildnum] = childname;

    grandchildnum++;

}

 

// 右表,取出parent放入grandparent

if ('2' == relationtype) {

    grandparent[grandparentnum] = parentname;

    grandparentnum++;

}

 

    针对一条数据进行分析:

 

<Jack,1+Tom+Jack,

        1+Jone+Jack,

        2+Jack+Alice,

        2+Jack+Jesse >

 

    分析结果左表用"字符1"表示,右表用"字符2"表示,上面的<key,value-list>中的"key"表示左表与右表链接键。而"value-list"表示以"key"链接左表与右表相关数据

    根据上面针对左表与右表不一样的处理规则,取得两个数组的数据以下所示:

 

grandchild

TomJonegrandchild[grandchildnum] = childname;

grandparent

AliceJessegrandparent[grandparentnum] = parentname;

    

    而后根据下面语句进行处理。

 

for (int m = 0; m < grandchildnum; m++) {

    for (int n = 0; n < grandparentnum; n++) {

        context.write(new Text(grandchild[m]), new Text(grandparent[n]));

    }

}

 

image  

 

处理结果以下面所示:

 

Tom        Jesse

Tom        Alice

Jone        Jesse

Jone        Alice 

    其余的有效shuffle链接处理都是如此

3)查看运行结果

    这时咱们右击Eclipse的"DFS Locations"中"/user/hadoop"文件夹进行刷新,这时会发现多出一个"STjoin_out"文件夹,且里面有3个文件,而后打开双其"part-r-00000"文件,会在Eclipse中间把内容显示出来。如图4.4-4所示。

 

图4.4-4 运行结果

五、多表关联

    多表关联和单表关联相似,它也是经过对原始数据进行必定的处理,从其中挖掘出关心的信息。下面进入这个实例。

5.1 实例描述

    输入是两个文件,一个表明工厂表,包含工厂名列和地址编号列;另外一个表明地址表,包含地址名列和地址编号列。要求从输入数据中找出工厂名地址名对应关系,输出"工厂名——地址名"表。

    样例输入以下所示。

    1)factory:

 

factoryname                    addressed

Beijing Red Star                    1

Shenzhen Thunder                3

Guangzhou Honda                2

Beijing Rising                       1

Guangzhou Development Bank      2

Tencent                        3

Back of Beijing                     1

 

    2)address:

 

addressID    addressname

1            Beijing

2            Guangzhou

3            Shenzhen

4            Xian

 

    样例输出以下所示。

 

factoryname                        addressname

Back of Beijing                          Beijing

Beijing Red Star                        Beijing

Beijing Rising                          Beijing

Guangzhou Development Bank          Guangzhou

Guangzhou Honda                    Guangzhou

Shenzhen Thunder                    Shenzhen

Tencent                            Shenzhen

 

5.2 设计思路

    多表关联和单表关联类似,都相似于数据库中的天然链接。相比单表关联,多表关联的左右表和链接列更加清楚。因此能够采用和单表关联的相同处理方式,map识别出输入的行属于哪一个表以后,对其进行分割,将链接的列值保存在key中,另外一列和左右表标识保存在value中,而后输出。reduce拿到链接结果以后,解析value内容,根据标志将左右表内容分开存放,而后求笛卡尔积,最后直接输出。

    这个实例的具体分析参考单表关联实例。下面给出代码。

5.3 程序代码

    程序代码以下所示:

 

package com.hebut.mr;

 

import java.io.IOException;

import java.util.*;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

 

public class MTjoin {

 

    public static int time = 0;

 

    /*

     * map中先区分输入行属于左表仍是右表,而后对两列值进行分割,

     * 保存链接列在key值,剩余列和左右表标志在value中,最后输出

     */

    public static class Map extends Mapper<Object, Text, Text, Text> {

 

        // 实现map函数

        public void map(Object key, Text value, Context context)

                throws IOException, InterruptedException {

            String line = value.toString();// 每行文件

            String relationtype = new String();// 左右表标识

 

            // 输入文件首行,不处理

            if (line.contains("factoryname") == true

                    || line.contains("addressed") == true) {

                return;

            }

 

            // 输入的一行预处理文本

            StringTokenizer itr = new StringTokenizer(line);

            String mapkey = new String();

            String mapvalue = new String();

            int i = 0;

            while (itr.hasMoreTokens()) {

                // 先读取一个单词

                String token = itr.nextToken();

                // 判断该地址ID就把存到"values[0]"

                if (token.charAt(0) >= '0' && token.charAt(0) <= '9') {

                    mapkey = token;

                    if (i > 0) {

                        relationtype = "1";

                    } else {

                        relationtype = "2";

                    }

                    continue;

                }

 

                // 存工厂名

                mapvalue += token + " ";

                i++;

            }

 

            // 输出左右表

            context.write(new Text(mapkey), new Text(relationtype + "+"+ mapvalue));

        }

    }

 

    /*

     * reduce解析map输出,将value中数据按照左右表分别保存,

  * 而后求出笛卡尔积,并输出。

     */

    public static class Reduce extends Reducer<Text, Text, Text, Text> {

 

        // 实现reduce函数

        public void reduce(Text key, Iterable<Text> values, Context context)

                throws IOException, InterruptedException {

 

            // 输出表头

            if (0 == time) {

                context.write(new Text("factoryname"), new Text("addressname"));

                time++;

            }

 

            int factorynum = 0;

            String[] factory = new String[10];

            int addressnum = 0;

            String[] address = new String[10];

 

            Iterator ite = values.iterator();

            while (ite.hasNext()) {

                String record = ite.next().toString();

                int len = record.length();

                int i = 2;

                if (0 == len) {

                    continue;

                }

 

                // 取得左右表标识

                char relationtype = record.charAt(0);

 

                // 左表

                if ('1' == relationtype) {

                    factory[factorynum] = record.substring(i);

                    factorynum++;

                }

 

                // 右表

                if ('2' == relationtype) {

                    address[addressnum] = record.substring(i);

                    addressnum++;

                }

            }

 

            // 求笛卡尔积

            if (0 != factorynum && 0 != addressnum) {

                for (int m = 0; m < factorynum; m++) {

                    for (int n = 0; n < addressnum; n++) {

                        // 输出结果

                        context.write(new Text(factory[m]),

                                new Text(address[n]));

                    }

                }

            }

 

        }

    }

 

    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();

        // 这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

 

        String[] ioArgs = new String[] { "MTjoin_in", "MTjoin_out" };

        String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();

        if (otherArgs.length != 2) {

            System.err.println("Usage: Multiple Table Join <in> <out>");

            System.exit(2);

        }

 

        Job job = new Job(conf, "Multiple Table Join");

        job.setJarByClass(MTjoin.class);

 

        // 设置MapReduce处理类

        job.setMapperClass(Map.class);

        job.setReducerClass(Reduce.class);

 

        // 设置输出类型

        job.setOutputKeyClass(Text.class);

        job.setOutputValueClass(Text.class);

 

        // 设置输入和输出目录

        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);

    }

}

 

5.4 代码结果

1)准备测试数据

    经过Eclipse下面的"DFS Locations"在"/user/hadoop"目录下建立输入文件"MTjoin_in"文件夹(备注:"MTjoin_out"不须要建立。)如图5.4-1所示,已经成功建立。

 

                 

图5.4-1 建立"MTjoin_in"                                                             图5.4.2 上传两个数据表

 

    而后在本地创建两个txt文件,经过Eclipse上传到"/user/hadoop/MTjoin_in"文件夹中,两个txt文件的内容如"实例描述"那两个文件同样。如图5.4-2所示,成功上传以后。

    从SecureCRT远处查看"Master.Hadoop"的也能证明咱们上传的两个文件。

 

图5.4.3 两个数据表的内容

2)查看运行结果

    这时咱们右击Eclipse的"DFS Locations"中"/user/hadoop"文件夹进行刷新,这时会发现多出一个"MTjoin_out"文件夹,且里面有3个文件,而后打开双其"part-r-00000"文件,会在Eclipse中间把内容显示出来。如图5.4-4所示。

 

图5.4-4 运行结果

六、倒排索引

    "倒排索引"是文档检索系统最经常使用数据结构,被普遍地应用于全文搜索引擎。它主要是用来存储某个单词(或词组)一个文档或一组文档中的存储位置映射,即提供了一种根据内容来查找文档方式。因为不是根据文档来肯定文档所包含的内容,而是进行相反的操做,于是称为倒排索引(Inverted Index)。

6.1 实例描述

    一般状况下,倒排索引由一个单词(或词组)以及相关的文档列表组成,文档列表中的文档或者是标识文档的ID号,或者是指文档所在位置的URL,如图6.1-1所示。

 image

图6.1-1 倒排索引结构

    从图6.1-1能够看出,单词1出如今{文档1,文档4,文档13,……}中,单词2出如今{文档3,文档5,文档15,……}中,而单词3出如今{文档1,文档8,文档20,……}中。在实际应用中,还须要每一个文档添加一个权值,用来指出每一个文档与搜索内容的相关度,如图6.1-2所示。

 

 image

图6.1-2 添加权重的倒排索引

    最经常使用的是使用词频做为权重,即记录单词在文档中出现的次数。以英文为例,如图6.1-3所示,索引文件中的"MapReduce"一行表示:"MapReduce"这个单词在文本T0中出现过1次,T1中出现过1次,T2中出现过2次。当搜索条件为"MapReduce"、"is"、"Simple"时,对应的集合为:{T0,T1,T2}∩{T0,T1}∩{T0,T1}={T0,T1},即文档T0和T1包含了所要索引的单词,并且只有T0是连续的。

 

 image

图6.1-3 倒排索引示例

    更复杂的权重还可能要记录单词在多少个文档中出现过,以实现TF-IDF(Term Frequency-Inverse Document Frequency)算法,或者考虑单词在文档中的位置信息(单词是否出如今标题中,反映了单词在文档中的重要性)等。

    样例输入以下所示。

    1)file1:

 

MapReduce is simple

 

    2)file2:

 

MapReduce is powerful is simple

 

    3)file3:

 

Hello MapReduce bye MapReduce

 

    样例输出以下所示。

 

MapReduce      file1.txt:1;file2.txt:1;file3.txt:2;

is            file1.txt:1;file2.txt:2;

simple           file1.txt:1;file2.txt:1;

powerful      file2.txt:1;

Hello          file3.txt:1;

bye            file3.txt:1;

 

6.2 设计思路

    实现"倒排索引"只要关注的信息为:单词文档URL词频,如图3-11所示。可是在实现过程当中,索引文件的格式与图6.1-3会略有所不一样,以免重写OutPutFormat类。下面根据MapReduce的处理过程给出倒排索引设计思路

    1)Map过程

    首先使用默认的TextInputFormat类对输入文件进行处理,获得文本中每行偏移量及其内容。显然,Map过程首先必须分析输入的<key,value>对,获得倒排索引中须要的三个信息:单词、文档URL和词频,如图6.2-1所示。

 image

图6.2-1 Map过程输入/输出

 

  这里存在两个问题第一,<key,value>对只能有两个值,在不使用Hadoop自定义数据类型的状况下,须要根据状况将其中两个值合并成一个值,做为key或value值;第二,经过一个Reduce过程没法同时完成词频统计生成文档列表,因此必须增长一个Combine过程完成词频统计

    这里讲单词和URL组成key值(如"MapReduce:file1.txt"),将词频做为value,这样作的好处是能够利用MapReduce框架自带的Map端排序,将同一文档相同单词词频组成列表,传递给Combine过程,实现相似于WordCount的功能。

    2)Combine过程

    通过map方法处理后,Combine过程将key值相同的value值累加,获得一个单词在文档在文档中的词频,如图6.2-2所示。若是直接将图6.2-2所示的输出做为Reduce过程的输入,在Shuffle过程时将面临一个问题:全部具备相同单词的记录(由单词、URL和词频组成)应该交由同一个Reducer处理,但当前的key值没法保证这一点,因此必须修改key值和value值。此次将单词做为key值,URL和词频组value值(如"file1.txt:1")。这样作的好处是能够利用MapReduce框架默认的HashPartitioner类完成Shuffle过程,将相同单词全部记录发送给同一个Reducer进行处理

 

 image

图6.2-2 Combine过程输入/输出

    3)Reduce过程

    通过上述两个过程后,Reduce过程只需将相同key值的value值组合成倒排索引文件所需的格式便可,剩下的事情就能够直接交给MapReduce框架进行处理了。如图6.2-3所示。索引文件的内容除分隔符外与图6.1-3解释相同。

    4)须要解决的问题

    本实例设计的倒排索引在文件数目没有限制,可是单词文件不宜过大(具体值与默认HDFS块大小及相关配置有关),要保证每一个文件对应一个split。不然,因为Reduce过程没有进一步统计词频,最终结可能出现词频未统计彻底单词。能够经过重写InputFormat类将每一个文件为一个split,避免上述状况。或者执行两次MapReduce第一次MapReduce用于统计词频第二次MapReduce用于生成倒排索引。除此以外,还能够利用复合键值对等实现包含更多信息的倒排索引。

 

 image

图6.2-3 Reduce过程输入/输出

6.3 程序代码

  程序代码以下所示:

 

package com.hebut.mr;

 

import java.io.IOException;

import java.util.StringTokenizer;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Job;

import org.apache.hadoop.mapreduce.Mapper;

import org.apache.hadoop.mapreduce.Reducer;

import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.input.FileSplit;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.GenericOptionsParser;

 

public class InvertedIndex {

 

    public static class Map extends Mapper<Object, Text, Text, Text> {

 

        private Text keyInfo = new Text(); // 存储单词和URL组合

        private Text valueInfo = new Text(); // 存储词频

        private FileSplit split; // 存储Split对象

 

        // 实现map函数

        public void map(Object key, Text value, Context context)

                throws IOException, InterruptedException {

 

            // 得到<key,value>对所属的FileSplit对象

            split = (FileSplit) context.getInputSplit();

 

            StringTokenizer itr = new StringTokenizer(value.toString());

 

            while (itr.hasMoreTokens()) {

                // key值由单词和URL组成,如"MapReducefile1.txt"

                // 获取文件的完整路径

                // keyInfo.set(itr.nextToken()+":"+split.getPath().toString());

                // 这里为了好看,只获取文件的名称。

                int splitIndex = split.getPath().toString().indexOf("file");

                keyInfo.set(itr.nextToken() + ":"

                    + split.getPath().toString().substring(splitIndex));

                // 词频初始化为1

                valueInfo.set("1");

 

                context.write(keyInfo, valueInfo);

            }

        }

    }

 

    public static class Combine extends Reducer<Text, Text, Text, Text> {

 

        private Text info = new Text();

 

        // 实现reduce函数

        public void reduce(Text key, Iterable<Text> values, Context context)

                throws IOException, InterruptedException {

 

            // 统计词频

            int sum = 0;

            for (Text value : values) {

                sum += Integer.parseInt(value.toString());

            }

 

            int splitIndex = key.toString().indexOf(":");

            // 从新设置value值由URL和词频组成

            info.set(key.toString().substring(splitIndex + 1) + ":" + sum);

            // 从新设置key值为单词

            key.set(key.toString().substring(0, splitIndex));

 

            context.write(key, info);

        }

    }

 

    public static class Reduce extends Reducer<Text, Text, Text, Text> {

 

        private Text result = new Text();

 

        // 实现reduce函数

        public void reduce(Text key, Iterable<Text> values, Context context)

                throws IOException, InterruptedException {

 

            // 生成文档列表

            String fileList = new String();

            for (Text value : values) {

                fileList += value.toString() + ";";

            }

 

            result.set(fileList);

 

            context.write(key, result);

        }

    }

 

    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();

        // 这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

 

        String[] ioArgs = new String[] { "index_in", "index_out" };

        String[] otherArgs = new GenericOptionsParser(conf, ioArgs)

                .getRemainingArgs();

        if (otherArgs.length != 2) {

            System.err.println("Usage: Inverted Index <in> <out>");

            System.exit(2);

        }

 

        Job job = new Job(conf, "Inverted Index");

        job.setJarByClass(InvertedIndex.class);

 

        // 设置MapCombineReduce处理类

        job.setMapperClass(Map.class);

        job.setCombinerClass(Combine.class);

        job.setReducerClass(Reduce.class);

 

        // 设置Map输出类型

        job.setMapOutputKeyClass(Text.class);

        job.setMapOutputValueClass(Text.class);

 

        // 设置Reduce输出类型

        job.setOutputKeyClass(Text.class);

        job.setOutputValueClass(Text.class);

 

        // 设置输入和输出目录

        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));

        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);

    }

}

 

6.4 代码结果

1)准备测试数据

    经过Eclipse下面的"DFS Locations"在"/user/hadoop"目录下建立输入文件"index_in"文件夹(备注:"index_out"不须要建立。)如图6.4-1所示,已经成功建立。

 

               

图6.4-1 建立"index_in"                                             图6.4.2 上传"file*.txt"

 

    而后在本地创建三个txt文件,经过Eclipse上传到"/user/hadoop/index_in"文件夹中,三个txt文件的内容如"实例描述"那三个文件同样。如图6.4-2所示,成功上传以后。

    从SecureCRT远处查看"Master.Hadoop"的也能证明咱们上传的三个文件。

 

图6.4.3 三个"file*.txt"的内容

2)查看运行结果

    这时咱们右击Eclipse的"DFS Locations"中"/user/hadoop"文件夹进行刷新,这时会发现多出一个"index_out"文件夹,且里面有3个文件,而后打开双其"part-r-00000"文件,会在Eclipse中间把内容显示出来。如图6.4-4所示。

 

图6.4-4 运行结果

 

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.9.rar

Hadoop集群(第10期)_MySQL关系数据库

一、MySQL安装

    MySQL下载地址:http://www.mysql.com/downloads/

1.1 Windows平台

  1)准备软件

  MySQL版本:mysql-5.5.21-win32.msi

  2)安装环境:

  操做系统:Windows 7旗舰版

  3)开始安装

  第一步:双击"msi"安装文件,出现如图1.1-1界面——"MySQL安装向导",按"Next"继续。

 

图1.1-1 MySQL安装向导

  第二步:在"I accept …."前面勾上,赞成协议,按"Next"按钮继续。

 

图1.1-2 软件协议

  第三步:选择安装类型,有"Typical(默认)"、"Custom(定制安装)"、"Complete(彻底)"三个选项。

  • 典型安装:安装只安装MySQL服务器、mysql命令行客户端和命令行实用程序。命令行客户端和实用程序包括mysqldump、myisamchk和其它几个工具来帮助你管理MySQL服务器。
  • 定制安装:安装容许你彻底控制你想要安装的软件包和安装路径。
  • 彻底安装:安装将安装软件包内包含的全部组件。彻底安装软件包包括的组件包括嵌入式服务器库、基准套件、支持脚本和文档。

  咱们选择"Custom",有更多的选项,也方便熟悉安装过程。

 

图1.1-3 安装类型

  第四步:选择组件及更改文件夹位置。

 

图1.1-4 自定义界面

  全部可用组件列入定制安装对话框左侧的树状视图内。未安装的组件用红色X 图标表示;已经安装的组件有灰色图标。要想更改组件,点击该组件的图标并从下拉列表中选择新的选项。组件选择了默认安装位置我会更改一下,点击Browse。

 

图1.1-5 路径选择

  按"OK"按钮返回,并按"Next"按钮继续。

  备注:安装mysql的路径中,不能含有中文

  第五步:确认一下先前的设置,若是有误,按"Back"返回重作。按"Install"开始安装。

 

图1.1-6 准备安装

  第六步:正在安装中,请稍候……

 

图1.1-7 正在安装

  第七步:弹出一个页面来,是关于介绍MySQL企业版的信息,没有什么可操做的,按"Next"按钮继续。

 

图1.1-8 MySQL企业版介绍

  而后弹出一个相似界面,接着按"Next"按钮继续。

  第八步:那个带复选框的是"MySQL服务器实例配置向导",保持默认勾选,按"Finish"按钮。至此,安装过程已经结束了,可是还须要配置一下。

 

图1.1-9 安装结束

  第九步:MySQL配置向导启动界面,按"Next"按钮继续。

 

图1.1-10 配置向导

  MySQL Configuration Wizard(配置向导)能够帮助自动配置Windows中的服务器。MySQL Configuration Wizard(配置向导)问你一系列问题,而后将回答放到模板中生成一个my.ini文件,该文件与你的安装一致。目前只适用于Windows用户。

  通常状况当MySQL安装帮助退出时,从MySQL安装帮助启动MySQL Configuration Wizard(配置向导)。还能够点击Windows启动菜单中MySQL服务器实例配置向导条目中的MySQL部分来启动MySQL Configuration Wizard(配置向导)。而且,还能够进入MySQL安装bin目录直接启动MySQLInstanceConfig.exe文件。

  第十步:选择配置类型,能够选择两种配置类型:Detailed Configuration(详细配置)和Standard Configuration(标准配置)。Standard Configuration(标准配置)选项适合想要快速启动MySQL而没必要考虑服务器配置的新用户。详细配置选项适合想要更加细粒度控制服务器配置的高级用户。咱们选择"Detailed Configuration",方便熟悉配置过程

 

图1.1-11 配置类型

  备注

  若是你是MySQL的新手,须要配置为单用户开发机的服务器,Standard Configuration(标准配置)应当适合你的需求。选择Standard Configuration(标准配置)选项,则 MySQL Configuration Wizard(配置向导)自动设置全部配置选项,但不包括服务选项和安全选项。

  Standard Configuration(标准配置)设置选项可能与安装MySQL的系统不兼容。若是系统上已经安装了MySQL和你想要配置的安装,建议选择详细配置。

  第十一步:选择服务器类型,能够选择3种服务器类型,选择哪一种服务器将影响到MySQL Configuration Wizard(配置向导)对内存、硬盘和过程或使用的决策。

 

  • Developer Machine(开发机器):该选项表明典型我的用桌面工做站。假定机器上运行着多个桌面应用程序。将MySQL服务器配置成使用最少的系统资源。

 

  • Server Machine(服务器):该选项表明服务器,MySQL服务器能够同其它应用程序一块儿运行,例如FTP、email和web服务器。MySQL服务器配置成使用适当比例的系统资源。

 

  • Dedicated MySQL Server Machine(专用MySQL服务器):该选项表明只运行MySQL服务的服务器。假定运行没有运行其它应用程序。MySQL服务器配置成使用全部可用系统资源。

 

你们根据本身的类型选择了,通常选"Server Machine",不会太少,也不会占满。咱们选择"Server Machine",按"Next"按钮继续。

 

图1.1-12 服务器类型

  第十二步:选择数据库用途,经过Database Usage(数据库使用)对话框,你能够指出建立MySQL表时使用的表处理器。经过该选项,你能够选择是否使用InnoDB储存引擎,以及InnoDB占用多大比例的服务器资源。"Multifunctional Database(通用多功能型,)"、"Transactional Database Only(服务器类型,专一于事务处理,通常)"、"Non-Transactional Database Only(非事务处理型,较简单,主要作一些监控、记数用,对MyISAM 数据类型的支持仅限于non-transactional)",随本身的用途而选择了,通常选择第一种多功能的。咱们选择"Multifunctional Database",按"Next"按钮继续。

 

图1.1-13 数据库用途

  第十三步:对InnoDB Tablespace 进行配置,就是为InnoDB 数据库文件选择一个存储空间,若是修改了,要记住位置,重装的时候要选择同样的地方,不然可能会形成数据库损坏,固然,对数据库作个备份就没问题了,这里不详述。这里没有修改,使用用默认位置,按"Next"按钮继续。

 

图1.1-14 配置InnoDB表空间

  第十四步:选择MySQL容许的最大链接数,限制所建立的与MySQL服务器之间的并行链接数量很重要,以便防止服务器耗尽资源。在Concurrent Connections(并行链接)对话框中,能够选择服务器的使用方法,并根据状况限制并行链接的数量。还能够手动设置并行链接的限制。第一种是最大20个链接并发数,第二种是最大500个并发链接数,最后一种是自定义。咱们选择"Online Transaction PRocessing(OLTP)",按"Next"按钮继续。

 

图1.1-15 最大链接数

  第十五步:进行网络配置,在Networking Options(网络选项)对话框中能够启用或禁用TCP/IP网络,并配置用来链接MySQL服务器的端口号。默认状况启用TCP/IP网络。要想禁用TCP/IP网络,取消选择Enable TCP/IP Networking选项旁边的检查框。默认使用3306端口。要想更访问MySQL使用的端口,从下拉框选择一个新端口号或直接向下拉框输入新的端口号。若是你选择的端口号已经被占用,将提示确认选择的端口号。咱们保持默认选项,按"Next"按钮继续。

 

图1.1-16 网络配置

  第十六步:对数据库语言编码进行设置,很是重要,由于Hadoop里默认编码为UTF-8,因此为了不出现乱码,咱们这里选择"UTF-8"做为MySQL数据库的语言编码。

 

图1.1-17 数据库编码

  第十七步:是否要把MySQL设置成Windows的服务,通常选择设成服务,这样之后就能够经过服务中启动和关闭mysql数据库了。推荐:下面的复选框也勾选上,这样,在cmd模式下,没必要非到mysql的bin目录下执行命令。咱们所有打上了勾Service Name 不变。按"Next"按钮继续。

 

图1.1-18 服务选项

  第十八步:设置MySQL的超级用户密码,这个超级用户很是重要,对MySQL拥有所有的权限,请设置好并牢记超级用户的密码,下面有个复选框是选择是否容许远程机器用root用户链接到你的MySQL服务器上面,若是有这个需求,也请勾选。咱们这里的root用户密码设置为"hadoop",并勾上"容许远程链接"复选框,按"Next"按钮继续。

 

图1.1-19 安全选项

  备注

  • "Enable root access from remote machines(是否容许root 用户在其它的机器上登录,若是要安全,就不要勾上,若是要方便,就勾上它)"。
  • "Create An Anonymous Account(新建一个匿名用户,匿名用户能够链接数据库,不能操做数据,包括查询)",通常就不用勾了。

  第十九步:确认设置无误,若是有误,按"Back"返回检查。若是没有,按"Execute"使设置生效。

 

图1.1-20 确认配置

  第二十步:设置完毕,按"Finish"按钮结束MySQL的安装与配置。

 

图1.1-21 配置完成

  备注:这里有一个比较常见的错误,就是不能"Start service",通常出如今之前有安装MySQL的服务器上,解决的办法,先保证之前安装的MySQL 服务器完全卸载掉了;不行的话,检查是否按上面一步所说,以前的密码是否有修改,照上面的操做;若是依然不行,将MySQL 安装目录下的data 文件夹备份,而后删除,在安装完成后,将安装生成的 data 文件夹删除,备份的data 文件夹移回来,再重启MySQL 服务就能够了,这种状况下,可能须要将数据库检查一下,而后修复一次,防止数据出错。

  4)验证成功

  第一种:打开任务管理器 看到MySQL服务是否已经启动。

 

图1.1-22 任务管理器

  第二种:"开始à启动cmdà开打cmd模式",输入"mysql –u root –p"链接数据库。

 

图1.1-23 链接数据库

1.2 Linux平台

  1)准备软件

  MySQL数据库:MySQL-server-5.5.21-1.linux2.6.i386.rpm

  MySQL客户端:MySQL-client-5.5.21-1.linux2.6.i386.rpm

  2)安装环境:

  操做系统:CentOS6.0 Linux

  3)检查安装

  在安装MySQL以前,先检查CentOS系统中是否已经安装了一个MySQL,若是已经安装先卸载,否则会致使安装的MySQL失败

  用下面命令查看系统以前是否已安装MySQL。

 

rpm -qa | grep mysql

 

  查看结果以下:

 

  

 

  从上图得知,CentOS6.0系统自带了一个MySQL,咱们须要删除这个老版本,用root用户执行下面语句。

 

rpm -e --nodeps mysql-libs-5.1.47-4.el6.i686

 

  

 

  上图中,咱们先切换到"root"用户下,而后执行删除语句,删除以后,咱们再次查看,发现已经成功删除了CentOS6.0自带的旧MySQL版本。

  在删除MySQL的rpm后,还要进行一些扫尾操做,网上有两种操做。(备注:我在这里两种都没有用到,发现系统中并无其余残余的MySQL信息。)

  第一种善后处理:使用下面命令进行处理。

 

rm -rf /var/lib/mysql*

rm -rf /usr/share/mysql*

 

  另外一种善后处理:卸载后/var/lib/mysql中的/etc/my.cnf会重命名为my.cnf.rpmsave,/var/log/mysqld.log 会重命名为/var/log/mysqld.log.rpmsave,若是肯定没用后就手工删除。

  4)开始安装

  第一步:上传所需软件。经过"FlashFXP"软件使用"vsftpd"上传用到的两个软件到"/home/hadoop"目录下。

 

  第二步:安装MySQL服务端。用"root"用户运行以下命令进行安装:(备注:如下步骤都是用"root"用户执行。)

 

rpm -ivh MySQL-server-5.5.21-1.linux2.6.i386.rpm

 

  经过SecureCRT查看以下:

 

  

  

  如出现如上信息,服务端安装完毕。

  第三步:检测MySQL 3306端口是否安打开。测试是否成功可运行netstat看MySQL端口是否打开,如打开表示服务已经启动,安装成功。MySQL默认的端口是3306。

 

netstat -nat

 

  

  从上图中发现并无与"3306"有关的信息,说明"MySQL服务器"没有启动。经过下面命令启动MySQL。

 

service mysql start

 

  

  从上图中已经发现咱们的MySQL服务器已经起来了。

  第四步:安装MySQL客户端。用下面命令进行安装:

 

rpm -ivh MySQL-client-5.5.21-1.linux2.6.i386.rpm

 

  执行命令显示以下:

  

  从上图中显示MySQL客户端已经安装完毕。

  第五步:MySQL的几个重要目录。MySQL安装完成后不像SQL Server默认安装在一个目录,它的数据库文件配置文件命令文件分别不一样目录,了解这些目录很是重要,尤为对于Linux的初学者,由于 Linux自己的目录结构就比较复杂,若是搞不清楚MySQL的安装目录那就无从谈起深刻学习。

  下面就介绍一下这几个目录。

 

a、数据库目录

/var/lib/mysql/

 

b、配置文件

/usr/share/mysql(mysql.server命令及配置文件)

 

c、相关命令

/usr/bin(mysqladmin mysqldump等命令)

 

d、启动脚本

/etc/rc.d/init.d/(启动脚本文件mysql的目录)

如:/etc/rc.d/init.d/mysql start/restart/stop/status

 

  下面就分别展现上面的几个目录内容:

  • 数据库目录

 

  

 

  • 配置文件

 

  

 

  • 相关命令

  

 

  • 启动脚本

 

  

 

  第六步:更改MySQL目录。因为MySQL数据库目录占用磁盘比较大,而MySQL默认的数据文件存储目录为/"var/lib/mysql",因此咱们要把目录移到"/"根目录下的"mysql_data"目录中。

  须要如下几个步骤:

  • "/"根目录下创建"mysql_data"目录

 

cd /

mkdir mysql_data

 

  

 

  • 把MySQL服务进程停掉

  能够用两种方法:

 

service mysql stop

 

  或者

 

mysqladmin -u root -p shutdown

 

  

  从上图中咱们得知"MySQL服务进程"已经停掉。

  备注MySQL默认用户名为"root",此处的"root"与Linux的最高权限用户"root"不是一下子,并且默认的用户"root"的密码为,因此上图中让输入密码,直接点击回车便可。

    

  • 把"/var/lib/mysql"整个目录移到"/mysql_data"

 

mv /var/lib/mysql /mysql_data

 

  

  这样就把MySQL的数据文件移动到了"/mysql_data/mysql"下。

 

  • 找到my.cnf配置文件

  若是"/etc/"目录下my.cnf配置文件,请到"/usr/share/mysql/"下找到*.cnf文件,拷贝其中一个合适的配置文件到"/etc/"并更名为"my.cnf"中。命令以下:

 

cp /usr/share/mysql/my-medium.cnf  /etc/my.cnf

 

  

  上图中,下查看"/etc/"下面是否有"my.cnf"文件,发现没有,而后经过上面的命令进行拷贝,拷贝完以后,进行查看,发现拷贝成功。

  备注:"/usr/share/mysql/"下有好几个结尾为cnf的文件,它们的做用分别是。

 

  

 

a、my-small.cnf:是为了小型数据库而设计的。不该该把这个模型用于含有一些经常使用项目的数据库。

b、my-medium.cnf:是为中等规模的数据库而设计的。若是你正在企业中使用RHEL,可能会比这个操做系统的最小RAM需求(256MB)明显多得多的物理内存。因而可知,若是有那么多RAM内存能够使用,天然能够在同一台机器上运行其它服务。

c、my-large.cnf:是为专用于一个SQL数据库的计算机而设计的。因为它能够为该数据库使用多达512MB的内存,因此在这种类型的系统上将须要至少1GB的RAM,以便它可以同时处理操做系统与数据库应用程序。

d、my-huge.cnf:是为企业中的数据库而设计的。这样的数据库要求专用服务器和1GB或1GB以上的RAM。

这些选择高度依赖于内存的数量、计算机的运算速度、数据库的细节大小、访问数据库的用户数量以及在数据库中装入并访问数据的用户数量。随着数据库和用户的不断增长,数据库的性能可能会发生变化。

 

  备注:这里咱们根据实际状况,选择了"my-medium.cnf"进行配置。

 

  • 编辑MySQL的配置文件"/etc/my.cnf"

  为保证MySQL可以正常工做,须要指明"mysql.sock"文件的产生位置,以及默认编码修改成UTF-8。用下面命令:

 

vim /etc /my.cnf

 

  

  须要修改和添加的内容以下:

    【client

 

socket = /mysql_data/mysql/mysql.sock

default-character-set=utf8

 

    【mysqld

 

socket = /mysql_data/mysql/mysql.sock

datadir         =/mysql_data/mysql

character-set-server=utf8

lower_case_table_names=1(注意linux下mysql安装完后是默认:区分表名的大小写,不区分列名的大小写;lower_case_table_names = 0 0:区分大小写,1:不区分大小写)

 

  备注:【client】和【mysqld】设置的编码时前地名称不同。

 

  

 

  • 修改MySQL启动脚本"/etc/rc.d/init.d/mysql"

  最后,须要修改MySQL启动脚本/etc/rc.d/init.d/mysql,修改datadir=/mysql_data/mysql

 

vim /etc/rc.d/init.d/mysql

 

  

 

  

 

  • 从新启动MySQL服务

 

service mysql start

 

  

  正准备高兴时,发现MySQL启动不了了,网上搜了一下午,各类都没有解决。后来在一篇文章才得知又是"SELinux"惹得祸。解决办法以下:

  打开/etc/selinux/config,把SELINUX=enforcing改成SELINUX=disabled后存盘退出重启机器试试,必需要重启,很关键。

 

  

 

  机器重启以后,在把"mysql服务"启动。

  

  第七步:修改登陆密码。

  MySQL默认没有密码,安装完毕增长密码的重要性是不言而喻的。

  • 修改前,直接登陆

 

  

  在没有添加密码前,直接输入"mysql"就能登陆到MySQL数据库里。

  • 修改登陆密码

  用到的命令以下:

 

mysqladmin -u root password 'new-password'

格式:mysqladmin -u用户名 -p旧密码 password 新密码

 

  咱们这里设置MySQL数据库"root"用户的密码为"hadoop"。执行的命令以下:

 

mysqladmin –u root password hadoop

 

  

 

  • 测试是否修改为功

  (1)不用密码登陆

 

  

  此时显示错误,说明密码已经修改。

  (2)用修改后的密码登陆

 

  

  从上图中得知,咱们已经成功修改了密码,而且用新的密码登陆了MySQL服务器。

  第八步:配置防火墙

  第一种:修改防火墙配置文件"/etc/sysconfig/iptables",添加以下内容:

 

-A INPUT -m state --state NEW -m tcp -p tcp --sport 3306 -j ACCEPT

-A OUTPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT

 

  而后执行下面命令,使防火墙当即生效。

 

service iptables restart

 

  第二种:关闭防火墙

  经过下面两个命令使防火墙关闭,而且永远不起做用。

 

service iptables stop

chkconfig iptables off

 

  咱们在这里为了方便,采用第二种方法,执行效果以下。

 

  

    第九步:验证MySQL数据库编码是否为UTF-8。

  链接上数据库以后,输入命令:"SHOW VARIABLES LIKE '%char%';"便可查看到如今你的数据库所使用的字符集了。

 

  

  第十步:删除空用户,加强安全。

  目前为止咱们都是以"root"的身份进行的,可是当咱们切换至普通用户登陆MySQL时,直接输入"mysql"就进去了,咱们刚才不是设置密码了吗?怎么就失效了呢?说明有空用户存在。先用命令"exit"退出,在按照下面命令进行修正。

 

  

 

     解决步骤以下:

  • 以MySQL用户"root"用密码形式登陆。

 

mysql -u root -p

 

  • 删除空用户,强烈建议。

 

mysql>delete from mysql.user where user='';

 

  • 刷新权限表,以即可以使更改当即生效。

 

mysql>flush privileges;

 

  • 输入"exit",退出MySQL。

 

mysql>exit

 

  • 再从新以"mysql"登陆测试

 

mysql

 

     发现以"mysql"登陆已经失效,必须以"mysql –u root -p"才能登陆。

 

     下面是执行效果截图:

 

  

二、MapReduce与MySQL交互

  MapReduce技术推出后,曾遭到关系数据库研究者的挑剔和批评,认为MapReduce不具有有相似于关系数据库中的结构化数据存储和处理能力。为此,Google和MapReduce社区进行了不少努力。一方面,他们设计了相似于关系数据中结构化数据表的技术(Google的BigTable,Hadoop的HBase)提供一些粗粒度的结构化数据存储和处理能力;另外一方面,为了加强与关系数据库的集成能力,Hadoop MapReduce提供了相应的访问关系数据库库的编程接口。

  MapReduce与MySQL交互的总体架构以下图所示。

 

图2-1整个环境的架构

  具体到MapReduce框架读/写数据库,有2个主要的程序分别是 DBInputFormatDBOutputFormat,DBInputFormat 对应的是SQL语句select,而DBOutputFormat 对应的是 Inster/update,使用DBInputFormat和DBOutputForma时候须要实现InputFormat这个抽象类,这个抽象类含有getSplits()和createRecordReader()抽象方法,在DBInputFormat类中由 protected String getCountQuery() 方法传入结果集的个数,getSplits()方法再肯定输入的切分原则,利用SQL中的 LIMIT 和 OFFSET 进行切分得到数据集的范围 ,请参考DBInputFormat源码中public InputSplit[] getSplits(JobConf job, int chunks) throws IOException的方法,在DBInputFormat源码中createRecordReader()则能够按必定格式读取相应数据。

      1)创建关系数据库链接

  • DBConfiguration:提供数据库配置和建立链接的接口。

      DBConfiguration类中提供了一个静态方法建立数据库链接:

 

public static void configureDB(Job job,String driverClass,String dbUrl,String userName,String Password)

 

      其中,job为当前准备执行的做业,driverClasss为数据库厂商提供的访问其数据库的驱动程序,dbUrl为运行数据库的主机的地址,userName和password分别为数据库提供访问地用户名和相应的访问密码。

      2)相应的从关系数据库查询和读取数据的接口

  • DBInputFormat:提供从数据库读取数据的格式。
  • DBRecordReader:提供读取数据记录的接口。

  3)相应的向关系数据库直接输出结果的编程接口

  • DBOutputFormat:提供向数据库输出数据的格式。
  • DBRecordWrite:提供数据库写入数据记录的接口。

  数据库链接完成后,便可完成从MapReduce程序向关系数据库写入数据的操做。为了告知数据库将写入哪一个表中的哪些字段,DBOutputFormat中提供了一个静态方法来指定须要写入的数据表和字段:

 

public static void setOutput(Job job,String tableName,String ... fieldName)

 

      其中,tableName指定即将写入的数据表,后续参数将指定哪些字段数据将写入该表。

2.1 从数据库中输入数据

      虽然Hadoop容许从数据库中直接读取数据记录做为MapReduce的输入,但处理效率较低,并且大量频繁地从MapReduce程序中查询读取关系数据库可能会大大增长数据库访问负载,所以DBInputFormat仅适合读取小量数据记录计算和应用不适合数据仓库联机数据分析大量数据读取处理

      读取大量数据记录一个更好的解决办法是:用数据库中的Dump工具将大量待分析数据输出文本数据文件,并上载到HDFS中进行处理。

 

      1)首先建立要读入的数据

  • Windows环境

  首先建立数据库"school",使用下面命令进行:

 

create database school;

 

      而后经过如下几句话,把咱们事先准备好的sql语句(student.sql事先放到了D盘目录)导入到刚建立的"school"数据库中。用到的命令以下:

 

use school;

source d:\student.sql

 

      "student.sql"中的内容以下所示:

 

DROP TABLE IF EXISTS `school`.`student`;

 

CREATE TABLE `school`.`student` (

`id` int(11) NOT NULL default '0',

`name` varchar(20) default NULL,

`sex` varchar(10) default NULL,

`age` int(10) default NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

INSERT INTO `student` VALUES ('201201', '张三', '男', '21');

INSERT INTO `student` VALUES ('201202', '李四', '男', '22');

INSERT INTO `student` VALUES ('201203', '王五', '女', '20');

INSERT INTO `student` VALUES ('201204', '赵六', '男', '21');

INSERT INTO `student` VALUES ('201205', '小红', '女', '19');

INSERT INTO `student` VALUES ('201206', '小明', '男', '22');

 

      执行结果以下所示:

 

 

      查询刚才建立的数据库表"student"的内容。

 

 

      结果发现显示是乱码,记得我当时是设置的UTF-8,怎么就出现乱码了呢?其实咱们使用的操做系统的系统为中文,且它的默认编码是gbk,而MySQL的编码有两种,它们分别是:

  【client】:客户端的字符集。客户端默认字符集。当客户端向服务器发送请求时,请求以该字符集进行编码。

  【mysqld】:服务器字符集,默认状况下所采用的。

 

      找到安装MySQL目录,好比咱们的安装目录为:

 

E:\HadoopWorkPlat\MySQL Server 5.5

 

      从中找到"my.ini"配置文件,最终发现my.ini里的2个character_set把client改为gbk,把server改为utf8就能够了。

    【client】端:

 

[client]

port=3306

[mysql]

default-character-set=gbk

 

    【mysqld】端:

 

[mysqld]

# The default character set that will be used when a new schema or table is

# created and no character set is defined

character-set-server=utf8

 

      按照上面修改完以后,重启MySQL服务。

 

 

      此时在Windows下面的数据库表已经准备完成了。

 

  • Linux环境

  首先经过"FlashFXP"把咱们刚才的"student.sql"上传到"/home/hadoop"目录下面,而后按照上面的语句建立"school"数据库。

 

  

      查看咱们上传的"student.sql"内容:

 

  

      建立"school"数据库,并导入"student.sql"语句。

 

  

 

      显示数据库"school"中的表"student"信息。

 

  

     显示表"student"中的内容。

 

  

 

      到此为止在"Windows"和"Linux"两种环境下面都建立了表"student"表,并初始化了值。下面就开始经过MapReduce读取MySQL库中表"student"的信息。

      2)使MySQL能远程链接

      MySQL默认是容许别的机器进行远程访问地,为了使Hadoop集群能访问MySQL数据库,因此进行下面操做。

  • 用MySQL用户"root"登陆。

 

mysql -u root -p

 

  • 使用下面语句进行受权,赋予任何主机访问数据的权限。

 

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'hadoop' WITH GRANT OPTION;

 

  • 刷新,使之当即生效。

 

FLUSH PRIVILEGES;

 

      执行结果以下图。

      Windows下面:

 

  

      Linux下面:

 

  

      到目前为止,若是链接Win7上面的MySQL数据库还不行,你们还应该记得前面在Linux下面关掉了防火墙可是咱们在Win7下对防火墙并无作任何处理,若是不对防火墙作处理,即便执行了上面的远程受权,仍然不能链接。下面是设置Win7上面的防火墙,使远程机器能经过3306端口访问MySQL数据库。

      解决方案:只要在'入站规则'上创建一个3306端口便可。

  执行顺序控制面板à管理工具à高级安全的Windows防火墙à入站规则

  而后新建规则à选择'端口'à在'特定本地端口'上输入一个'3306' à选择'容许链接'=>选择'域'、'专用'、'公用'=>给个名称,如:MySqlInput

 

      3)对JDBC的Jar包处理

      由于程序虽然用Eclipse编译运行但最终要提交到Hadoop集群上,因此JDBC的jar必须放到Hadoop集群中。有两种方式:

      (1)在每一个节点下的${HADOOP_HOME}/lib下添加该包,重启集群,通常是比较原始的方法。

      咱们的Hadoop安装包在"/usr/hadoop",因此把Jar放到"/usr/hadoop/lib"下面,而后重启,记得是Hadoop集群中全部的节点都要放,由于执行分布式是程序是在每一个节点本地机器上进行。

      (2)在Hadoop集群的分布式文件系统中建立"/lib"文件夹,并把咱们的的JDBC的jar包上传上去,而后在主程序添加以下语句,就能保证Hadoop集群中全部的节点都能使用这个jar包。由于这个jar包放在了HDFS上,而不是本地系统,这个要理解清楚。

 

DistributedCache.addFileToClassPath(new Path("/lib/mysql-connector-java-5.1.18-bin.jar"), conf);

 

      咱们用的JDBC的jar以下所示:

 

mysql-connector-java-5.1.18-bin.jar

 

      经过Eclipse下面的DFS Locations进行建立"/lib"文件夹,并上传JDBC的jar包。执行结果以下:

  

      备注咱们这里采用第二种方式

      4)源程序代码以下所示

 

package com.hebut.mr;

 

import java.io.IOException;

import java.io.DataInput;

import java.io.DataOutput;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

 

import org.apache.hadoop.filecache.DistributedCache;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.io.Writable;

import org.apache.hadoop.mapred.JobClient;

import org.apache.hadoop.mapred.JobConf;

import org.apache.hadoop.mapred.MapReduceBase;

import org.apache.hadoop.mapred.Mapper;

import org.apache.hadoop.mapred.OutputCollector;

import org.apache.hadoop.mapred.FileOutputFormat;

import org.apache.hadoop.mapred.Reporter;

import org.apache.hadoop.mapred.lib.IdentityReducer;

import org.apache.hadoop.mapred.lib.db.DBWritable;

import org.apache.hadoop.mapred.lib.db.DBInputFormat;

import org.apache.hadoop.mapred.lib.db.DBConfiguration;

 

public class ReadDB {

 

    public static class Map extends MapReduceBase implements

            Mapper<LongWritable, StudentRecord, LongWritable, Text> {

 

        // 实现map函数

        public void map(LongWritable key, StudentRecord value,

        OutputCollector<LongWritable, Text> collector, Reporter reporter)

                throws IOException {

            collector.collect(new LongWritable(value.id),

                    new Text(value.toString()));

        }

 

    }

 

    public static class StudentRecord implements Writable, DBWritable {

        public int id;

        public String name;

        public String sex;

        public int age;

 

        @Override

        public void readFields(DataInput in) throws IOException {

            this.id = in.readInt();

            this.name = Text.readString(in);

            this.sex = Text.readString(in);

            this.age = in.readInt();

        }

 

        @Override

        public void write(DataOutput out) throws IOException {

            out.writeInt(this.id);

            Text.writeString(out, this.name);

            Text.writeString(out, this.sex);

            out.writeInt(this.age);

        }

 

        @Override

        public void readFields(ResultSet result) throws SQLException {

            this.id = result.getInt(1);

            this.name = result.getString(2);

            this.sex = result.getString(3);

            this.age = result.getInt(4);

        }

 

        @Override

        public void write(PreparedStatement stmt) throws SQLException {

            stmt.setInt(1, this.id);

            stmt.setString(2, this.name);

            stmt.setString(3, this.sex);

            stmt.setInt(4, this.age);

        }

 

        @Override

        public String toString() {

            return new String("学号:" + this.id + "_姓名:" + this.name

                    + "_性别:"+ this.sex + "_年龄:" + this.age);

        }

    }

 

    public static void main(String[] args) throws Exception {

 

        JobConf conf = new JobConf(ReadDB.class);

 

        // 这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

 

        // 很是重要,值得关注

        DistributedCache.addFileToClassPath(new Path(

         "/lib/mysql-connector-java-5.1.18-bin.jar"), conf);

 

        // 设置输入类型

        conf.setInputFormat(DBInputFormat.class);

 

        // 设置输出类型

        conf.setOutputKeyClass(LongWritable.class);

        conf.setOutputValueClass(Text.class);

 

        // 设置MapReduce

        conf.setMapperClass(Map.class);

        conf.setReducerClass(IdentityReducer.class);

 

        // 设置输出目录

        FileOutputFormat.setOutputPath(conf, new Path("rdb_out"));

 

        // 创建数据库链接

        DBConfiguration.configureDB(conf, "com.mysql.jdbc.Driver",

            "jdbc:mysql://192.168.1.24:3306/school", "root", "hadoop");

 

        // 读取"student"表中的数据

        String[] fields = { "id", "name", "sex", "age" };

        DBInputFormat.setInput(conf, StudentRecord.class, "student", null,"id", fields);

 

        JobClient.runJob(conf);

    }

}

 

      备注:因为Hadoop1.0.0新的API对关系型数据库暂不支持,只能用旧的API进行,因此下面的"向数据库中输出数据"也是如此。

 

      5)运行结果以下所示

      通过上面的设置后,已经经过链接Win7和Linux上的MySQL数据库,执行结果都同样。惟独变得就是代码中"DBConfiguration.configureDB"中MySQL数据库所在机器的IP地址。

 

 

2.2 向数据库中输出数据

      基于数据仓库数据分析挖掘输出结果的数据量通常不会太大,于是可能适合直接向数据库写入咱们这里尝试与"WordCount"程序相结合,把单词统计的结果存入到关系型数据库中。

      1)建立写入的数据库表

      咱们还使用刚才建立的数据库"school",只是在里添加一个新的表"wordcount",仍是使用下面语句执行:

 

use school;

source sql脚本全路径

 

      下面是要建立的"wordcount"表的sql脚本。

 

DROP TABLE IF EXISTS `school`.`wordcount`;

 

CREATE TABLE `school`.`wordcount` (

`id` int(11) NOT NULL auto_increment,

`word` varchar(20) default NULL,

`number` int(11) default NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

      执行效果以下所示:

  • Windows环境

  • Linux环境

 

      2)程序源代码以下所示

 

package com.hebut.mr;

 

import java.io.IOException;

import java.io.DataInput;

import java.io.DataOutput;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.Iterator;

import java.util.StringTokenizer;

 

import org.apache.hadoop.filecache.DistributedCache;

import org.apache.hadoop.fs.Path;

import org.apache.hadoop.io.IntWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.io.Writable;

import org.apache.hadoop.mapred.FileInputFormat;

import org.apache.hadoop.mapred.JobClient;

import org.apache.hadoop.mapred.JobConf;

import org.apache.hadoop.mapred.MapReduceBase;

import org.apache.hadoop.mapred.Mapper;

import org.apache.hadoop.mapred.OutputCollector;

import org.apache.hadoop.mapred.Reducer;

import org.apache.hadoop.mapred.Reporter;

import org.apache.hadoop.mapred.TextInputFormat;

import org.apache.hadoop.mapred.lib.db.DBOutputFormat;

import org.apache.hadoop.mapred.lib.db.DBWritable;

import org.apache.hadoop.mapred.lib.db.DBConfiguration;

 

public class WriteDB {

    // Map处理过程

    public static class Map extends MapReduceBase implements

            Mapper<Object, Text, Text, IntWritable> {

 

        private final static IntWritable one = new IntWritable(1);

        private Text word = new Text();

 

        @Override

        public void map(Object key, Text value,

            OutputCollector<Text, IntWritable> output, Reporter reporter)

                throws IOException {

            String line = value.toString();

            StringTokenizer tokenizer = new StringTokenizer(line);

            while (tokenizer.hasMoreTokens()) {

                word.set(tokenizer.nextToken());

                output.collect(word, one);

            }

        }

    }

 

    // Combine处理过程

    public static class Combine extends MapReduceBase implements

            Reducer<Text, IntWritable, Text, IntWritable> {

 

        @Override

        public void reduce(Text key, Iterator<IntWritable> values,

            OutputCollector<Text, IntWritable> output, Reporter reporter)

                throws IOException {

            int sum = 0;

            while (values.hasNext()) {

                sum += values.next().get();

            }

            output.collect(key, new IntWritable(sum));

        }

    }

 

    // Reduce处理过程

    public static class Reduce extends MapReduceBase implements

            Reducer<Text, IntWritable, WordRecord, Text> {

 

        @Override

        public void reduce(Text key, Iterator<IntWritable> values,

            OutputCollector<WordRecord, Text> collector, Reporter reporter)

                throws IOException {

 

            int sum = 0;

            while (values.hasNext()) {

                sum += values.next().get();

            }

 

            WordRecord wordcount = new WordRecord();

            wordcount.word = key.toString();

            wordcount.number = sum;

 

            collector.collect(wordcount, new Text());

        }

    }

 

    public static class WordRecord implements Writable, DBWritable {

        public String word;

        public int number;

 

        @Override

        public void readFields(DataInput in) throws IOException {

            this.word = Text.readString(in);

            this.number = in.readInt();

        }

 

        @Override

        public void write(DataOutput out) throws IOException {

            Text.writeString(out, this.word);

            out.writeInt(this.number);

        }

 

        @Override

        public void readFields(ResultSet result) throws SQLException {

            this.word = result.getString(1);

            this.number = result.getInt(2);

        }

 

        @Override

        public void write(PreparedStatement stmt) throws SQLException {

            stmt.setString(1, this.word);

            stmt.setInt(2, this.number);

        }

    }

 

    public static void main(String[] args) throws Exception {

 

        JobConf conf = new JobConf(WriteDB.class);

 

        // 这句话很关键

        conf.set("mapred.job.tracker", "192.168.1.2:9001");

 

        DistributedCache.addFileToClassPath(new Path(

                "/lib/mysql-connector-java-5.1.18-bin.jar"), conf);

 

        // 设置输入输出类型

        conf.setInputFormat(TextInputFormat.class);

        conf.setOutputFormat(DBOutputFormat.class);

        // 不加这两句,通不过,可是网上给的例子没有这两句。

        conf.setOutputKeyClass(Text.class);

        conf.setOutputValueClass(IntWritable.class);

 

        // 设置MapReduce

        conf.setMapperClass(Map.class);

        conf.setCombinerClass(Combine.class);

        conf.setReducerClass(Reduce.class);

 

        // 设置输如目录

        FileInputFormat.setInputPaths(conf, new Path("wdb_in"));

 

        // 创建数据库链接

        DBConfiguration.configureDB(conf, "com.mysql.jdbc.Driver",

            "jdbc:mysql://192.168.1.24:3306/school", "root", "hadoop");

 

        // 写入"wordcount"表中的数据

        String[] fields = { "word", "number" };

        DBOutputFormat.setOutput(conf, "wordcount", fields);

 

        JobClient.runJob(conf);

    }

}

 

      3)运行结果以下所示

  • Windows环境

  测试数据:

(1)file1.txt

 

hello word

hello hadoop

 

    (2)file2.txt

 

虾皮 hadoop

虾皮 word

软件 软件

 

      运行结果:

 

      咱们发现上图中出现了"?",后来查找原来是由于个人测试数据时在Windows用记事本写的而后保存为"UTF-8",在保存时为了区分编码,自动在前面加了一个"BOM",可是不会显示任何结果。然而咱们的代码把它识别为"?"进行处理。这就出现了上面的结果,若是咱们在每一个要处理的文件前面的第一行加一个空格,结果就成以下显示:

 

      接着又作了一个测试,在Linux上面用下面命令建立了一个文件,并写上中文内容。结果显示并无出现"?",并且网上说不一样的记事本软件(EmEditor、UE)保存为"UTF-8"就没有这个问题。通过修改以后的Map类,就可以正常识别了。

 

    // Map处理过程

    public static class Map extends MapReduceBase implements

            Mapper<Object, Text, Text, IntWritable> {

 

        private final static IntWritable one = new IntWritable(1);

        private Text word = new Text();

 

        @Override

        public void map(Object key, Text value,

            OutputCollector<Text, IntWritable> output, Reporter reporter)

                throws IOException {

            String line = value.toString();

           

            //处理记事本UTF-8的BOM问题

            if (line.getBytes().length > 0) {

                if ((int) line.charAt(0) == 65279) {

                    line = line.substring(1);

                }

            }

           

            StringTokenizer tokenizer = new StringTokenizer(line);

            while (tokenizer.hasMoreTokens()) {

                word.set(tokenizer.nextToken());

                output.collect(word, one);

            }

        }

    }

 

      处理以后的结果:

 

 

      从上图中得知,咱们的问题已经解决了,所以,在编辑、更改任何文本文件时,请务必使用不会乱加BOM的编辑器。Linux下的编辑器应该都没有这个问题。Windows下,请勿使用记事本等编辑器。推荐的编辑器是: Editplus 2.12版本以上; EmEditor; UltraEdit(须要取消'添加BOM'的相关选项); Dreamweaver(须要取消'添加BOM'的相关选项) 等。

  对于已经添加了BOM的文件,要取消的话,能够用以上编辑器另存一次。(Editplus须要先另存为gb,再另存为UTF-8。) DW解决办法以下: 用DW打开指定文件,按Ctrl+Jà标题/编码à编码选择"UTF-8",去掉"包括Unicode签名(BOM)"勾选à保存/另存为,便可。

    国外有一个牛人已经把这个问题解决了,使用"UnicodeInputStream"、"UnicodeReader"。

    地址:http://koti.mbnet.fi/akini/java/unicodereader/

    示例:Java读带有BOM的UTF-8文件乱码缘由及解决方法

    代码:http://download.csdn.net/detail/xia520pi/4146123

 

  • Linux环境

  测试数据:

    (1)file1.txt

 

MapReduce is simple

 

    (2)file2.txt

 

MapReduce is powerful is simple

 

    (3)file2.txt

 

Hello MapReduce bye MapReduce

 

      运行结果:

 

 

      到目前为止,MapReduce与关系型数据库交互已经结束,从结果中得知,目前新版的API还不能很好的支持关系型数据库的操做,上面两个例子都是使用的旧版的API。关于更多的MySQL操做,具体参考"Hadoop集群_第10期副刊_经常使用MySQL数据库命令_V1.0"。

 

      本期历时五天,终于完成,期间遇到的关键问题以下:

 

  • MySQL的JDBC的jar存放问题。
  • Win7对MySQL防火墙的设置。
  • Linux中MySQL变动目录不能启动。
  • MapReduce处理带BOM的UTF-8问题。
  • 设置MySQL能够远程访问。
  • MySQL处理中文乱码问题。

 

  从这几天对MapReduce的了解,发现其实Hadoop对关系型数据库的处理还不是很强,主要是Hadoop和关系型数据作的事不是同一类型,各有所特长。下面几期咱们将对Hadoop里的HBase和Hive进行全面了解。

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.10.rar

Hadoop集群(第10期副刊)_经常使用MySQL数据库命令

一、系统管理

1.1 链接MySQL

  格式: mysql -h主机地址 -u用户名 -p用户密码

  举例

  例1:链接到本机上的MySQL。

  首先在打开DOS窗口,而后进入目录 mysqlbin,再键入命令"mysql –u root –p",回车后提示你输密码,若是刚安装好MySQL,超级用户"root"是没有密码的,故直接回车便可进入到MySQL中了,MySQL的提示符是: mysql>。

  例2:链接到远程主机上的MYSQL。假设远程主机的IP为:110.110.110.110,用户名为root,密码为abcd123。则键入如下命令:

 

mysql -h 110.110.110.110 -u root –p abcd123

 

  备注:u与root能够不用加空格,其它也同样。

  退出MySQL命令: exit (回车)。

1.2 修改新密码

  格式:mysqladmin -u用户名 -p旧密码 password 新密码

  举例

  例1:给root加个密码ab12。首先在DOS下进入目录mysqlbin,而后键入如下命令:

 

mysqladmin -u root -password ab12

 

  备注:由于开始时root没有密码,因此-p旧密码一项就能够省略了。

  例2:再将root的密码改成djg345。

 

mysqladmin -u root -p ab12 password djg345

 

1.3 增长新用户

  备注:和上面不一样,下面的由于是MySQL环境中的命令,因此后面都带一个分号";"做为命令结束符。

  格式:grant select on 数据库.* to 用户名@登陆主机 identified by '密码'

  举例

  例1:增长一个用户test1密码为abc,让他能够在任何主机上登陆,并对全部数据库有查询、插入、修改、删除的权限。首先用以root用户连入MySQL,而后键入如下命令:

 

grant select,insert,update,delete on *.* to test2@localhost identified by 'abc';

 

  或者

 

grant all privileges on *.* to test2@localhost identified by 'abc';

 

  而后刷新权限设置。

 

flush privileges;

 

  例2:若是你不想test2有密码操做数据库"mydb"里的数据表,能够再打一个命令将密码消掉。

 

grant select,insert,update,delete on mydb.* to test2@localhost identified by '';

 

1.4 启动中止MySQL

  1)Windows环境下

  首先进入DOS环境,而后进行下面操做。

  • 启动服务

 

net start mysql

 

  • 中止服务

 

net stop mysql

 

  2)Linux环境下

  • 启动服务

 

service mysql start

 

  • 中止服务

 

service mysql stop

 

二、数据库操做

2.1 库操做

  1)建立数据库

  命令:create database <数据库名>

  例如:创建一个名为xhkdb的数据库

 

mysql> create database xhkdb;

 

  2)显示全部的数据库

  命令:show databases (注意:最后有个s

 

mysql> show databases;

 

  3)删除数据库

  命令:drop database <数据库名>

  例如:删除名为 xhkdb的数据库

 

mysql> drop database xhkdb;

 

  4)链接数据库

  命令: use <数据库名>

  例如:若是xhkdb数据库存在,尝试存取它

 

mysql> use xhkdb;

 

  屏幕提示:Database changed

  5)查看当前使用的数据库

 

mysql> select database();

 

  6)当前数据库包含的表信息

 

mysql> show tables; (注意:最后有个s)

 

2.2 表操做

  备注:操做之使用"use <数据库名>"应链接某个数据库。

 

  1)建表

  命令:create table <表名> ( <字段名1> <类型1> [,..<字段名n> <类型n>]);

 

mysql> create table MyClass(

> id int(4) not null primary key auto_increment,

> name char(20) not null,

> sex int(4) not null default '0',

> degree double(16,2));

 

  2)获取表结构

  命令: desc 表名,或者show columns from 表名

 

mysql>DESCRIBE MyClass

mysql> desc MyClass;

mysql> show columns from MyClass;

 

  3)删除表

  命令:drop table <表名>

  例如:删除表名为 MyClass 的表

 

mysql> drop table MyClass;

 

  4)插入数据

  命令:insert into <表名> [( <字段名1>[,..<字段名n > ])] values ( 值1 )[, ( 值n )]

  例如:往表 MyClass中插入二条记录,这二条记录表示:编号为1的名为Tom的成绩为96.45,编号为2 的名为Joan 的成绩为82.99,编号为3 的名为Wang 的成绩为96.5。

 

mysql> insert into MyClass values(1,'Tom',96.45),(2,'Joan',82.99), (2,'Wang', 96.59);

 

  5)查询表中的数据

  • 查询全部行

  命令: select <字段1,字段2,...> from < 表名 > where < 表达式 >

  例如:查看表 MyClass 中全部数据

 

mysql> select * from MyClass;

 

  • 查询前几行数据

  例如:查看表 MyClass 中前2行数据

 

mysql> select * from MyClass order by id limit 0,2;

 

  或者

 

mysql> select * from MyClass limit 0,2;

 

  6)删除表中数据

  命令:delete from 表名 where 表达式

  例如:删除表 MyClass中编号为1 的记录

 

mysql> delete from MyClass where id=1;

 

  7)修改表中数据

  命令:update 表名 set 字段=新值,… where 条件

 

mysql> update MyClass set name='Mary' where id=1;

 

  8)在表中增长字段

  命令:alter table 表名 add字段 类型 其余;

  例如:在表MyClass中添加了一个字段passtest,类型为int(4),默认值为0

 

mysql> alter table MyClass add passtest int(4) default '0'

 

  9)更改表名

  命令:rename table 原表名 to 新表名;

  例如:在表MyClass名字更改成YouClass

 

mysql> rename table MyClass to YouClass;

 

  10)更新字段内容

  命令:update 表名 set 字段名 = 新内容

     update 表名 set 字段名 = replace(字段名,'旧内容','新内容');

  例如:文章前面加入4个空格

 

update article set content=concat('  ',content);

 

三、数据库导入导出

3.1 从数据库导出数据库文件

  使用"mysqldump"命令

  首先进入DOS界面,而后进行下面操做。

  1)导出全部数据库

  格式:mysqldump -u [数据库用户名] -p -A>[备份文件的保存路径]

  2)导出数据和数据结构

  格式:mysqldump -u [数据库用户名] -p [要备份的数据库名称]>[备份文件的保存路径]

  举例

  例1:将数据库mydb导出到e:\MySQL\mydb.sql文件中。

  打开开始à运行à输入"cmd",进入命令行模式。

 

c:\> mysqldump -h localhost -u root -p mydb >e:\MySQL\mydb.sql

 

  而后输入密码,等待一会导出就成功了,能够到目标文件中检查是否成功。

  例2:将数据库mydb中的mytable导出到e:\MySQL\mytable.sql文件中。

 

c:\> mysqldump -h localhost -u root -p mydb mytable>e:\MySQL\mytable.sql

 

  例3:将数据库mydb的结构导出到e:\MySQL\mydb_stru.sql文件中。

 

c:\> mysqldump -h localhost -u root -p mydb --add-drop-table >e:\MySQL\mydb_stru.sql

 

  备注:-h localhost能够省略,其通常在虚拟主机上用。

  3)只导出数据不导出数据结构

  格式:mysqldump -u [数据库用户名] -p -t [要备份的数据库名称]>[备份文件的保存路径]

  4)导出数据库中的Events

  格式:mysqldump -u [数据库用户名] -p -E [数据库用户名]>[备份文件的保存路径]

  5)导出数据库中的存储过程和函数

  格式:mysqldump -u [数据库用户名] -p -R [数据库用户名]>[备份文件的保存路径]

3.2 从外部文件导入数据库中

  1)使用"source"命令

  首先进入"mysql"命令控制台,而后建立数据库,而后使用该数据库。最后执行下面操做。

 

mysql>source [备份文件的保存路径]

 



重点看第9期,转载地址:

  2)使用"<"符号

  首先进入"mysql"命令控制台,而后建立数据库,而后退出MySQL,进入DOS界面。最后执行下面操做。

 

mysql -u root –p < [备份文件的保存路径]

 

  文章下载地址:http://files.cnblogs.com/xia520pi/HadoopCluster_Vol.10S.rar

http://www.cnblogs.com/xia520pi/category/346943.html  :地址 (重点第9期)