Hadoop的那些事儿

一台单机在存储容量、并发性上毫无疑问都是有很大限制的。为了解决单机无法完成的大存储(>1TB)和大规模计算,分布式系统就应运而生了。

MapReduce


MapReduce计算框架适用于超大规模的数据(100TB量级)且各数据之间相关性较低的情况。MapReduce的思想是由Google的论文所提及而被广为流传的,简单的一句话解释MapReduce就是“任务的分解与结果的汇总”。

MapReduce的编程模型:

  • Map: <k1,v1> –> <k2,v2>
  • Shuffle: sort by key & group by key
  • Reduce: <k2,<list of v2>>  -> <k3,v3>

Map的作用就是把输入数据打散,做简单的处理,输出。而hadoop则要先将中间数据排序,这个称为shuffle,然后由reduce把中间数据合并到一起。将最终结果输出。

其框架实现是由一个单独运行在主节点上的JobTracker和运行在每个集群从属节点上的TaskTracker共同组成。主节点负责调度构成一个个作业,这些作业分布运行在从属节点上,主节点监控它们的执行情况并管理失败的作业重新执行。

Google的GFS(Google File System),MapReduce论文

  • 采用了函数式编程语言的map和reduce两个函数
  • 解决那些数据可以切割进行计算的应用,比如grep操作,求和计算
  • 提供了运行平台,自动处理出错

Mapreduce & Hadoop Algorithms in Academic Papers (4th update – May 2011)

Google MapReduce/GFS/BigTable三大技术的论文中译版

 

Hadoop


Hadoop是伟大的Apache基金会实现的一套分布式系统,是采用Java开发的开源MapReduce框架实现。Hadoop包括分布式文件系统(HDFS)、MapReduce计算框架、HBase等很多组件——这些基本都是Google的GFS/MapReduce/BigTable的克隆产品。

Hadoop经过数年的发展,目前已经很成熟了,尤其是其中的HDFS和MapReduce计算框架组件。数百台机器的集群已经被证明可以使用(Yahoo!的最大hadoop集群部署为4000个计算节点),可以承担PB级别的数据:

  • Hadoop Distributed File System(HDFS)
    对数据进行分布式存储,并且为上层的mapred计算层提供支持
  • Hadoop MapReduce
    对存储在HDFS上的数据进行分布式计算

Hadoop的前身是Apache Nutch,始于2002年,是Apache Lucene的子项目之一,Hadoop在2008年1月被提升为顶级项目。在Google提出在基于自己的BigTable大规模数据存储的Map Reduce计算框架之后,Nutch的发起者开始尝试将二者结合并在2006年分离出来成立了一套完整的软件取名为Hadoop。因此,如今的Hadoop成为了一个包含HDFS,MapReduce,Pig,ZooKeeper等子项目的集合。

 

Hadoop(某人儿子的一只虚拟大象的名字)是一个复杂到极致,又简单到极致的东西。

  • 说它复杂,是因为一个hadoop集群往往有几十台甚至成百上千台low cost的计算机组成,你运行的每一个任务都要在这些计算机上做任务的分发,执行中间数据排序以及最后的汇总,期间还包含节点发现,任务的重试,故障节点替换等等等等的维护以及异常情况处理。谁叫hadoop集群往往都是由一些平民计算机组成,没事儿罢个工什么的,实在是再寻常不过的事情。
  • 而说其简单,则是因为,上面说到的那些,你通通不用管,你所需要做的,就是写一个程序,当然也可以是脚本,从标准输入读入一条数据,处理完之后,把结果输出到标准输出。

举个简单的例子:公安局要根据数据库内身份证号获得全国每个地市人口数情况(好吧,这个应该是统计局做的),这个任务落到你的头上了,你应该先把所有的身份证号导出到文件中,每行一个,然后把这些文件交给map。Map中的要做的就是截取身份证号的前面六位,把这六位数字直接输出。然后hadoop会把这些身份证号的前六位排序,把相同的数据都排到一起,交给reduce,reduce判断每次输入的号码是否与上一个处理的相同,相同则累加,不同则把之前的号码,和统计的数值输出。这样,你就获得了各地市的人口数统计。

下面这个图就是map和reduce处理的图示。

Image

上图是MapReduce的数据处理视图。分为map,shuffle,reduce三个部分。各map任务读入切分后的大规模数据进行处理并将数据作为一系列key:value对输出,输出的中间数据按照定义的方式通过shuffle程序分发到相应的reduce任务。Shuffle程序还会按照定义的方式对发送到一个reduce任务的数据进行排序。Reduce进行最后的数据处理。

 

现在讨论得比较热的是Facebook主打的Hive,还有淘宝网所使用的HBase。这二者都是基于Hadoop的衍化项目。

一个Hive的实例是Facebook利用Hive QL强大的查询分析能力给的页面的广告商提供大量有价值的用户喜好数据,便于广告商在特定的时机投放回报率最高的广告。一个HBase的实例是淘宝网利用HBase分布式读写大数据的能力来支撑圣诞、光棍节这种庞大的实时在线交易数据。(原文

HBase


Hadoop项目中的HBase(分布式索引系统, 类Google的BigTable)是一个按列存储NoSQL分布式数据库。该技术来源于Google的BigTable(一个结构化数据的分布式存储系统)。HBase在Hadoop基础上提供了类似BigTable的分布式存储能力。

HBase是一个适合于存储非结构化数据的数据库,因为它是基于列存储而不是行存储,用户将数据存储在稀松的表里,每一行数据都可以拥有可选择的键和任意数量的列。HBase主要用于需要随机访问实时读写大数据的应用。

HBase提供的功能和接口都非常简单,只能进行简单的K-V查询,因此并不直接适用于大多数日志分析应用。


所以一般使用Hadoop来做日志分析,首先还是需要将日志存储在HDFS中,然后再使用它提供的MapReduce API编写日志分析程序。

MapReduce是一种分布式编程模型,并不难学习,但是很显然使用它来处理日志的代价依然远大于单机脚本或者SQL。一个简单的词频统计计算可能都需要上百代码——SQL只需要一行,另外还有复杂的环境准备和启动脚本。Hadoop的实现就要复杂的多,通常需要两轮MapReduce来完成。

首先要在第一轮的mapper中计算部分ip的访问次数之和,并以ip为key输出;然后在第一轮的reduce中就可以得到每个ip完整的计数,可以顺便排个序,并且只保留前100个;由于reduce一般会有很多个,所以最后还需要将所有reduce的输出进行合并、再排序,并得到最终的前100个IP以及对应的访问量。

所以使用Hadoop来做日志分析很显然不是一件简单事情,它带来了很多的额外的学习和运维成本,但是至少,它让超大规模的日志分析变成了可能。

 

Hive(Facebook)


在超大规模的数据上做任何事情都不是一件容易的事情,包括日志分析,但也并不是说分布式的日志分析就一定要去写MapReduce代码。

总是可以去做进一步的抽象,在特定的应用下让事情变得更简单:

也许有人会很自然的想到如果能用SQL来操作Hadoop上的数据该有多好。

事实上,不仅仅只有你一个人会这么想,很多人都这么想,并且他们实现了这个想法,于是就有了Hive。

Hive现在也是Hadoop项目下面的一个子项目,是建立在Hadoop基础之上的数据仓库,它可以让我们用SQL的接口来执行MapReduce(该语言简称Hive QL),甚至提供了JDBC和ODBC的接口。有了这个之后,Hadoop基本上被包装成一个数据库。Hive提供了一些用于数据整理、特殊查询和分析存储在Hadoop文件系统中数据的工具。

当然实际上Hive的SQL最终还是被翻译成了MapReduce代码来执行,因此即使最简单的SQL可能也要执行好几十秒。幸好在通常的离线日志分析中,这个时间还是可以接受的。更重要的是,对于上面提到的例子,我们又可以用一样的SQL来完成分析任务了。

当然Hive并不是完全的兼容SQL语法,而且也不能做到完全的对用户屏蔽细节。很多时候为了执行性能的优化,依然需要用户去了解一些MapReduce的基本知识,根据自己的应用模式来设置一些参数,否则我们可能会发现一个查询执行很慢,或者压根执行不出来。

另外,很显然Hive也并不能覆盖所有的需求,所以它依然保留插入原始MapReduce代码的接口,以便扩展。

 

即使有了Hive这样一个类似于数据库的东西,我们依然还有很多事情需要做。

例如时间久了,可能会有越来越多的需要例行执行的SQL,而这些SQL中,

  • 也许有一些是做了重复的事情;
  • 也许有一些的执行效率非常低下,一个复杂的SQL就占满了所有的计算资源。

这样的系统会变得越来越难以维护的,直到有一天例行的SQL终于跑不完了。而最终用户往往不会去关心这些事情,他们只关心自己提交的查询是不是能即时得到响应,怎么样才能尽快的拿到结果。

举个简单的例子,如果发现在使用apache_log的所有查询中,几乎没有人用其中的user_agent字段,那么我们完全可以把这个字段去除掉,或者拆分成两张表,以减少多数查询的IO时间,提高执行的效率。

为了系统化的解决这些问题,

  • 我们可能需要引入例行任务的调度机制
  • 可能需要去分析所有的SQL来发现哪些是可以合并的、哪些的性能需要优化,
  • 使用的数据表是不是需要做水平或者垂直分表等等。
  • 根据实际情况的不同,这时事情可能是人工来完成,也可能是写程序来自动分析并调整。

再者随着日志类型、分析需求的不断增长。用户会越来越多的抱怨很难找到想要的数据在哪份日志里,或者跑的好好的查询因为日志格式的变化而突然不能用了。另外上面提到的ETL过程也会变得复杂,简单的转换导入脚本很可能已经解决不了问题。这时候可能需要构建一个数据管理系统,或者干脆考虑建立一个所谓的数据仓库

总之,随着日志数据量、日志类型、用户数量、分析需求等等的不断增长,越来越多的问题会逐渐浮现出来,日志分析这件事情可能就不再像我们最初想的那么简单,会变得越来越有价值,也越来越有挑战。

 

ZooKeeper


 

 

日志分析方法概述

使用hadoop进行大规模数据的全局排序

Zookeeper工作原理

框计算垂直搜索之索引篇

 

HDFS


HDFS是基于Java实现的可以部署在廉价的硬件上的,具有高吞吐率高容错性的一套开源系统。由于HDFS放宽了POSIX的部分约束规范,使得它能以流形式访问文件系统中的数据。

  • 分布式存储
    文件被分成256MB的block
    block被分配到各个存储节点上
  • 容错性
    每个block有多个replica(副本)
    Re-Replication
  • 负载均衡
    Re-Balance

整个HDFS系统设计了两套自己的协议,都是基于TCP/IP协议之上设计的:Client Protocol和DataNode Protocol。

  • Client Protocol负责客户端与文件系统的通信,
  • 而文件系统内部各个节点之间通过DataNode Protocol协议来实现内部的通信和文件和管理。

 

这是一张任何介绍hdfs的文章都会出现的架构图。

HDFS采用了主从(Master/Slave)结构模型,一个HDFS由一个NameNode和若干个DataNode组成。其中NameNode作为主服务器,管理文件系统的命名空间和客户端的连接。集群中的DataNode则管理各自存储的数据。

NameNode(以下简称nn)是master,主要负责管理hdfs文件系统和client对文件的访问,具体地包括

  • 文件系统命名空间namespace管理(其实就是目录结构,HDFS对外提供一个namespace允许用户把数据存为文件的格式),
  • block管理(其中包括 filename->block,block->ddatanode list的对应关系)。
  • nn提供的是始终被动接收服务的server,主要有三类协议接口:ClientProtocol接口、DatanodeProtocol接口、NamenodeProtocol接口,貌似还有一种,忘记了。
  • HDFS的文件组织结构和linux的local filesystem非常类似。你可以创建,删除,移动,重命名文件或者目录。NameNode操作命名空间比如:打开,关闭,重命名文件目录。
  • NameNode只负责元数据信息,没有数据流。NameNode维护namespace,任何对namespace的改动都记录在NameNode。

DataNode(简称dn)主要是用来存储数据文件,

  • hdfs将一个文件分割成一个个的block,这些block可能存储在一个DataNode上或者是多个DataNode上。
  • 通常一个机器节点一个DataNode,管理这个节点上的存储。
  • DataNode负责为文件系统的客户提供读/写操作服务。DataNode同时还为NameNode提供block创建,删除,备份机制
  • dn负责实际的底层的文件的读写,如果客户端client程序发起了读hdfs上的文件的命令,那么首先将这些文件分成block,
  • 然后nn将告知client这些block数据是存储在那些dn上的,之后,client将直接和dn交互。

体系结构中还有个节点没画出来,Secondary NameNode,

  • 该部分主要是定时对NameNode进行数据snapshots进行备份,这样尽量降低NameNode崩溃之后,导致数据的丢失,
  • 其实所作的工作就是从nn获得fsimage和edits把二者重新合并然后发给nn,这样,既能减轻nn的负担又能保险地备份。

不管是client还是dn的消息发到nn后最终都会落到FSNamesystem身上,这是一个重量级家伙,如图,对各种服务请求的处理都转交给它完成,它提供了对各种数据结构操作的接口,这些数据结构共同维护了整个namenode的元数据信息。

x`

这里有篇分析namenode源码的博文,可供进一步探究。

 

MapReduce


 

image

和HDFS类似,MapReduce中也有两种角色:Master/Worke

Master-JobTracker
–作业与任务调度
–负责将中间文件信息通知给reducer所在的worker
–Master周期性检查Worker的存活
Worker-TaskTracker
–TaskTracker空闲, 向Master要任务
–执行mapper或者reducer任务

除了作业任务调度,这个框架还要做以下处理
–错误处理,失败任务自动重算
–防止慢作业,任务的预测执行

image

更多可以看Hadoop开源社区MapReduce官方指南

下一代MapReduce资源调度与计算模型分离

 

Streaming


Streaming接口
–支持使用脚本和任何程序来书写mapper和reducer程序
–java和本地的脚本或程序利用管道传输数据
–程序示例:
$HADOOP_HOME/bin/hadoop streaming -input myInputDirs -output myOutputDir -mapper "grep baidu" -reducer /bin/wc

 

 

Message-Passing Interface (MPI)


MPI是一种消息传递编程模型,并成为该编程模型的代表和事实标准。

  • MPI是一个库,而不是一门语言,MPI库可以被FORTRAN/C/C++/Python/java调用,把这些串行语言扩展为并行语言。
  • MPI拥有多种开源实现:Mpich, lammpi, openmpi。
  • MPI能用于大多数并行计算机、机群系统和异构网络环境,能达到较高的数据传输速率。一个正确的MPI程序,可以不加修改地在所有的并行计算机上运行。
  • 开发成本高,无容错

 

HDFS

数据透明压缩--节省存储空间(利用CPU波压缩长时间未使用的块,随即读处理+Append处理)

数据可靠性--HDFS块复制改进

 

MapReduce

调度--Job Queue:多队列 借用 抢占(资源调度)

Hadoop C++ Extension(HCE用户编程框架)

作业断点重启--作业失败后可以接着上次的进度运行,集群重启后运行的作业重启前的进度运行

Shuffle独立--提高shuffle的总吞吐 减少资源浪费

 

同一个reduce不同类型的数据输出到不同文件

多路输出 == 多路合并?

 

传统数据库的瓶颈


传统的基于RDBMS的存储和计算存在着扩展差容错差的两大瓶颈。

关于分布式数据库的现实

  • 首先,实现比较完美的分布式数据库(受限于CAP原则)是一个非常复杂的问题,因此在这里并不像单机数据库那样,有那么多开源的好东西可以用,甚至于商用的也并不是太多。当然,也并非绝对,如果有钱,还是可以考虑一下Oracle RAC、Greenplum之类东西。
  • 其次,绝大多数分布式数据库都是NoSQL的,所以想继续用上SQL的那些优点基本上是没指望,取而代之的都是一些简单、难以使用的接口。单从这点看来,使用这些数据库的价值已经降低很多了。
  • 所以,还是先现实一点,先退一步考虑如何解决的超大规模的日志的分析问题,而不是想如何让它变的像在小数据规模时那样简单。单单想做到这点,目前看来并不是太难,并且依然有免费的午餐可以吃。

比较SQL数据库和Hadoop

1 用向外扩展代替向上扩展(服务器集群)

2 用key/value对代替关系表(文本、图片、xml文件)

3 用函数式编程(mapreduce)代替声明式查询(SQL)

 

http://www.cnblogs.com/wangyonghui/category/319595.html

http://www.cnblogs.com/wycg1984/category/238035.html

http://www.cnblogs.com/wayne1017/archive/2007/03/18/668768.html

http://blog.csdn.net/lengzijian/article/category/942129

posted on 2012-04-01 23:02  小唯THU  阅读(1328)  评论(0编辑  收藏  举报

导航