Hadoop相关组成介绍

Hadoop只是一套工具的总称,它包含三部分:HDFS,Yarn,MapReduce,功能分别是分布式文件存储、资源调度和计算。仓库管理中心(namenode)每次入库,需要管理中心安排自我复制多份放到不同的仓库,每次有人来取,需要去管理中心查询在哪些仓库并就近获取。(namenode管理元数据,负责HDFS上数据的读写)


HDFS(分布式文件系统)

分布式文件系统,将不同服务器的硬盘连接起来,在外面看起来就好像一块巨大的硬盘。然后构建与其上的MapReduce协同各个服务器运算。


MapReduce(分布式计算模型)

用来解决大规模集群协同运算的问题,海量数据计算,Map阶段把数据分发给多个处理站分批统计处理,Reduce阶段把多个处理站处理的解决汇总给一个处理站再处理统计,最后放到HDFS就是资源。


Yarn

用Yarn调度资源,读取HDFS文件内容进行MR计算。要写Java代码,但做数据的最好的工具是什么?SQL!所以Hive相当于这一套标准流程的SQL化。


Hive

可以简单理解为基于HDFS的数据仓库工具,可以将Hive SQL转化为MapReduce进行数据处理查询的工具。Hadoop之上添加了自己的SQL解析和优化器,写一段SQL,解析为Java代码,然后去执行MR,底层数据还是在HDFS上。它们把脚本和SQL语言翻译成MapReduce程序,丢给计算引擎去计算,而你就从繁琐的MapReduce程序中解脱出来,用更简单更直观的语言去写程序了。

它的最大贡献有两个:

  • 提供了一个存储和管理元数据的HiveMetastore,以库和表的形式来组织存储在HDFS上面的数据;
  • 实现了一套将SQL转换为分布式执行的MapReduce的执行引擎。这么看起来,Hive就是一个分布式的数据库嘛,但是它是OLAP,适合在海量数据上做大范围的SCAN和聚合,不擅长做OLTP数据(如MySQL)那样频繁的CRUD数据。

Hbase

是Hadoop项目的子项目,是一个分布式的、面向列的NoSQL数据库,虽然不是基于MapReduce,但是也是可以存储、处理大规模的数据,是Hadoop家族重要的一员。


Spark

spark streaming 微批次准实时处理数据吞吐量巨大,应用于很多的实时数据统计场景,基于内存。


从hive + 元数据管理 + HDFS 变成 spark + 元数据管理 + HDFS工作量太大,就想了一个妥协的办法,在元数据管理上沿用Hive Metastore,但是在执行引擎上用Spark SQL。


Flink:对流批关系、有状态计算等做了更合理的抽象,有状态计算是指下一次计算依赖上一次结算输出的结果,Flink里面把它叫做State。Flink 支持三种时间机制:事件时间,注入时间,处理时间,同时支持 watermark 机制处理迟到的数据,说明Flink在处理乱序大实时数据的时候,优势比较大。



举例使用场景(订单)

订单数据插入数据库时一般会有binlog,即记录插入、更新或删除的数据,我们只要能实时拿到这一条binlog,就相当于拿到了实时数据。数据库的主从备份机制,一般本身就是拿主库的binlog同步到备份库,canal可以把自己伪装成备份库,来拉取主库的binlog,再解析、包装最后抛出,就相当于实时拿到数据。canal抛出的消息下游无法一次消费完,可以放入消息队列,Kafka和rocketmq 就是起这样的作用:异步、解耦、消峰。canal的数据一般会抛到kafka或RocketMQ,可以保存一段时间。然后下游程序再去实时拉取消息来计算。下游有Spark Streaming 就是用来微批地处理流式数据的,Flink 不同于 Spark Streaming 的微批次处理,它是一条一条数据处理的。但难免会有些数据沿途受阻晚来了几秒钟,这就会导致两个问题:数据延迟和乱序数据。这也是做实时数据的非常关注的问题。

数据延迟:如果是上游数据迟了,就加大上游资源;如果是数据突然激增,Flink 处理不过来导致任务出现延迟,就加大 Flink 的资源,比如并发。
数据乱序:一般也通过上游和 Flink 本身来分别保证。
Kafka 有分区的概念,就像是不同的通道,一条消息来了后,可以走 A,也可以走 B,也可以走 C。那么问题来了,业务数据抛入 Kafka,如何保证消息的顺序性呢?

顺序性一般有两方面需要保证。我们举一个小小的例子,一个用户下单的场景,有两个基本共识:

(1)同一个用户的订单状态会先后变化;

那么如何保证同一用户的订单顺序呢?很简单,前面我们提到的链路是,数据库中插入或更新数据时,会实时产生该条数据的 binlog,canal 获取、解析、包装这条 binlog 并抛入 Kafka。Kafka 由于有分区的存在,很可能同一个订单的消息会被发送到不同的分区中,这样的话,如果下游的 Flink 任务消费不同分区速率不同,就可能导致先到的数据反而被后消费,产生顺序误差。解决的办法即保证同一订单的消息进入 Kafka 的同一分区即可。Kafka 的每一条消息都会有 messageKey 和 message 两个结构,如果没有直接给消息指定分区,那么 messageKey 决定了消息进入哪个分区,在 canal 中,我们便可以设定消息如何进入 Kafka。数据库中的业务数据,会存在一张张的表中,表一般都会有主键,来唯一标识一条数据,我们一般也就是通过设定 canal 选择 binlog 所在表的主键来决定其进入 Kafka 的分区。这样,就基本解决了第一个问题。

(2)不同用户的不同订单也有先后之分。

但这只保证了同一订单数据的顺序性,并未保证不同订单之间的顺序性。在 Flink 中,有种机制就叫做 watermark。每一条数据一般都会自带一个时间字段,来标志这条数据的业务时间,即什么时候发生的。然后 Flink 提取这个时间字段,就知道了目前 Flink 任务进行到几点了。在实时的流数据中,如果想要拿到 T 时刻的数据,只要等一小会儿比如 1s,就能保证在 T+1s 的时刻拿到 T 时刻的所有数据。考虑乱序或迟到数据,我们一般也会让 Flink 当前的时间稍微迟几秒钟。

数据湖框架采用批式和流式共存的 Lambda 架构
1 批式模型就是使用 MapReduce、Hive、Spark 等典型的批计算引擎,以小时任务或者天任务的形式来做数据计算。
2 流式模型就是使用 Flink 来进行实时的数据计算。




额外补充

Copy On Write(写时才拷贝):优雅地解决读多写少场景下的并发问题,懒惰行为,拖延战术,每次写文件操作都写在特定大小的一块内存中(磁盘缓存),只有当我们关闭文件时,才写到磁盘上(这就是为什么如果文件不关闭,所写的东西会丢失的原因),更有甚者是文件关闭时都不写磁盘,而一直等到关机或是内存不够时才写磁盘,Unix就是这样一个系统。仅使用列式文件(parquet)存储数据。在写入/更新数据时,直接同步合并原文件,生成新版本的基文件(需要重写整个列数据文件,即使只有一个字节的新数据被提交)。

CopyOnWriteArrayList:总体设计思想是在读的过程中去掉了锁,而在写的过程中则需要引入互斥锁,但是这个锁不会影响到读本身。

通过OS copy-on-write 的过程我们可以总结出两个重要的特性:

  1. 父子进程的内存共享的数据仅仅是fork那一时间点的数据,fork 后的数据不会有任何共享;
  2. 所谓 lazy copy,就是在需要修改的时候拷贝一个副本出来,如果没有任何改动,则不会占用额外的物理内存。

COW核心思想:
如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。

Merge On Read(读时合并):更新被写入到增量日志文件中,该文件以 avro 格式存储。这些增量日志文件始终与基本文件相关联。假设有一个名为 data_file_1 的数据文件,对 data_file_1 中记录的任何更新都将写入到新的增量日志文件。在服务读取查询时,实时合并基础文件及其相应的增量日志文件中的记录。

你可能感兴趣的:(hadoop,big,data,mapreduce)