Hadoop生态概览

Hadoop生态概览:
#hadoop#
HDFS两种文件格式(基于文件的数据结构):1,SequenceFile,2,MapFile
SequenceFile特性:SequenceFile文件是Hadoop用来存储二进制形式的对而设计的一种平面文件(Flat File);可以把SequenceFile当作一个容器,把所有文件打包到SequenceFile类中,可以高效地对小文件进行存储和处理;SequenceFile并不按照其存储的key进行排序存储,SequenceFile的内部类Writer提供了append功能;SequenceFile中的key和value可以是任意类型Writable或者是自定义Writable类型。
MapFile特性:MapFile是经过排序的索引的SequenceFile,可以根据key进行查找;MapFile的key是WritableComparable类型的,而value是Writable类型的;可以使用MapFile.fix()方法来重建索引,把SequenceFile转换成MapFile;它有两个静态成员变量(static String DATA_FILE_NAME; //数据文件名  STATIC String INDEX_FILE_NAME;   //索引文件名)。
Hadoop RPC:Hadoop的进程间交互都是通过RPC来进行的,比如NameNode与Datanode之间,Jobtracker与Tasktracker之间等; 什么是RPC:RPC采用了Client/Server的模式,Client端发送了一个带有参数的请求信息到Server端,Server接受到这个请求后,根据发送过来的参数调用相应的程序,然后把自己计算好的结果发送给Client端,Client端接收到结果后继续运行;
Hadoop RPC实现机制:序列化层:Client与Server端通信传递的信息采用了Hadoop里提供的序列化类或自定义Writable类型;函数调用层:Hadoop RPC通过动态代理以及java反射机制实现函数调用;网络传输层:Hadoop RPC采用了TCP/IP的socket机制;服务器端框架层:RPC Server利用java NIO以及采用了事件驱动的I/O模型,提高了RPC Server的并发处理能力。
NameNode是RPC的一个动态代理对象;
public Writable call(Writable param,ConnectionId remoteId) throws InterruptedException,IOException{
Call call = new Call(param);
Connection connection = getConnection(remoteId,call);
connection.sendParam(call);
boolean interrupted = false;
synchronized(call){
while(!call.done){
try{
call.wait();
}catch(InterruptedException ie){
interrupted = true;
……
}}}}
MapReduce API: 通过org.apache.hadoop.util.RunJar来运行MapReduce任务;
新老API对比:1,新的API倾向于使用抽象类,而不是接口,因为这更容易扩展,例如,可以添加一个方法(用默认的实现)到一个抽象类中而不需修改类之前的实现方法,在新的API中,Mapper和Reducer是抽象类,2,新的API是在org.apache.hadoop.mapreduce包中,之前版本的API在org.apache.hadoop.mapred中的,3,新的API广泛使用context object(上下文对象),并允许用户代码与MapReduce系统进行通信,例如,MapContext基本上充当着JobConf的OutputCollector和Report的角色,4,新的API统一了配置,旧的API有一个特殊的JobConf对象用于作业配置,这是一个对于Hadoop通常的Configuration对象的扩展,在新的API中,这种区别没有了,所以作业配置通过Configuration来完成,作业控制的执行由Job类来负责,而不是JobClient,它在新的API中已经荡然无存。
提交作业流程:1,向jobtracker请求,getNewJobId(),2,检查job的相关输出路径,提交job以及相关的jar到jobtracker,相关的libjars是通过distributedCache方式传递到jobtracker,3,jobClient计算输入分片,把splitMetaInfo写入JobSplit,4,把job.xml配置文件发送到JobTracker,5,调用JobSubmissionProtocol的submitJob方法真正去提交作业;
错误处理:主要出错原因:1,Task失败,2,JobTracker失败,3,TaskTracker失败
JobTracker失败:是最严重的失败,如果存在单点故障,问题更加糟糕,可通过启动多个jobtracker,只运行一个主jobtracker,且由zookeeper协调控制;
作业调度(可自定义):1,先进先出调度器(FIFO),2,公平调度器(FairScheduler),3,容量调度器(CapacityScheduler);
map端:1,map端并不是简单的把中间结果写入磁盘,而是利用缓冲的方式先把map输出的结果输出到内存,2,每个map都有一个环形缓冲区,默认大小100M,大小可由属性io.sort.mb来修改,3,一旦内存缓冲区达到一个溢写阈值(io.sort.spill.percent),就会新建一个溢写文件,4,多个溢写文件最终会合并成一个已分区已排序的输出文件,作为reduce的输入,5,io.sort.factor控制着一次最多可以合并多少个分区;
reduce端:1,reduce端shuffle过程,分为三个阶段(复制map输出,排序合并,reduce处理),2,由于reduce可以接收多个map的输出,所以复制map输出阶段的时候仍然需要在本地排序与合并,3,map任务可以在不同时间完成,因此只要有一个map任务结束,reduce任务就开始复制其输出,4,reduce任务有少量的复制线程,可以并行取得map输出(mapred.reduce.parallel.copis属性来控制),5,reduce处理阶段不会等待所有输入合并成一个大文件后进行处理,而是把部分合并后的结果直接进行处理。
输入分片与记录:1,JobClient通过指定的输入文件的格式来生成数据分片InputSplit,2,一个分片不是数据本身,而是可分片数据的引用,3,InputFormat接口负责生成分片;
源码片段:FileInputFormat类中,public List getSplits(JobContext job) 
long blockSize = file.getBlockSize();    long splitSize = computeSplitSize(…);
输入类型:文本输入,二进制输入,多文件输入,数据库输入
Combiner组件:相当于本地的reducer,合并多个map;Combiner的作用是把一个map产生的多个合并成一个新的,然后再将新的作为reduce的输入;在map函数与reduce函数多了一个combine函数,目的是为了减少map输出的中间结果,这样减少了reduce复制map输出的数据,减少网络传输负载;并不是所有场景下都能使用Combiner,Combiner适用于对记录汇总的场景(如求和),但是求平均数的场景就不能使用了。
Partitioner组件:让map对key分区,根据不同key分发到不同的reduce中处理;
demo:   public class myPartitioner extends Partitioner{
public int getPartition(Text key,IntWritable value,int numPartitions){
if(key.toString().equals(“shoes”))   return 0;
if(key.toString().equals(“hat”))   return 1;
if(key.toString().equals(“stocking”))   return 2;
return 3;
}
}
LineRecordReader:public class LineRecordReader extends RecordReader
start = split.getStart();
end = start + split.getLength();
MapReduce框架允许用户自定义计数器:计数器主要用于收集系统信息,以及相关作业运行时候的统计数据,以知道作业成功或失败等情况,相比而言,计数器方式比日志更易于分析。
计数器由相关的task进行维护,定期传递给tasktracker,再由tasktracker传给jobtracker;
Map端Join:Map端连接是指数据到达map处理函数之前进行合并;
基本思路:1,需要join的两个文件,一个存储在HDFS中,一个使用DistributedCache.addCacheFile()将需要join的另一个文件加入到所有Map的缓存里,2,在Map函数里读取该文件,进行Join,3,将结果输出到reduce,4,DistributedCache.addCacheFile()需要在作业提交前设置;
Reduce端Join:reduce端连接比map端连接更普遍,因为输入的数据不需要特定的结构,但是效率低,因为所有数据必须经过shuffle过程;
基本思路:1,map 端读取所有文件,并在输出的内容加上标识代表数据是从哪个文件里来的,2,在reduce处理函数里,对按照标识对数据进行保存,3,根据Key的Join来求出结果直接输出;
MapReduce Sort;
Hadoop Streaming;
Hadoop集群管理:HDFS管理,MapReduce作业管理;
HBase利用Hadoop MapReduce来处理HBase中的海量数据;
HBase利用Zookeeper作为分布式协同服务,保持数据的一致性;
三维有序:SortedMap(RowKey,List(SortedMap(Column,List(value,TimeStamp)))
rowkey(ASC)+columnLabel(ASC)+Version(DESC) —>value
zookeeper file 记录一个ROOT表,ROOT表记录META表中每个region的位置,ROOT表只有一个region信息,META表记录各个表每个region所在的region server,META表可能包含多个region;
Spark:RDD(计算单元)支持两种操作:1,转化:从现有数据集创建一个新的数据集,2,动作:在数据集上运行计算后,返回一个值给驱动程序;
#HBase#
数据存储格式:B+树,LSM树;
StoreFile:DataBlocks,FileInfo,DataIndex,MetaBlock,Trailer;
WAL预写日志;
HLogKey类:1,当前的WAL使用的是Hadoop的SequenceFile格式,其key是HLogKey实例,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number;2,HLog Sequence File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue;
WALEdit类:客户端发送的每个修改都会封装成WALEdit类,一个WALEdit类包含了多个更新操作,可以说一个WALEdit就是一个原子操作,包含若干个操作的集合;
LogSyncer类:Table在创建的时候,有一个参数可以设置,是否每次写Log日志都需要往集群里的其他机器同步一次,默认是每次都同步,同步的开销是比较大的,但不及时同步又可能因为机器宕而丢日志;同步的操作现在是通过Pipeline的方式来实现的,Pipeline是指datanode接收数据后,再传给另外一台datanode,是一种串行的方式;n-Way Writes是指多datanode同时接收数据,最慢的一台结束就是整个结束,特点是延迟大但并发高;
Hbase Replication:来自每个region server的HLog是HBase复制的基础;
在线备份方案比较:简单备份模式:定时的Dump出集群数据保证数据安全性,通常通过snapshot或设置时间来dump数据来实现这种方案,缺点:只对时间点之前的数据安全性有保障,如果突发事件会导致不可避免的整段时间的数据丢失; 主从模式(Master-Slave):主流方案,通过最终一致性保证数据的一致,数据从主集群到备集群延时较低,异步写入不会对主集群带来性能压力,突发事件来临数据丢失很少,并且主集群的事务在备集群也可以得到保证,一般通过构造较好的Log系统加上check Point来实现,可以实现读写分离,主集群可以担当读写服务,但备集群一般只承担读服务; 主主模式(Master-Master)原理总体类似于主从模式,不同的是2个集群可以互相承担读写服务;
 集群数据迁移方案:1,静态迁移方案:Hadoop distcp,2,动态迁移方案:Replication备份方案,CopyTable方案,Export and Import方案,3,手动方式;
数据导入方案:1,利用ImportTsv将csv文件导入到HBase,2,利用completebulkload将数据导入HBase,3,利用Import将数据导入HBase;
HBase一级索引:RowKey;
HBase二级索引:1,MapReduce方案:IndexBuilder:利用MR的方式构建Index(反向表),优点:并发批量构建,缺点:不能实时构建Index; 2,Solr方案,HBase本身只对rowkey支持毫秒级的快速检索,对于多字段的组合查询却无能为力,基于Solr的HBase多条件查询原理很简单,将HBase表中涉及条件过滤的字段和rowkey在Solr中建立索引,通过Solr的多条件查询快速获得过滤条件的rowkey值,拿到这些rowkey之后在HBase中通过指定rowkey进行查询;
Snapshot(快照):快照就是一份元信息的合集,允许管理员恢复到表的先前状态,快照不是表的复制而是一个名称列表,因而不会复制数据,完全快照恢复是指恢复到之前的“表结构”以及当时的数据,快照之后发生数据不会恢复;
BloomFiler:利用多个哈希函数来判断某个元素是否属于该集合;
HBase利用Bloomfilter来提高随机读(Get)的性能,对于顺序读(Scan)而言,设置Bloomfilter是没有作用的(0.92以后,如果设置了bloomfilter为ROWCOL,对于指定了qualifier的Scan有一定优化); BloomFilter类型:ROW,ROWCOL;
基于Solr的Hbase实时查询方案:
hbase+solr+hbase indexer
1,hbase提供海量数据存储,2,solr提供索引构建与查询,3,hbase indexer提供自动化索引构建(从hbase到solr);
利用SolrJ操作solr API,使用SolrJ操作Solr会比利用httpClient来操作Solr要简单,查询使用的类:1,HttpSolrServer,2,SolrQuery;
public class HbaseConnection{
private String rootDir;
private String zkServer;
private String port;
private Configuration conf;
private HConnection hconn = null;
public HbaseConnection(String rootDir,String zkServer,String port){
this.rootDir = rootDir;
this.zkServer = zkServer;
this.port = port;
conf = HbaseConfiguration.create();
conf.set(“hbase.rootdir”,rootDir);
conf.set(“hbase.zookeeper.quorum”,zkserver);
……
}
}
#Hive#
简单函数:关系函数,数学函数,逻辑函数,数值计算,类型转换,条件函数,字符串函数,统计函数;
窗口函数:first_value(money) over (partition by id order by money rows between 1 preceding and 1 following)   // 在当前分区内取第一个值,1 preceding 当前行 1following
lead(money,3)over(order by money)      //距离当前行第三行记录
分析函数:rank() over(partition by id order by money) //排序
ntile(2) over (order by money desc nulls last)     //分片
混合函数:java_mothod(class,method[,arg1[,arg2..]])
reflect(class,method[,arg1[,arg1[,arg2..]]) hash(a1[,a2])
select java_method(“java.lang.Math”,”sqrt”,cast(id  as double)) from winfunc;
表函数(UDTF):lateralView:LATERAL VIEW udtf(expression) tableAlias AS columnAlias (‘,’columnAlias)*fromClause:FROM baseTable (lateralView)*
eg: select id,adid from winfunc lateral view explode(split(type,’B’) tt as adid;   //行转列
正则表达式:A LIKE B,字符“_”表示任意单个字符,而字符“%”表示任意数量的字符;
eg : select 1 from dual where ‘footbar’ rlike ^f.*r$;
自定义函数(UDF):userdefined function,针对单条记录;
创建函数:自定义一个java类,继承UDF类,重写evaluate方法,打jar包,hive执行add jar,hive执行创建模板函数,hql中使用;
UDAF:用户自定义聚合函数,user defined aggregation function,针对记录集合;
开发通用UDAF有两个步骤:1,编写resolver类,resolver负责类型检查,操作符重载,2,编写evaluator类,evaluator真正实现UDAF的逻辑;
Mode:    PARTIAL1(mapreduce的map阶段):从原始数据到部分数据聚合,将会调用iterate()和terminatePartial() PARTIAL2(mapreduce的map端的Combiner阶段):负责在map端合并map的数据,从部分数据聚合到部分数据聚合,将会调用merge()和terminatePartial() FINAL(map reduce的reduce阶段):从部分数据的聚合到完全聚合,将会调用merge()和terminate() COMPLETE:如果出现了这个阶段,表示map reduce只有map,没有reduce,所以map端就直接出结果了,从原始数据到完全聚合,将会调用iterate()和terminate();
代码示例:
public class CountBigThan extends AbstractGenericUDAResolver{
public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters) throws SemanticException{
if(parameters.length !=2){
throw new UDFArgumentTypeException(parameters.length -1,”Exactly two argument is expected.”;
}
return new GenericUDAFCountBigThanEvaluator();
}
public static class GenericUDAFCountBigThanEvaluator extends GenericUDAFEvaluator{
private LongWritable result;
private PrimitiveObjectInspector inputOI1;
private PrimitiveObjectInspector inputOI2;
@override //map和reduce两个阶段都会调用
public ObjectInspector init(Mode m,ObjectInspetor[] parameters) throws HiveException{
super.init(m,parameters);
result = new LongWritable(0);
inputOI1 = (PrimitiveObjectInspector) parameters[0];
if(parameters.length>1){
inputOI2 = (PrimitiveObjectInspector) parameters[1];
}
return PrimitiveObjectInspectorFactory.writableLongObjectInspector;
}
@override
public void iterate(Aggregation agg,Object[] par) throws HiveException{
assert(par.length==2);
if(par ==null || par[0] == null ||par[1] == null{
return;
}
double base = PrimitiveObjectInspectorUtils.getDouble(par[0],inputOI1);
double tmp = PrimitiveObjectInspectorUtils.getDouble(par[1],inputOI2);
if(base > tmp){
((CountAgg)agg).count++;
}
}
}
…… 
}
永久函数:FunctionRegistry.java,registerUDF(“parse_url”,UDFParseUrl.class,false);
Hive优化:
hive查询操作优化
join优化:hive.optimize.skewjoin=true;如果是join过程出现倾斜,应该设置为true;
set hive.skewjoin.key = 100000;这个是join的键对应的记录条数超过这个值则会进行优化;
mapjoin:   set hive.auto.convert.join = true;
hive.mapjoin.smalltable.filesize默认值是25mb
select /*+mapjoin(A)*/ f.a,f.b from A t join B f on (f.a = t.a)
mapjoin使用场景:1,关联操作中有一张表非常小,2,不等值的连接操作
Hive SQL 优化:bucket join:两个表以相同的方式划分桶,两个表的桶个数是倍数关系,
create table order(cid int , price float) clustered by(cid) into 32 buckets;
create table customer(id int,first string) clustered by(id) into 32 buckets;
select price from order t join customer s on t.cid = s.id;
eg : 优化前:select m.cid,u.id from order m join customer u on m.cid = u.id where m.dt =‘2013-12-12’
select m.cid,u.id from (select cid from order where dt = ‘2013-12-12’) m join customer u on m.cid = u.id;
count distinct 优化:
优化前:select count(distinct id) from tableName;      //在同一个job多步完成
优化后:select count(1) from (select distinct id from table name) tmp;    或者
select count(1) from (select id from tableName group by id) tmp;   //分成多个job完成
eg: 优化前:select a,sum(b0,count(distinct c),count(distinct d) from test group by a;
优化后:select a,sum(b) as b,count(c) as c,count(d) as d from (select a,0 as b,c,null as d from test group by a,c  union all  select a,0 as b,null as c,d from test group by a,d  union all  select a,b,null as c,null as d from test)tmp1 group by a;
Hive表优化:分区,分桶;
Hive job优化:并行化执行:每个查询被hive转化成多个阶段,有些阶段关联性不大,则可以并行化执行。减少执行时间,set hive.exec.parallel=true;   set hive.exec.parallel.thread.number=8; 本地化执行(避免数据远距离传输):set hive.exec.mode.local.auto=true;当一个job满足如下条件才能真正使用本地模式:1,job的输入数据大小必须小于参数:hive.exec.mode.local.auto.inputbytes.max(默认128MB),2,job的map数必须小于参数:hive.exec.mode.local.auto.tasks.max(默认4),3,job的reduce数必须为0或者1; JVM重利用:set mapred.job.reuse.jvm.num.tasks=20;    压缩数据:中间压缩,最好选择一个节省CPU耗时的压缩方式;最终输出也可以压缩:set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
Hive Map优化:set mapred.map.tasks=10; 无效 1,默认map个数 default_num = total_size/block_size;2,期望大小:goal_num = mapred.map.tasks;3,设置处理的文件大小,split_size = max(mapred.min.split.size,block_size); split_num = total_size/split_size;4,计算的map个数,compute_map_num = min(split_num,max(default_num,goal_num) map端聚合:set hive.map.aggr=true;
推测执行;
#集成实战#
Flume-ng介绍:Agent使用JVM运行Flume,每台机器运行一个agent,但是可以在一个agent中包含多个sources和sinks,client生产数据,运行一个独立的线程,Source从Client收集数据,传递给Channel,Sink从Channel收集数据,运行在一个独立线程,Channel连接sources和sinks,Events可以是日志记录、avro对象等。
使用kafka几个操作:
bin/zookeeper-server-start.sh config/zookeeper.properties
bin/kafka-server-start.sh config/server.properties
bin/kafka-console-producer.sh —zookeeper localhost:2181 —topic test
bin/kafka-console-consumer.sh — zookeeper localhost:2181 — topic test —from -beginning
kafka Partition offset记录在zookepper中;
Flume-ng+Kafka+Hdfs:
日志处理:1,Flume收集日志,2日志分发(hdfs,kafka)  3,日志处理(MR处理HDFS数据,Spark处理kafka数据) 4,Hive管理HDFS数据(编写hql统计数据);
#Mahout#
运行一个Mahout案例:1,启动hadoop集群,start-all.sh 2,创建测试目录testdata,并把数据文件synthetic_control.data导入到这个testdata目录中,hadoop  fs -mkdir testdata # , hadoop fs - put /opt/mahout-distribution-0.7/synthetic_control.data testdata, 3,运行Kmeans算法,hadoop  jar /opt/mahout-distribution-0.7/mahout-examples-0.7-job.jar org.apache.mahout.clustering.syntheticcontrol.kmeans.job;
聚类算法:聚类(Cluster)分析是由若干模式(Pattern)组成的,通常,模式是一个度量(Measurement)的向量,或者是多维空间中的一个点,聚类分析以相似性为基础,在一个聚类中的模式之间比不在同一聚类的模式之间具有更多的相似性;canopy聚类(Canopy Clustering),K均值算法(K-means Clustering),模糊K均值(Fuzzy K-Means),EM聚类(Expectation Maximization),均值漂移聚类(Mean Shift Clustering),层次聚类(Hierarchical),狄里克雷过程聚类(Dirichlet Process Clustering),LDA聚类(Latent Dirichlet Allocation),谱聚类(Special Clustering,Minhash,Top Down Clustering);
分类(Categorization or Classification)就是按照某种标准给对象贴标签(label),再根据标签来区分归类,分类是事先定义好类别,类别数不变。 逻辑回归(Logistic Regression),贝叶斯(Bayesian),支持向量机(Support Vector Machines),感知器算法(Perception and Winnow),神经网络(Neural NetWork),随机森林(Random Forests),有限波尔兹曼机(Restricted Boltzmann Machines);
协同过滤:电子商务推荐;
Mahout源码编译:下载mahout源码包,转成eclipse工程,mvn eclipse:eclipse;
K-mans算法:以空间中k个点为中心进行聚类,对最靠近他们的对象归类,通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果; 
类的解释:KMeansMapper:在configure中初始化mapper时读入上一次迭代产生或初始聚类中心(每个mapper都读入所有的聚类中心);map方法对输入的每个点,计算距离其最近的类,并加入其中输出key为该点所属聚类ID,value为KMeansInfo实例,包含点的个数和各分量和;   KMeasCombiner:本地累加KMeansMapper输出的同一聚类ID下的点个数和各分量的和    KMeansReducer:累加同一聚类ID下的点个数和各分量的和,求本次迭代的聚类中心;  并根据输入Delta判断该聚类是否收敛:上一次迭代聚类中心与本次迭代聚类中心的距离
Canopy Clustering是一种小而美的,但不太准确的聚类方法:1,设样本集合为S,确定两个阈值t1和t2,且t1>t2,2,任取一个样本点p属于S,作为一个Canopy,记为C,从S中移除p,3,计算S中所有点到p的距离dist,,4,若dist
Bayes算法:概率公式原型 P(A∩B)=P(A)*P(B|A)=P(B)*P(A|B),多项式模型,伯努利模型。
Mahout Taste框架:协同过滤在mahout里是由一个叫taste的引擎提供的,它提供两种模式,一种是以jar包形式嵌入到程序里在进程内运行,另外一种是MapReduce Job形式在hadoop上运行。 Taste自带的推荐器:Item-based,User-based,Model-based,ItemAverageRecommender;

你可能感兴趣的:(Hadoop生态)