一台单机在存储容量、并发性上毫无疑问都是有很大限制的。为了解决单机无法完成的大存储(>1TB)和大规模计算,分布式系统就应运而生了。传统的基于RDBMS的存储和计算存在着扩展差和容错差的两大瓶颈。
关于分布式数据库的现实
MapReduce计算框架适用于超大规模的数据(100TB量级)且各数据之间相关性较低的情况。MapReduce的思想是由Google的论文所提及而被广为流传的,简单的一句话解释MapReduce就是“任务的分解与结果的汇总”。
MapReduce的编程模型:
Map的作用就是把输入数据打散,做简单的处理,输出。而hadoop则要先将中间数据排序,这个称为shuffle,然后由reduce把中间数据合并到一起。将最终结果输出。
其框架实现是由一个单独运行在主节点上的JobTracker和运行在每个集群从属节点上的TaskTracker共同组成。主节点负责调度构成一个个作业,这些作业分布运行在从属节点上,主节点监控它们的执行情况并管理失败的作业重新执行。
Google的GFS(Google File System),MapReduce论文
Mapreduce & Hadoop Algorithms in Academic Papers (4th update – May 2011)
Google MapReduce/GFS/BigTable三大技术的论文中译版
Hadoop是伟大的Apache基金会实现的一套分布式系统,是采用Java开发的开源MapReduce框架实现。Hadoop包括分布式文件系统(HDFS)、MapReduce计算框架、HBase等很多组件——这些基本都是Google的GFS/MapReduce/BigTable的克隆产品。
Hadoop经过数年的发展,目前已经很成熟了,尤其是其中的HDFS和MapReduce计算框架组件。数百台机器的集群已经被证明可以使用(Yahoo!的最大hadoop集群部署为4000个计算节点),可以承担PB级别的数据:
Hadoop的前身是Apache Nutch,始于2002年,是Apache Lucene的子项目之一,Hadoop在2008年1月被提升为顶级项目。在Google提出在基于自己的BigTable大规模数据存储的Map Reduce计算框架之后,Nutch的发起者开始尝试将二者结合并在2006年分离出来成立了一套完整的软件取名为Hadoop。因此,如今的Hadoop成为了一个包含HDFS,MapReduce,Pig,ZooKeeper等子项目的集合。
Hadoop(某人儿子的一只虚拟大象的名字)是一个复杂到极致,又简单到极致的东西。
举个简单的例子:公安局要根据数据库内身份证号获得全国每个地市人口数情况(好吧,这个应该是统计局做的),这个任务落到你的头上了,你应该先把所有的身份证号导出到文件中,每行一个,然后把这些文件交给map。Map中的要做的就是截取身份证号的前面六位,把这六位数字直接输出。然后hadoop会把这些身份证号的前六位排序,把相同的数据都排到一起,交给reduce,reduce判断每次输入的号码是否与上一个处理的相同,相同则累加,不同则把之前的号码,和统计的数值输出。这样,你就获得了各地市的人口数统计。
下面这个图就是map和reduce处理的图示。
上图是MapReduce的数据处理视图。分为map,shuffle,reduce三个部分。各map任务读入切分后的大规模数据进行处理并将数据作为一系列key:value对输出,输出的中间数据按照定义的方式通过shuffle程序分发到相应的reduce任务。Shuffle程序还会按照定义的方式对发送到一个reduce任务的数据进行排序。Reduce进行最后的数据处理。
现在讨论得比较热的是Facebook主打的Hive,还有淘宝网所使用的HBase。这二者都是基于Hadoop的衍化项目。
一个Hive的实例是Facebook利用Hive QL强大的查询分析能力给的页面的广告商提供大量有价值的用户喜好数据,便于广告商在特定的时机投放回报率最高的广告。一个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来做日志分析很显然不是一件简单事情,它带来了很多的额外的学习和运维成本,但是至少,它让超大规模的日志分析变成了可能。
在超大规模的数据上做任何事情都不是一件容易的事情,包括日志分析,但也并不是说分布式的日志分析就一定要去写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终于跑不完了。而最终用户往往不会去关心这些事情,他们只关心自己提交的查询是不是能即时得到响应,怎么样才能尽快的拿到结果。
举个简单的例子,如果发现在使用apache_log的所有查询中,几乎没有人用其中的user_agent字段,那么我们完全可以把这个字段去除掉,或者拆分成两张表,以减少多数查询的IO时间,提高执行的效率。
为了系统化的解决这些问题,
再者随着日志类型、分析需求的不断增长。用户会越来越多的抱怨很难找到想要的数据在哪份日志里,或者跑的好好的查询因为日志格式的变化而突然不能用了。另外上面提到的ETL过程也会变得复杂,简单的转换导入脚本很可能已经解决不了问题。这时候可能需要构建一个数据管理系统,或者干脆考虑建立一个所谓的数据仓库。
总之,随着日志数据量、日志类型、用户数量、分析需求等等的不断增长,越来越多的问题会逐渐浮现出来,日志分析这件事情可能就不再像我们最初想的那么简单,会变得越来越有价值,也越来越有挑战。
HDFS是基于Java实现的可以部署在廉价的硬件上的,具有高吞吐率和高容错性的一套开源系统。由于HDFS放宽了POSIX的部分约束规范,使得它能以流形式访问文件系统中的数据。
整个HDFS系统设计了两套自己的协议,都是基于TCP/IP协议之上设计的:Client Protocol和DataNode Protocol。
这是一张任何介绍hdfs的文章都会出现的架构图。
HDFS采用了主从(Master/Slave)结构模型,一个HDFS由一个NameNode和若干个DataNode组成。其中NameNode作为主服务器,管理文件系统的命名空间和客户端的连接。集群中的DataNode则管理各自存储的数据。
NameNode(以下简称nn)是master,主要负责管理hdfs文件系统和client对文件的访问,具体地包括
DataNode(简称dn)主要是用来存储数据文件,
体系结构中还有个节点没画出来,Secondary NameNode,
不管是client还是dn的消息发到nn后最终都会落到FSNamesystem身上,这是一个重量级家伙,如图,对各种服务请求的处理都转交给它完成,它提供了对各种数据结构操作的接口,这些数据结构共同维护了整个namenode的元数据信息。
这里有篇分析namenode源码的博文,可供进一步探究。
和HDFS类似,MapReduce中也有两种角色:Master/Worke
Master-JobTracker –作业与任务调度 –负责将中间文件信息通知给reducer所在的worker –Master周期性检查Worker的存活 Worker-TaskTracker –TaskTracker空闲, 向Master要任务 –执行mapper或者reducer任务
除了作业任务调度,这个框架还要做以下处理 –错误处理,失败任务自动重算 –防止慢作业,任务的预测执行
更多可以看Hadoop开源社区MapReduce官方指南。
下一代MapReduce资源调度与计算模型分离
Streaming接口 –支持使用脚本和任何程序来书写mapper和reducer程序 –java和本地的脚本或程序利用管道传输数据 –程序示例: $HADOOP_HOME/bin/hadoop streaming -input myInputDirs -output myOutputDir -mapper "grep baidu" -reducer /bin/wc
MPI是一种消息传递编程模型,并成为该编程模型的代表和事实标准。
HDFS
数据透明压缩--节省存储空间(利用CPU波压缩长时间未使用的块,随即读处理+Append处理)
数据可靠性--HDFS块复制改进
MapReduce
调度--Job Queue:多队列 借用 抢占(资源调度)
Hadoop C++ Extension(HCE用户编程框架)
作业断点重启--作业失败后可以接着上次的进度运行,集群重启后运行的作业重启前的进度运行
Shuffle独立--提高shuffle的总吞吐 减少资源浪费
同一个reduce不同类型的数据输出到不同文件
多路输出 == 多路合并?