Hadoop原理
分为HDFS与Yarn两个部分。HDFS有Namenode和Datanode两个部分。每个节点占用一个电脑。Datanode定时向Namenode发送心跳包,心跳包中包含Datanode的校验等信息,用来监控Datanode。HDFS将数据分为块,默认为64M每个块信息按照配置的参数分别备份在不同的Datanode,而数据块在哪个节点上,这些信息都存储到Namenode上面。Yarn是MapReduce2,可以集成更多的组件,如spark、mpi等。MapReduce包括Jobtraker与Tasktraker两个部分。其中JobTraker是在主节点上,负责整体的调度。Tasktraker在slave节点上,当提交任务后,将其交给Jobtraker进行调度,调度到该任务之后就会将jar包发送到响应的Tasktraker,以实现分布式中移动计算资源而非移动数据。因为这些任务都是并发执行的,所以每个任务需要调用哪个节点的数据必须非常的明确,通常这一部分是通过Jobtraker进行指挥。
在MapReduce的开始,每个block作为一个Map输入,Map输入后就进入shuffle阶段。Shuffle阶段主要分为Map和Reduce两个阶段。在Map Shuffle阶段,Map输入按用户的程序进行处理,生成的结果按key排序,然后进入内存,溢出后形成一个spill写入磁盘,这样多个spill在这个节点中进行多路归并排序(胜者树)形成一个排序文件写入磁盘,这期间那些Map文件交给那些节点处理由Jobtraker进行调度,最后生成一个大排序的文件,并且删除spill。之后,再将多个节点上已经排序的文件进行行多路归并排序(一个大文件N分到n个节点,每个节点分为k个spill,一个spill长度s,时间复杂度是N(logn(n个节点多路归并排序) + logk(每个节点内k个spill排序) + logs(每个spill内部进行排序)),N=nks,所以最后的复杂度还是NlogN)。
完成Map Shuffle阶段后通知Jobtraker进入Reduce Shuffle阶段。在这个阶段,因为已经排序,很容易将用户的程序直接作用到相同key的数据上,这些数据作为Reduce的输入进行处理,最终将输出的结果数据写入到HDFS上,并删除磁盘数据。Map一般多,Reduce少,所以通过Hash的方法将Map文件映射到Reduce上,进行处理,这个阶段叫做Patition。为了避免譬如所有数据相加这种操作使得数据负载移动的数量少的Reduce阶段,造成效率低下的结果,我们可以在在Map Shuffle阶段加一个Combine阶段,这个Combine是在每一台节点上将已经排序好的文件进行一次Reduce并将结果作为Reduce Shuffle阶段的输入,这样可以大大减少数据的输入量。通常Reduce的个数通过用户来指定,通常和CPU个数相适应才能使其效率达到最大。
HBase原理
Hbase是列存储数据库。其存储的组织结构就是将相同的列族存储在一起,因此得名的。Hbase存储有行键,作为唯一标识,列表示为<列族>:<列>存储信息,如address:city,address:provice,然后是时间戳。
Hbase物理模型中,有一个总结点HMaster,通过其自带的zookeeper与客户端相连接。Hbse作为分布式每一个节点作为一个RegionServer,维护Region的状态和管理。Region是数据管理的基本单位。最初只有一个,通过扩充后达到阈值然后分裂,通过Server控制其规模。在RegionServer中,每一个store作为一个列族。当数据插入进来,新数据成为Memstore,写入内存,当Memstore达到阈值后,通过Flashcache进程将数据写入storeFile,也就是当内存数据增多后溢出成一个StoreFile写入磁盘,这里和Hadoop的spill类似,这个过程是在HDFS上进行的操作。所以数据的插入并不是追加的过程,而是积累成大块数据后一并写入。当StoreFile数量过多时,进行合并,将形成一个大的StoreFile并且删除掉原来的StoreFile。再当StoreFile大小超过一定阈值后,分裂成Region。
HBase有一个ROOT表和META表。META表记录用户Region的信息,但是随着数据增多,META也会增大,进而分裂成多个Region ,那我们用ROOT表记录下META的信息,是一个二级表,而zookeeper中记录ROOT表的location。当我们需找找到一条信息时,先去zookeeper查找ROOT,从ROOT中查找META找到META位置,在进入META表中寻找该数据所在Region,再读取该Region的信息。HBase适合大量插入又同时读的情况,其瓶颈是硬盘的传输速度而不再是像Oracle一样瓶颈在硬盘的寻道速度。
Zookeeper原理
Zookeeper是一个资源管理库,对节点进行协调、通信、失败处理、节点损坏的处理等,是一个无中心设计,主节点通过选举产生。Zookeeper的节点是Znode。每一个节点可以存放1M的数据,client访问服务器时创建一个Znode,可以是短暂的Znode,其上可以放上观察Watcher对node进行监控。Zookeeper有高可用性,每个机器复制一份数据,只要有一般以上的机器可以正常的运行,整个集群就可以工作。比如6台的集群容忍2台断开,超过两台达到一般的数量就不可以,因此集群通常都是奇数来节约资源。
Zookeeper使用zab协议,是一个无中心协议,通过选举的方式产生leader,通过每台机器的信息扩散选举最闲的资源利用较少的节点作为主控。同时当配置数据有更改更新时,在每个节点上有配置watcher并触发读取更改,。因此能够保证一致性。每个节点通过leader广播的方式,使所有follower同步。
Zookeeper可以实现分布式锁机制。通过watcher监控,对每个Znode的锁都有一个独一的编号,按照序号的大小比较,来分配锁。当一个暂时Znode完结后删除本节点,通知leader完结,之后下一个Znode获取锁进行操作。
Kafka原理
Kafka是分布式发布-订阅消息系统。它最初由LinkedIn公司开发,之后成为Apache项目的一部分。Kafka是一种快速、可扩展的、设计内在就是分布式的,分区的和可复制的提交日志服务。它被设计为一个分布式系统,易于向外扩展;它同时为发布和订阅提供高吞吐量;它支持多订阅者,当失败时能自动平衡消费者;它将消息持久化到磁盘,因此可用于批量消费,例如ETL,以及实时应用程序。broker和生产者、消费者各自都是集群,集群中的各个实例他们之间是对等的,集群扩充节点很方便。
Kafka的基本概念包括话题、生产者、消费者、代理或者kafka集群。话题是特定类型的消息流。消息是字节的有效负载,话题是消息的分类名或种子名。生产者是能够发布消息到话题的任何对象。已发布的消息保存在一组服务器中,它们被称为代理或Kafka集群。消费者可以订阅一个或多个话题,并从Broker拉数据,从而消费这些已发布的消息。
Kafka的存储布局非常简单。话题的每个分区对应一个逻辑日志。物理上,一个日志为相同大小的一组分段文件。每次生产者发布消息到一个分区,代理就将消息追加到最后一个段文件中。当发布的消息数量达到设定值或者经过一定的时间后,段文件真正写入磁盘中。写入完成后,消息公开给消费者。段文件机制和Hadoop中spill类似。消费者始终从特定分区顺序地获取消息,如果消费者知道特定消息的偏移量,也就说明消费者已经消费了之前的所有消息。消费者向代理发出异步拉请求,准备字节缓冲区用于消费。每个异步拉请求都包含要消费的消息偏移量与其它消息系统不同,Kafka代理是无状态的。这意味着消费者必须维护已消费的状态信息。这些信息由消费者自己维护,代理完全不管。消费者可以故意倒回到老的偏移量再次消费数据。这违反了队列的常见约定,但被证明是许多消费者的基本特征。
kafka的broker在配置文件中可以配置最多保存多少小时的数据和分区最大的空间占用,过期的和超量的数据会被broker自动清除掉。
Kafka会记录offset到zk,同时又在内存中维护offset,允许快速的checkpoint,如果consumer比partition多是浪费,因为kafka不允许partition上并行consumer读取。同时,consumer比partition少,一个consumer会对应多个partition,有可能导致partition中数据的读取不均匀,也不能保证数据间的顺序性,kafka只有在一个partition读取的时候才能保证时间上是有顺序的。增加partition或者consumer或者broker会导致rebalance,所以rebalance后consumer对应的partition会发生变化。
Spark原理
spark 可以很容易和yarn结合,直接调用HDFS、Hbase上面的数据,和hadoop结合。配置很容易。spark发展迅猛,框架比hadoop更加灵活实用。减少了延时处理,提高性能效率实用灵活性。也可以与hadoop切实相互结合。
spark核心部分分为RDD。Spark SQL、Spark Streaming、MLlib、GraphX、Spark R等核心组件解决了很多的大数据问题,其完美的框架日受欢迎。其相应的生态环境包括zepplin等可视化方面,正日益壮大。大型公司争相实用spark来代替原有hadoop上相应的功能模块。Spark读写过程不像hadoop溢出写入磁盘,都是基于内存,因此速度很快。另外DAG作业调度系统的宽窄依赖让Spark速度提高。
RDD是弹性分布式数据也是spark的核心,完全弹性的,如果数据丢失一部分还可以重建。有自动容错、位置感知调度和可伸缩性,通过数据检查点和记录数据更新金象容错性检查。通过SparkContext.textFile()加载文件变成RDD,然后通过transformation构建新的RDD,通过action将RDD存储到外部系统。
RDD使用延迟加载,也就是懒加载,只有当用到的时候才加载数据。如果加载存储所有的中间过程会浪费空间。因此要延迟加载。一旦spark看到整个变换链,他可以计算仅需的结果数据,如果下面的函数不需要数据那么数据也不会再加载。转换RDD是惰性的,只有在动作中才可以使用它们。
Spark分为driver和executor,driver提交作业,executor是application早worknode上的进程,运行task,driver对应为sparkcontext。Spark的RDD操作有transformation、action。Transformation对RDD进行依赖包装,RDD所对应的依赖都进行DAG的构建并保存,在worknode挂掉之后除了通过备份恢复还可以通过元数据对其保存的依赖再计算一次得到。当作业提交也就是调用runJob时,spark会根据RDD构建DAG图,提交给DAGScheduler,这个DAGScheduler是在SparkContext创建时一同初始化的,他会对作业进行调度处理。当依赖图构建好以后,从action开始进行解析,每一个操作作为一个task,每遇到shuffle就切割成为一个taskSet,并把数据输出到磁盘,如果不是shuffle数据还在内存中存储。就这样再往前推进,直到没有算子,然后运行从前面开始,如果没有action的算子在这里不会执行,直到遇到action为止才开始运行,这就形成了spark的懒加载,taskset提交给TaskSheduler生成TaskSetManager并且提交给Executor运行,运行结束后反馈给DAGScheduler完成一个taskSet,之后再提交下一个,当TaskSet运行失败时就返回DAGScheduler并重新再次创建。一个job里面可能有多个TaskSet,一个application可能包含多个job。