大数据面试技术点总结

大数据面试题总结

1. MySQL

1.1 三大范式:

  • 第一范式:数据库表的每个列都不可以再拆分的原子数据
  • 第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分
  • 第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键

1.2 事务

  1. 概念
    事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行

  2. 事物的四大特性(ACID):
    A(原子性):
    事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
    C(一致性):
    执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
    I(隔离性):
    并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
    D:(持久性)
    一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

  3. 脏读,幻读,重复读
    1. 脏读:一个事务更新了一份数据,另一个事务此时读取了该数据,第一个事务又执行了回滚操作,导致第二个事务读取了错误的数据,像是遇到了脏东西
    2. 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行或者数据列。
    3. 不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样
    注:不可重复读的重点是修改:两次读到的数据不一样;幻读的重点在于新增或者删除:两次读到的数据行数或者列数不一样

  4. 事务的隔离级别:
    1. READ-UNCOMMITTED(读未提交):
    最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
    2. READ-COMMITTED(读已提交):
    允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
    3. REPEATABLE-READ(可重复读):
    对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
    4. SERIALIZABLE(可串行化):
    最高的隔离级别,完全服从ACID的隔离级别。事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
    注:Mysql 默认采用的可重复读隔离级别 ,Oracle 默认采用的读已提交隔离级别

1.3 mysql数据库数据类型

  1. 数据库类型:数值类型,字符串类型,日期和时间类型
    • 数值类型:
      TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别表示 1 字节、2 字节、3 字节、4 字节、8 字节的整数类型; FLOAT、DOUBLE、DECIMAL 表示小数类型
    • 字符串类型: VARCHAR、CHAR、TEXT、BLOB
    • 时间和日期类型:
      常用于表示日期和时间类型为 DATETIME、DATE 和 TIMESTAMP。
      尽量使用 TIMESTAMP,空间效率高于 DATETIME。
  2. char和vachar的区别:
    • char是定长,vachar是变长。char最长255,vachar最大是24k
    • char会根据声明的字符串长度分配空间,并会使用空格对字符串右边进行尾部填充。所以在检索 CHAR 类型数据时尾部空格会被删除,如保存的是字符串 'char ',但最后查询到的是 ‘char’。又因为长度固定,所以存储效率高于 VARCHAR 类型。但是varchar在存储空间上更省空间。
    • VARCHAR 是根据字符串长度分配存储空间的,在存储方式上,CHAR 对英文字符(ASCII)占用 1 字节,对一个汉字使用用 2 字节。而 VARCHAR 对每个字符均使用 2 字节。
    • 对于经常变更的数据来说,CHAR 比 VARCHAR更好,因为 CHAR 不容易产生碎片。对于非常短的列或固定长度的数据(如 MD5),CHAR 比 VARCHAR 在存储空间上更有效率。

1.4 引擎(都是B+树索引)

  1. Innodb(现在Mysql的默认引擎):
    Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
  2. MyISAM(原本Mysql的默认引擎):
    不提供事务的支持,也不支持行级锁和外键。
  3. MEMARY:
    所有的数据都在内存中,数据的处理速度快,但是安全性不高。
  • MyISAM索引与InnoDB索引的区别?
    • InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
    • InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。
    • MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。
    • InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效。

1.5 索引

  1. 概念:
    索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
    索引是一种数据结构,索引的实现通常使用B树及其变种B+树。索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。
  2. 索引的优点:
    可以大大加快数据的检索速度,这也是创建索引的最主要的原因。通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能
  3. 索引的缺点:
    时间方面、创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;空间方面、索引需要占物理空间。
  4. 索引的分类类型:
    1. 主键索引:
      数据列不允许重复,不允许为null,一个表只能有一个主键
    2. 唯一索引:
      数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
    3. 普通索引:
      基本的索引类型,没有唯一性的限制,允许为null值
    4. 全文索引:
      搜索引擎使用的一种关键技术
  5. 索引的数据结构:
    在MySQL中使用较多的索引有Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为B+树索引。
    对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
  6. 索引设计和创建的原则:
    • 适合索引的列是出现在where子句中的列,或者连接子句中指定的列,较频繁作为查询条件的字段才去创建索引;基数较小的类,索引效果较差,没有必要在此列建立索引;
    • 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可;
    • 定义有外键的数据列一定要建立索引;更新频繁字段不适合创建索引;对于那些查询中很少涉及的列,重复值比较多的列不要建立索引;若是不能有效区分数据的列不适合做索引列
      (如性别,男女未知,最多也就三种,区分度实在太低)
    • 最左前缀原则,最左匹配原则:
      顾名思义,就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
      最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

1.6 B树和B+树的区别:

  1. 在B树中,你可以将键和值存放在内部节点和叶子节点;但在B+树中,内部节点都是键,没有值,叶子节点同时存放键和值;B+树的叶子节点有一条链相连,而B树的叶子节点各自独立。
  2. B树的优点:
    B树可以在内部节点同时存储键和值,因此,把频繁访问的数据放在靠近根节点的地方将会大大提高热点数据的查询效率。这种特性使得B树在特定数据重复多次查询的场景中更加高效。
  3. B+树的优点:
    • 由于B+树的内部节点只存放键,不存放值,因此,一次读取,可以在内存页中获取更多的键,有利于更快地缩小查找范围。
    • B+树的叶节点由一条链相连,因此,当需要进行一次全数据遍历的时候,B+树只需要使用O(logN)时间找到最小的一个节点,然后通过链进行O(N)的顺序遍历即可。而B树则需要对树的每一层进行遍历,这会需要更多的内存置换次数,因此也就需要花费更多的时间
    • B树只适合随机检索,而B+树同时支持随机检索和顺序检索;B+树空间利用率更高,可减少I/O次数,磁盘读写代价更低;B+树的查询效率更加稳定,B树搜索有可能会在非叶子结点结束,只要找到关键字即可确定记录的存在,而在B+树中,顺序检索比较明显,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路

2. hadoop

2.1 hadoop组成

  • hadoop1.x:
    MapReduce:计算+资源调度
    HDFS:数据存储
  • hadoop2.x:
    MapReduce:计算
    HDFS:数据存储
    yarn:资源调度

2.2 HDFS

2.2.1 hdfs集群架构
  1. NameNode(nn):元数据节点
  • 维护和管理文件系统的元数据(元数据:名称空间目录树结构,文件和块的位置信息,访问权限等信息)
  • 监控集群中dataNode的健康状态
  • 处理客户端端读写请求(访问hdfs的唯一入口)
  • 管理数据块(block)的映射信息
  1. Client:HDFS的客户端
  • 切分文件,文件上传到hdfs的时候,client将文件切割成一个一个的block,然后进行存储
  • 与nameNode交互,获取文件的位置信息
  • 与dataNode交互,读取或是写入数据
  • 提供一些命令管理hdfs,比如启动关闭hdfs等
  1. DataNode:数据节点
  • 存储实际的数据块
  • 执行数据块的读|写请求
  1. SecondaryNameNode:备份节点
  • 并不是nameNode的热备,当nameNode挂掉后,不会立马替换nameNode并提供服务
  • 定期合并元数据镜像文件(fsimage)和改动日志(editlog),并推动给nameNode
  • 协助nameNode,分担工作量
  • 在紧急情况下,可辅助恢复nameNode可以对外提供写操作。
2.2.2 HDFD写数据流程
  1. HDFS client创建DistributedFileSystem 对象,通过该对象向 NameNode 请求上传文件,NameNode 检查权限,并判断目目录是否已存在。
  2. 如果权限许可,目标文件也存在,NameNode进行响应,返回可以上传文件。
  3. 客户端向 NameNode 请求第一个 Block 上传到哪几个 DataNode 服务器上。
  4. NameNode 返回 3 个 DataNode 节点(默认副本数为3),分别为 dn1、dn2、dn3。(这一步要考虑服务器是否可用、副本存储节点选择策略、DataNode负载均衡)
  5. 客户端创建FSDataOutputStream数据流对象,通过该对象请求dn1(即DataNode1) 上传(或写)数据(即建立传输通道), dn1 收到请求会继续调用dn2建立通道,然后 dn2 调用 dn3,这样dn1~dn3的通信通道建立完成。
  6. 传输通道建立完成后,dn1、dn2、dn3 逐级应答客户端。
  7. 客户端开始往 dn1 上传第一个 Block (先从磁盘读取数据放到一个本地内存缓存),以Packet为单位(每次发送的是一个Packet对象),dn1 收到一个 Packet (直接从内存中)传给 dn2,dn2 传给 dn3。需要注意的是,这里传输的packet大小是64k。
  8. 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 到服务器。(重复执行 3-7 步)。
  9. 所有的Block传输完毕并确认完成后,HDFS CLient关闭FSDataOutputStream数据流对象。然后,HDFS Client联系NameNode,确认数据写完成,NameNode 在内存中对其元数据进行增删改(然后再通过SecondaryNameNode对元数据进行修改)。注意,此时只是把更新操作记录到编辑日志Editlog,并没有真正合并编辑日志和镜像文件,只有触发checkPoint才合并。
2.2.3 HDFS读数据流程
  1. 客户端向元数据节点(nameNode)发送请求,请求文件block的位置;
  2. 元数据节点(nameNode)收到请求之后会检查用户权限以及是否有这个文件,如果都符合,则会视情况返回部分或全部的block列表
  3. Client选取排序靠前的DataNode来读取block,如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性);
  4. 读取完一个block都会进行checksum验证,如果读取dataNode时出现错误,客户端会通知元数据节点(nameNode)​​​​​​​,然后再从下一个拥有该block副本的dataNode 继续读;
    最终读取来所有的block会合并成一个完整的最终文件返回给客户端

2.3 MapReduce

2.3.1 MapReduce的优缺点
  1. 优点
  • 易于编程
    它简单的实现一些接口,就可以完成一个分布式程序, 这个分布式程序可以分布到大量廉价的 PC 机器上运行。也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点使得 MapReduce 编程变得非常流行。
  • 良好的扩展性
    当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展它的计算能力。
  • 高容错性
    MapReduce 设计的初衷就是使程序能够部署在廉价的 PC 机器上,这就要求它具有很高的容错性。比如其中一台机器挂了,它可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由 Hadoop 内部完成的。
  • 适合 TB/PB 级以上海量数据的离线处理
    可以实现上千台服务器集群并发工作,提供数据处理能力。
  1. 缺点
  • 不擅长实时计算
    MapReduce 无法像 MySQL 一样,在毫秒或者秒级内返回结果。
  • 不擅长流式计算
    流式计算的输入数据是动态的,而 MapReduce 的输入数据集是静态的,不能动态变化。这是因为 MapReduce自身的设计特点决定了数据源必须是静态的。
  • 不擅长 DAG(有向无环图)计算
    多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce 并不是不能做,而是使用后, 每个 MapReduce 作业的输出结果都会写入到磁盘,会造成大量的磁盘 IO,导致性能非常的低下。
2.3.2 MapReduce 的工作流程
  1. 分片、格式化数据源
    输入 Map 阶段的数据源,必须经过分片和格式化操作。
    分片操作:指的是将源文件划分为大小相等的小数据块( Hadoop 2.x 中默认 128MB ),也就是分片( split ),Hadoop 会为每一个分片构建一个 Map 任务,并由该任务运行自定义的 map() 函数,从而处理分片里的每一条记录;
    格式化操作:将划分好的分片( split )格式化为键值对<key,value>形式的数据,其中, key 代表偏移量, value 代表每一行内容。
  2. MapTask
    • Read 阶段:
      MapTask 通过用户编写的 RecordReader ,从输入的 InputSplit 中解析出一个个 key / value 。
    • Map 阶段:
      将解析出的 key / value 交给用户编写的 Map ()函数处理,并产生一系列新的 key / value 。
    • Collect 阶段:
      在用户编写的 map() 函数中,数据处理完成后,一般会调用 outputCollector.collect() 输出结果,在该函数内部,它会将生成的 key / value 分片(通过调用 partitioner ),并写入一个环形内存缓冲区中(该缓冲区默认大小是 100MB )。
    • Spill 阶段:
      即“溢写”,当缓冲区快要溢出时(默认达到缓冲区大小的 80 %),会在本地文件系统创建一个溢出文件,将该缓冲区的数据写入这个文件。将数据写入本地磁盘前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作。写入磁盘之前,线程会根据 ReduceTask 的数量,将数据分区,一个 Reduce 任务对应一个分区的数据。这样做的目的是为了避免有些 Reduce 任务分配到大量数据,而有些 Reduce 任务分到很少的数据,甚至没有分到数据的尴尬局面。如果此时设置了 Combiner ,将排序后的结果进行 Combine 操作,这样做的目的是尽可能少地执行数据写入磁盘的操作。
    • Combine 阶段:
      当所有数据处理完成以后, MapTask 会对所有临时文件进行一次合并,以确保最终只会生成一个数据文件
  3. Shuffle 过程
    MapReduce 工作过程中, Map 阶段处理的数据如何传递给 Reduce 阶段,这是 MapReduce 框架中关键的一个过程,这个过程叫作 Shuffle 。Shuffle 会将 MapTask 输出的处理结果数据分发给 ReduceTask ,并在分发的过程中,对数据按 key 进行分区和排序。
  4. Reduce Task
    • Copy 阶段:
      Reduce 会从各个 MapTask 上远程复制一片数据(每个 MapTask 传来的数据都是有序的),并针对某一片数据,如果其大小超过一定國值,则写到磁盘上,否则直接放到内存中
    • Merge 阶段:
      在远程复制数据的同时, ReduceTask 会启动两个后台线程,分别对内存和磁盘上的文件进行合并,以防止内存使用过多或者磁盘文件过多。
    • Sort 阶段:
      用户编写 reduce() 方法输入数据是按 key 进行聚集的一组数据。
      为了将 key 相同的数据聚在一起, Hadoop 采用了基于排序的策略。
      由于各个 MapTask 已经实现对自己的处理结果进行了局部排序,因此, ReduceTask 只需对所有数据进行一次归并排序即可。
    • Reduce 阶段:
      对排序后的键值对调用 reduce() 方法,键相等的键值对调用一次 reduce()方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到 HDFS 中
    • Write 阶段:
      reduce() 函数将计算结果写到 HDFS 上。
  5. 写入文件
    MapReduce 框架会自动把 ReduceTask 生成的<key, value>传入 OutputFormat 的 write 方法,实现文件的写入操作。
2.3.3 MapReduce 数据倾斜问题
  1. 空值引发的数据倾斜
    • 方法一:异常数据时,空KEY过滤
    • 方法二:非异常数据时,空key转换
      有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。由于null 值关联不上,处理后并不影响最终结果。
set mapreduce.job.reduces = 5;

insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on 
nvl(n.id,rand()) = o.id;
  1. 表连接时引发的数据倾斜
    将倾斜的数据存到分布式缓存中,分发到各个Map任务所在节点。在Map阶段完成join操作,即MapJoin,从而减少了Reduce数据倾斜。
    hive.auto.convert.join=true 默认值为true,自动开启MAPJOIN优化。
    hive.mapjoin.smalltable.filesize=2500000 默认值为2500000(25M),通过配置该属性来确定使用该优化的表的大小,如果表的大小小于此值就会被加载进内存中。
  2. Group By
    如果group by 维度过小, Map 阶段同一 Key 有大量的数据分发给一个 reduce,很容易发生倾斜了。
    两个参数:
    hive.map.aggr=true:在map中会做部分聚集操作,效率更高但需要更多的内存。
    hive.groupby.skewindata=true:数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。
  3. Count(Distinct) 去重统计
    数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题。
  4. 不可拆分大文件引发的数据倾斜
    当集群的数据量增长到一定规模,有些数据需要归档或者转储,这时候往往会对数据进行压缩;当对文件使用GZIP压缩等不支持文件分割操作的压缩方式,在日后有作业涉及读取压缩后的文件时,该压缩文件只会被一个任务所读取。如果该压缩文件很大,则处理该文件的Map需要花费的时间会远多于读取普通文件的Map时间,该Map任务会成为作业运行的瓶颈。这种情况也就是Map读取文件的数据倾斜。
    解决方案:
    这种数据倾斜问题没有什么好的解决方案,只能将使用GZIP压缩等不支持文件分割的文件转为bzip和zip等支持文件分割的压缩方式。或者加大MapTask内存的大小(默认为1G)
    所以,我们在对文件进行压缩时,为避免因不可拆分大文件而引发数据读取的倾斜,在数据压缩的时候可以采用bzip2和Zip等支持文件分割的压缩算法。

2.4 YARN

2.4.1 yarn的组成架构
  1. ResourceManager(RM):
    是整个集群资源(内存、CPU等)的老大,它是整个集群资源的主要协调者和管理者,具体如下:
    • 处理客户端请求
    • 监控NodeManager运行情况,如果某一个节点资源紧张,可以把新的任务分配给别其它闲置的结点
    • 启动或监控ApplicationMaster的任务运行情况,如果某个任务挂了,则可以把任务分配给别的结点执行。
    • 管理整个集群资源的分配与调度
  2. NodeManager(NM)
    是单个节点服务器资源老大,主要负责该节点内所有容器的生命周期的管理,监视资源和跟踪节点健康,具体如下:
    • 启动时向 ResourceManager 注册并定时发送心跳消息,等待 ResourceManager 的指令
    • 维护 Container 的生命周期,监控 Container 的资源使用情况;
    • 管理任务运行时的相关依赖,根据 ApplicationMaster 的需要,在启动 Container 之前将需要的程序及其依赖拷贝到本地。
  3. ApplicationMaster(AM)
    是单个任务运行的老大。在用户提交一个应用程序时,YARN 会通过ResourceManager 启动一个轻量级的进程 ApplicationMaster,通过ApplicationMaster来管理整个任务的运行。ApplicationMaster 作用具体如下:
    • 根据应用的运行状态来决定动态计算资源需求;
    • 向 ResourceManager 申请资源,监控申请的资源的使用情况;
    • 跟踪任务状态和进度,报告资源的使用情况和应用的进度信息;
    • 负责任务的容错。
  4. Container
    是 YARN 中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等。当 ApplicationMaster(AM)向 ResourceManager 申请资源时,RM 为 AM 返回的资源是用 Container 表示的。YARN 会为每个任务分配一个 Container,该任务只能使用该 Container 中描述的资源。ApplicationMaster 可在 Container 内运行任何类型的任务。例如,MapReduce ApplicationMaster 请求一个容器来启动 map 或 reduce 任务,而 Giraph ApplicationMaster 请求一个容器来运行 Giraph 任务。
2.4.2 YARN工作原理

在这里插入图片描述

  1. Client 提交作业到 YARN 上;
  2. Resource Manager 选择一个 NodeManager,启动一个 Container 并运行 Application Master 实例;
  3. Application Master 根据实际需要向 Resource Manager 请求更多的 Container 资源(如果作业很小, 应用管理器会选择在其自己的 JVM 中运行任务);
  4. Application Master 通过获取到的 Container 资源执行分布式计算。

2.5 hadoop小文件问题

2.5.1 Hadoop小文件弊端
  1. HDFS 上每个文件都要在 NameNode 上创建对应的元数据,这个元数据的大小约为150byte,这样当小文件比较多的时候,就会产生很多的元数据文件,一方面会大量占用NameNode 的内存空间,另一方面就是元数据文件过多,使得寻址索引速度变慢。
  2. 小文件过多,在进行 MR 计算时,会生成过多切片,需要启动过多的 MapTask。每个MapTask 处理的数据量小,导致 MapT ask 的处理时间比启动时间还小,白白消耗资源。
2.5.2 Hadoop 小文件解决方案
  1. 在数据采集的时候,就将小文件或小批数据合成大文件再上传 HDFS(数据源头)
  2. Hadoop Archive(存储方向)
    通过HDFS的har归档文件进行归档,它将HDFS中一个个小文件归档成一个文件,对 NameNode 是一个整体,但是其内部实际上还是许多个小文件,减少了 NameNode 的内存。 具体看49题
  3. CombineTextInputFormat(计算方向)
    CombineTextInputFormat 用于将多个小文件在切片过程中生成一个单独的切片或者少量的切片,以减少切片的数量。
  4. 开启 uber 模式,实现 JVM 重用(计算方向)
    默认情况下,每个 Task 任务都需要启动一个 JVM 来运行,如果 Task 任务计算的数据量很小,我们可以让同一个 Job 的多个 Task 运行在一个 JVM 中,不必为每个 Task 都开启一个 JVM。
  5. 使用Sequence file
    sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。 和 HAR 不同的是,这种方式还支持压缩。该方案对于小文件的存取都比较自由,不限制文件的多少,但是 SequenceFile 文件不能追加写入,适用于一次性写入大量小文件的操作。
    注:MapFile 是排序后的 SequenceFile,通过观察其目录结构可以看到 MapFile 由两部分组成,分别是 data 和 index

3. hive

Hive 是基于 Hadoop的一个数据仓库工具,可以将HDFS中的数据文件映射为一张数据库表,并提供类SQL查询功能(HQL),提供快速开发的能力。
Hive本质是将SQL转换为 MapReduce的任务进行运算,从而不必开发专门的MapReduce应用,减少开发人员的学习成本,功能扩展很方便。
Hive 通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的 Driver,结合元数据(MetaStore),将这些指令翻译成 MapReduce,提交到 Hadoop 中执行。最后,将执行返回的结果输出到用户交互接口。

3.1 Hive的架构原理

  1. 用户接口Client:
    Hive可以通过CLI(Command-line Interface,即命令行),JDBC/ODBC( jdbc 访问 hive)、WEBUI(浏览器访问 hive)。
  2. 元数据Metastore:
    Hive的元数据保存在数据库中,Hive中的元数据信息包含表名、表所属的数据库(默认是 default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等。
    Hive元数据默认存储在derby数据库,不支持多客户端访问,所以需要将元数据存储在MySQL中,才支持多客户端访问
  3. 驱动器Driver:
    • 解析器:将 SQL 字符串转换成抽象语法树 AST
    • 编译器:将 AST 编译生成逻辑执行计划
    • 优化器:对逻辑执行计划进行优化
    • 执行器:把逻辑执行计划转换成可以运行的物理计划。对于 Hive 来说,就是 MR/Spark。

3.2 Hive与传统数据库的区别

  • 存储位置:Hive数据存储在HDFS上。数据库保存在块设备或本地文件系统
  • 数据更新:Hive不建议对数据改写。数据库通常需要经常修改
  • 执行引擎:Hive通过MapReduce来实现。数据库用自己的执行引擎+++
  • 执行速度:Hive执行延迟高,但它数据规模远超过数据库处理能力时,Hive的并行计算能力就体现优势了。数据库执行延迟较低
  • 数据规模:hive大规模的数据计算。数据库能支持的数据规模较小
  • 扩展性:Hive建立在Hadoop上,随Hadoop的扩展性。数据库由于ACID语义的严格限制,扩展有限
  • 索引:hive不支持索引,数据库支持索引

3.3 Hive内部表和外部表的区别

  • 存储:外部表数据由HDFS管理;内部表数据由hive自身管理
  • 创建:被external修饰的就是外部表;没被修饰是内部表
  • 删除:删除外部表仅仅删除元数据;删除内部表会删除元数据和存储数据

3.4 Hive中order by,sort by,distribute by和cluster by的区别

  1. order by:对数据进行全局排序,只有一个reduce工作
  2. sort by:每个mapreduce中进行排序,一般和distribute by使用,且distribute by写在sort by前面。当mapred.reduce.tasks=1时,效果和order by一样
  3. distribute by:类似MR的Partition,对key进行分区,结合sort by实现分区排序
  4. cluster by:当distribute by和sort by的字段相同时,可以使用cluster by代替,但cluster by只能是升序,不能指定排序规则

3.5 窗口函数

  • row_number() :增加一个连续的序号 1,2,3,4,5 row_number() over(partition by col1 order by col2 desc) rn
  • rank() :相同的同序号(并列),下一个跳过 1,2,2,2,5 rank() over(partition by col1 order by col2 desc) r
  • dense_rank() :相同的同序号(并列),下一个连续 1,2,2,2,3 dense_rank() over(partition by col1 order by col2 desc) dr
  • current row :当前行
  • n preceding :往前n行 sum(col2) over(partition by col1 rows between 1 preceding and current row) as rs
  • n following :往后n行
  • unbounded preceding :从头开始直到某一行 sum(col2) over(partition by col1 rows between unbounded preceding and current row) as rs
  • unbounded following :从某一行直到终点
  • lag(col,n) :往前第n行的数据 lag(col3) over(partition col1 order by col2)
  • lead(col,n) :往后第n行的数据
  • ntile() :把有序分区中的行分化到n个数据组中,各组的编号从1开始,ntile会返回每行所属的组编号(n为int类型)
select name,orderdate,cost,
    sum(cost) over() as sp1, --所有行相加
    sum(cost) over(partition by name) as sp2, --按名字分组,组内相加
    sum(cost) over(partition by name order by orderdate) as sp3, --按名字分组并按时间排序
    sum(cost) over(partition by name order by orderdate
        rows between unbounded preceding and current row)as sp4,--由起点到当前行的聚合
    sum(cost) over(partition by name order by orderdate
        rows between 1 preceding and current row)as sp5, --由当前一行到当前行的聚合
    sum(cost) over(partition by name order by orderdate
        rows between 1 preceding and 1 following)as sp6, --由当前行到前后一行的聚合
    sum(cost) over(partition by name order by orderdate
        rows between current row and unbouded following)as sp7--由当前行到后面所有行的聚合
from business;

//查看顾客上次和下次的购买时间
select name,orderdate,cost,
    lag(orderdate,1) over(distribute by name sort by orderdate)as sp1,--上次购买时间
    lead(orderdate,1) over(distribute by name sort by orderdate)as sp2--下次购买时间
from business;

//查询前20%时间的订单信息
select * from (
    select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
    from business
) t
where sorted = 1;

3.6 数据倾斜 在实际项目中,主要三种情况会遇到数据倾斜,分别是join操作、group by 操作和count distinct 操作。

  1. Join 倾斜
    • 大表 Join 小表
      • 倾斜原因:主要是热点key导致,在shuffle过程中,相同的key会基于hash分发到同一个reduce算子上,导致join时倾斜。
      • 解决办法:开启map端join: set hive.auto.convert.join = true; 默认是打开的。
        – 开启该设置后,join时会在map端将小表缓存到内存中(缓存为hash table),在map端执行join。
        – 小表默认是 1000行或者25Mb大小。可以通过设置参数提高小表的阈值 :
        set hive.mapjoin.smalltable.filesize=25000000;
    • 大表 Join 大表
      • 倾斜原因:跟大表Join小表倾斜原因差不多,存在热点key,或者大量无用的空key,导致倾斜。
      • 解决办法:
        (1) 运行时优化:
        采用skewjoin(倾斜关联)开启对倾斜数据join的优化:
        set hive.optimize.skewjoin=true;
        然后可以设置join倾斜阈值: set hive.skewjoin.key=100000;
        当join的key对应的记录条数超过100000,就认为这个key发生了数据倾斜,会对其分拆优化。
        (2)编译时优化:
        通过设置: set hive.optimize.skewjoin.compiletime=true;
        可以在编译SQL时将执行计划优化完成。但是,这个需要在建表时指定数据倾斜元数据信息。
        (3) 一般情况下,运行时优化和编译时优化都同时开启,并且要开启union优化:
        set hive.optimize.union.remove=true;
        – 除了以上三个参数外,还可以 * 通过子查询剔除空key 、 空key转为随机字符串 * 、* 大表拆分为小表分别join再union * 等方式进行优化。

3.7 OLAP和OLTP的区别

  • OLAP 联机分析处理:
    从大量的数据中找出某种规律性的东西,用于了解现状并为将来的计划/决策提供数据支撑,所以对多张表的数据进行连接汇总非常普遍。
  • OLTP 联机事务处理:
    OLTP类的操作都比较简单,一般都是对数据库的增删改查,操作主题一般都是产品的用户、OLTP处理的数据量比较少,涉及的表也表少

3.8 数据治理

  1. 脏数据分类
    • 数据缺失:不影响结果的话,不纳入分析范围;设计数据填充
    • 数据重复:进行数据去重就好了
    • 数据错误:根据错误的情况进行认为的处理
    • 数据不可用:从源头解决
  2. 数据治理原则:要有一个公司级的语义字典
    约束输入:输入数据的类型,格式等等,规则要统一
    规范输出:统一语意,口径、计算方式都要一样

3.9 数据模型

事实表、维度表构成了数据仓库中任何模型的基础

  • 事实表:具有与任何业务流程对应的数据。每行代表可以与任何进程关联的任何事件。它存储用于分析的定量信息。
  • 维度表:存储有关如何分析事实表中的数据的数据。它们有助于事实表收集有关将要采取的措施的不同维度。
  1. 星型模型 :
    所有维表都直接连接到 “事实表” 上时,整个图解就像星星一样,故将该模型称为星型模型
  2. 雪花模型:
    当有一个或多个维度表没有直接连接到事实表上,而是通过其他维度表连接到事实表上时,其图解就像多个雪花连接在一起,故称雪花模型
  3. 星座模型:
    星座模型是由星型模型延伸而来,星型模型是基于一张事实表而星座模式是基于多张事实表,并且共享维度表信息,这种模型往往应用于数据关系比星型模型和雪花模型更复杂的场合。 星座模型需要多个事实表共享维度表,因而可以视为星形模型的集合,故亦被称为星系模型

3.10 hive小文件过多的问题

  1. hive小文件产生的原因:
    一般是向hive表中导入数据时候产生
    • insert into:每次插入产生一个小文件
    • load:load 的方式可以导入文件或者文件夹 ,导入一个文件时,hive表就有一个文件;导入一个文件夹时,文件夹中有几个文件,hive就会有几个文件
    • insert as select :这种方式是最常用的也是最容易产生小文件的,insert 会启动MR任务,有多少个reduce就会输出多少个文件
  2. 解决方法:
    • 使用 hive 自带的 concatenate 命令,自动合并小文件:
      alter table A concatenate; alter table B partition(day=20201224) concatenate;
    • 在数据采集的时候,就将小文件或小批数据合成大文件再上传 HDFS(数据源头)
    • Hadoop Archive(存储方向):通过HDFS的har归档文件进行归档,它将HDFS中一个个小文件归档成一个文件,对 NameNode 是一个整体, 但是其内部实际上还是许多个小文件,减少了 NameNode 的内存
    • CombineTextInputFormat(计算方向)
    • 使用Sequence file

3.11 hive中的压缩格式

  1. 行存储:
    • TextFile,默认格式,数据不做压缩,磁盘开销大,数据解析开销大
    • SequenceFile,可以解决存储的小文件的问题;MapFile 是排序后的 SequenceFile
  2. 列存储:
    • RCFile,数据按行分块,每块按列存储。结合了行存储和列存储的优点
    • ORCFile,数据按行分块,每块按照列存储。它是rcfile的改良版本, 效率比rcfile高, 压缩快、快速列存取。
  3. 二进制:
    Parquet 文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此 Parquet 格式文件是自解析的。

3.12 行专列、列转行

行列转换详细内容(包含实例)https://blog.csdn.net/korry24/article/details/126643433

  1. 字段值不发生改变,只是改变行列的分布
  • 行专列
select name,
	sum(case subject when 'Math' then score else 0 end) as Math,
	sum(case subject when 'Chinese' then score else 0 end) as Chinese,
	sum(case subject when 'English' then score else 0 end) as English
from tab_scores
group by name
  • 列转行
select name,'Math',Math from tab_scores
union all
select name,'English',English from tab_scores
union all
select name,'Chinese',Chinese from tab_scores
  1. 字段值进行分割,形成新的行或者列
  • 行转列
 select name,concat_ws(',',collect_set(hobby)) as hobby 
from hobbyInfo group by name
  • 列转行
select a.name,tabHobby.colHobby as hobby from hobbyInfo a
lateral view explode(split(a.hobby,',')) tabHobby as colHobby
-- tabHobby是侧视图的别名,colHobby是解析出来的字段名,#注意,as不能省略

3.13数仓分层架构

数仓分层和建模

4. spark

在这里插入图片描述

4.1 Spark架构

在这里插入图片描述

  1. Driver
    Spark驱动器节点,用于执行Spark任务中的main方法,负责实际代码的执行工作。Driver在Spark作业执行时主要负责:
  • 将用户程序转化为作业(job)
  • 在Executor之间调度任务(task)
  • 跟踪Executor的执行情况
  • 通过UI展示查询运行情况
  1. ApplicationMaster
    用户向YARN集群提交应用程序时,提交程序中应该包含ApplicationMaster,用于向资源调度器申请执行任务的资源容器Container,运行用户自己的程序任务job,监控整个任务的执行,跟踪整个任务的状态,处理任务失败等异常情况。
    说的简单点就是,ResourceManager(资源)和Driver(计算)之间的解耦合靠的就是ApplicationMaster。
  2. Executor
    Spark Executor是集群中工作节点(Worker)中的一个JVM进程,负责在 Spark 作业中运行具体任务(Task),任务彼此之间相互独立。
  3. Master & Worker
    Spark集群的独立部署环境中,不需要依赖其他的资源调度框架,自身就实现了资源调度的功能,所以环境中还有其他两个核心组件:Master和Worker,这里的Master是一个进程,主要负责资源的调度和分配,并进行集群的监控等职责,类似于Yarn环境中的RM, 而Worker呢,也是进程,一个Worker运行在集群中的一台服务器上,由Master分配资源对数据进行并行的处理和计算,类似于Yarn环境中NM。

4.2 Spark的几种部署方式

  1. Local:运行在一台机器上,通常是练手或者测试环境。
  2. Standalone:构建一个基于Mster+Slaves的资源调度集群,Spark任务提交给Master运行。是Spark自身的一个调度系统。
  3. Yarn: Spark客户端直接连接Yarn,不需要额外构建Spark集群。有yarn-client和yarn-cluster两种模式,主要区别在于:yarn-client Driver程序的运行节点是在client;yarn-cluster的Driver程序的运行节点是在随机的一个NodeManager上。

4.3 Spark提交作业的几个参数

  • executor-cores —— 每个executor使用的内核数,默认为1,官方建议2-5个,我们企业是4个
  • num-executors —— 启动executors的数量,默认为2
  • executor-memory —— executor内存大小,默认1G
  • driver-cores —— driver使用内核数,默认为1
  • driver-memory —— driver内存大小,默认512M

4.4 Spark的作业提交流程

Spark的任务提交方式实际上有两种,分别是YarnClient模式和YarnCluster模式。

  1. spark - YarnClient在这里插入图片描述
    Yarn-client模式下作业执行流程:
    1. 客户端提交一个Application,在客户端启动一个Driver进程
    2. 应用程序启动后会向RS(ResourceManager)发送请求,启动AM(ApplicationMaster)的资源
    3. RS收到请求,随机选择一台NM(NodeManager)启动AM。
    4. AM启动后,会向RS请求一批container资源,用于启动Executor
    5. RS会找到一批NM返回给AM,用于启动Executor
    6. AM会向NM发送命令启动Executor
    7. Executor启动后,会反向注册给Driver,Driver发送task到Executor,执行情况和结果返回给Driver端。
  2. spark - YarnCluster
    在这里插入图片描述
    Yarn-cluster模式下作业执行流程:
    1. 客户机提交Application应用程序,发送请求到RS(ResourceManager),请求启动AM(ApplicationMaster)。
    2. RS收到请求后随机在一台NM(NodeManager)上启动AM(相当于Driver端)。
    3. AM启动,AM发送请求到RS,请求一批container用于启动Excutor。
    4. RS返回一批NM节点给AM。
    5. AM连接到NM,发送请求到NM启动Excutor。
    6. Excutor反向注册到AM所在的节点的Driver,Driver发送task到Excutor。

4.5 Spark中血统(RDD)的概念和作用

  1. 概念:
    RDD是弹性分布式数据集,是Spark中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算 的集合。
  2. 作用
    提供了一个抽象的数据模型,将具体的应用逻辑表达为一系列转换操作(函数)。另外不同RDD之间的转换操作之间还可以形成依赖关系,进而实现管道化,从而避免了中间结果的存储,大大降低了数据复制、磁盘IO和序列化开销,并且还提供了更多的API(map/reduec/filter/groupBy…)

4.6 宽窄依赖和stage的划分

  1. 宽窄依赖
  • 窄依赖:父RDD的一个分区只会被子RDD的一个分区依赖
  • 宽依赖:父RDD的一个分区会被子RDD的多个分区依赖(涉及到shuffle)
    (宽依赖的函数有:groupByKey, join(父RDD不是hash-partitioned ), partitionBy)
  1. Stage是如何划分的
    根据RDD之间的依赖关系的不同将Job划分成不同的Stage,遇到一个宽依赖则划分一个Stage。

4.7 Spark常用的transformation和action算子,有哪些算子会导致Shuffle

  • transformation:map,mapRartition,flatMap,filter
  • action:reduce,collect,first,take
  • shuffle:reduceByKey,groupByKey,…

4.8 reduceByKey与groupByKey的区别,哪一种更具优势?

  • reduceByKey:按照key进行聚合,在shuffle之前有combine(预聚合)操作,返回结果是RDD[k,v]。
  • groupByKey:按照key进行分组,直接进行shuffle

所以,在实际开发过程中,reduceByKey比groupByKey,更建议使用

4.9 Repartition和Coalesce 的关系与区别

  • 关系:
    两者都是用来改变RDD的partition数量的,repartition底层调用的就是coalesce方法:coalesce(numPartitions, shuffle = true)
  • 区别:
    repartition一定会发生shuffle,coalesce 根据传入的参数来判断是否发生shuffle。

一般情况下增大rdd的partition数量使用repartition,减少partition数量时使用coalesce。

4.10 Spark中的缓存(cache和persist)与checkpoint机制,并指出两者的区别和联系

  1. 位置
    Persist 和 Cache将数据保存在内存,Checkpoint将数据保存在HDFS
  2. 生命周期
    Persist 和 Cache 程序结束后会被清除或手动调用unpersist方法,Checkpoint永久存储不会被删除。
  3. RDD依赖关系
    Persist 和 Cache,不会丢掉RDD间的依赖链/依赖关系,CheckPoint会斩断依赖链

5. Kafka

5.1 Kafka 架构

整体来看,kafka架构中包含四大组件:生产者、消费者、kafka集群、zookeeper集群
在这里插入图片描述

  1. Producer
    消息生产者,向Broker发送消息的客户端
  2. Consumer
    消息消费者,从Broker读取消息的客户端
  3. ConsumerGroup
    每个Consumer属于一个特定的Consumer Group,一条消息可以发送到多个不同的Consumer Group,但是一个Consumer Group中只能有一个Consumer能够消费该消息
  4. Broker
    消息中间件处理节点,一个Kafka节点就是一个broker,一个或者多个Broker可以组成一个Kafka集群
  5. Topic
    Kafka根据topic对消息进行归类,发布到Kafka集群的每条消息都需要指定一个topic。其实就是将消息按照topic来分类,topic就是逻辑上的分类,同一个topic的数据既可在同一个broker上也可以在不同的broker节点上
  6. Partition
    在这里插入图片描述
    每个topic被物理划分为一个或多个分区,每个分区在物理上对应一个文件夹,该文件夹里面存储了这个分区的所有消息和索引文件。在创建topic时可以指定partition数量,生产者将消息发送到topic时,消息会根据分区策略追加到分区文件的末尾,属于顺序写磁盘,因此效率非常高(经验证,顺序写磁盘效率比随机写内存还要高,这是Kafka高吞吐率的一个很重要的保证)
    Kafka 为我们提供了默认的分区策略,同时它也支持自定义分区策略。kafka允许为每条消息设置一个key,一旦消息被定义了 Key,那么就可以保证同一个 Key 的所有消息都进入到相同的分区。
    同一个partition的数据是有序的,但topic主题下多个partition之间在消费数据时不能保证有序性,在需要严格保证消息顺序性的场景下,可以将partition数设为1,但是这种做法的缺点就是降低吞吐量
    • leader:
      每个partition有多个副本,其中有且仅有一个作为leader,leader会负责所有的客户端读写操作。
    • follower:
      follower不对外提供服务,只与leader保持数据同步,如果leader失效,则选举一个follower来充当新的leader。当follower与leader挂掉、卡住或者同步太慢,leader会把这个follower从ISR列表中删除,重新创建一个follower。
      下图所示,Kafka集群中有4个broker, 某topic有3个partition,且复制因子即副本个数也为3:在这里插入图片描述

5.2 Kafka文件存储机制

5.2.1 分区

在Kafka文件存储中,同一个topic下有多个不同的partition,每个partiton为一个目录,partition的名称规则为:topic名称+有序序号,第一个序号从0开始计,最大的序号为partition数量减1,partition是实际物理上的概念,而topic是逻辑上的概念。假设有4个partition如下图:

drwxr-xr-x 2 root root 4096 Apr 10 16:10 topic_zzh_test-0
drwxr-xr-x 2 root root 4096 Apr 10 16:10 topic_zzh_test-1
drwxr-xr-x 2 root root 4096 Apr 10 16:10 topic_zzh_test-2
drwxr-xr-x 2 root root 4096 Apr 10 16:10 topic_zzh_test-3

partition还可以细分为segment,一个partition物理上由多个segment组成。
segment文件由两部分组成,分别为“.index”文件和“.log”文件,分别表示为segment索引文件和数据文件。这两个文件的命令规则为:partition全局的第一个segment从0开始,后续每个segment文件名为上一个segment文件最后一条消息的offset值,数值大小为64位,20位数字字符长度,没有数字用0填充,如下:

00000000000000000000.index
00000000000000000000.log
00000000000000170410.index
00000000000000170410.log
00000000000000239430.index
00000000000000239430.log

.index”索引和.log数据文件对应关系应下图所示:
在这里插入图片描述

5.2.2 副本

为了提高消息的可靠性,Kafka每个topic的partition有N个副本(replicas),其中N(大于等于1)是topic的复制因子(replica fator)的个数。其中一个为leader,其他为follower,leader处理partition的所有读写请求,包括producer的生产数据和cosumer的消费数据都是跟leader交互的。其他follower都会从leader复同步数据。
如下图所示,Kafka集群中有4个broker, 某topic有3个partition,且复制因子即副本个数也为3
在这里插入图片描述
每个 broker 都有消费者拉取消息,每个 broker 也都有生产者发送消息,每个 broker 上的读写负载都是一样的,这也说明了 kafka 独特的架构方式可以通过主写主读来实现负载均衡。

5.3 ISR

Kafka常见的面试题

  1. AR,ISR,OSR
    Leader 负责维护和跟踪 ISR 集合中所有 Follower 副本的滞后状态,当 Follower 副本落后过多时,就会将其放入 OSR 集合,当 Follower 副本追上了 Leader 的进度时,就会将其放入 ISR 集合。
  • AR:
    分区中的所有 Replica 统称为 AR
  • ISR:
    副本同步队列,所有与 Leader 副本保持一定程度同步的Replica(包括 Leader 副本在内)组成 ISR,由leader维护ISR列表
  • OSR:
    与 Leader 副本同步滞后过多的 Replica 组成了 OSR
  1. HW,LEO
  • HW
    HW俗称高水位,HighWatermark的缩写,取一个partition对应的ISR中最小的LEO作为HW,consumer最多只能消费到HW所在的位置。另外每个replica都有HW,leader和follower各自负责更新自己的HW的状态。对于leader新写入的消息,consumer不能立刻消费,leader会等待该消息被所有ISR中的replicas同步后更新HW,此时消息才能被consumer消费。这样就保证了如果leader所在的broker失效,该消息仍然可以从新选举的leader中获取。
  • LEO
    LogEndOffset的缩写,表示每个partition的log最后一条Message的位置
    在这里插入图片描述
    如上图是一个分区日志文件
    标识共有7条消息,offset (消息偏移量)分别是0~6
    0 代表这个日志文件的开始
    HW(High Watermark) 为4,0~3 代表这个日志文件可以消费的区间,消费者只能消费到这四条消息
    LEO 代表即将要写入消息的偏移量 offset

5.4 数据可靠性和持久性保证(ACK)

当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别:

  • 1(默认):这意味着producer在ISR中的leader已成功收到数据并得到确认。如果leader宕机了,则会丢失数据。
  • 0:这意味着producer无需等待来自broker的确认而继续发送下一批消息。这种情况下数据传输效率最高,但是数据可靠性确是最低的。
  • -1:producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。但是这样也不能保证数据不丢失,比如当ISR中只有leader时(前面ISR那一节讲到,ISR中的成员由于某些情况会增加也会减少,最少就只剩一个leader),这样就变成了acks=1的情况。

5.5 Kafka的作用

  1. 解耦:
    允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
  2. 冗余:
    消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
  3. 扩展性:
    因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。
  4. 灵活性 & 峰值处理能力:
    在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
  5. 可恢复性:
    系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
  6. 顺序保证:
    在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(Kafka 保证一个 Partition 内的消息的有序性)
  7. 缓冲:
    有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
  8. 异步通信:
    很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。

6. hbase

6.1 Hbase架构

在这里插入图片描述

  1. HMaster
    负责管理 RegionServer,实现其负载均衡;
    管理和分配 Region,比如在 Region split时分配新的 Region,在 RegionServer 退出时迁移其内的 Region 到其他 RegionServer上;
    管理namespace和table的元数据(实际存储在HDFS上);
    权限控制(ACL)。

  2. HRegionServer
    存放和管理本地 Region;
    读写HDFS,管理Table中的数据;
    Client 从 HMaster 中获取元数据,找到 RowKey 所在的 RegionServer 进行读写数据。

    下面给大家详细介绍下 Region Serve数据存储的基本结构,如下图所示。一个 Region Server 是包含多个 Region 的,这里仅展示一个。
    在这里插入图片描述

  • Region:
    每一个 Region 都有起始 RowKey 和结束 RowKey,代表了存储的Row的范围,保存着表中某段连续的数据。一开始每个表都只有一个 Region,随着数据量不断增加,当 Region 大小达到一个阀值时,Region 就会被 Regio Server 水平切分成两个新的 Region。当 Region 很多时,HMaster 会将 Region 保存到其他 Region Server 上。
  • Store:
    一个 Region 由多个 Store 组成,每个 Store 都对应一个 Column Family, Store 包含 MemStore 和 StoreFile。
  • MemStore:作为HBase的内存数据存储,数据的写操作会先写到 MemStore 中,当MemStore 中的数据增长到一个阈值(默认64M)后,Region Server 会启动 flasheatch 进程将 MemStore 中的数据写人 StoreFile 持久化存储,每次写入后都形成一个单独的 StoreFile。当客户端检索数据时,先在 MemStore中查找,如果MemStore 中不存在,则会在 StoreFile 中继续查找。
  • StoreFile:MemStore 内存中的数据写到文件后就是StoreFile,StoreFile底层是以 HFile 的格式保存。HBase以Store的大小来判断是否需要切分Region。
    当一个Region 中所有 StoreFile 的大小和数量都增长到超过一个阈值时,HMaster 会把当前Region分割为两个,并分配到其他 Region Server 上,实现负载均衡。
  • HFile:HFile 和 StoreFile 是同一个文件,只不过站在 HDFS 的角度称这个文件为HFile,站在HBase的角度就称这个文件为StoreFile。
  • HLog:负责记录着数据的操作日志,当HBase出现故障时可以进行日志重放、故障恢复。例如,磁盘掉电导致 MemStore中的数据没有持久化存储到 StoreFile,这时就可以通过HLog日志重放来恢复数据。
  1. ZooKeeper
    存放整个 HBase集群的元数据以及集群的状态信息;
    实现HMaster主从节点的failover。
  2. HDFS
    HDFS 为 HBase 提供最终的底层数据存储服务,同时为 HBase 提供高可用的支持。

6.2 Hbase逻辑结构和物理存储结构

在这里插入图片描述
在这里插入图片描述

6.3 hbase数据模型

在这里插入图片描述

  1. Name Space
    命名空间,类似于关系型数据库的 DatabBase 概念,每个命名空间下有多个表。HBase 有两个自带的命名空间,分别是 hbase 和 default,hbase 中存放的是 HBase 内置的表,default 表是用户默认使用的命名空间。
  2. Region
    HBase 将表中的数据基于 RowKey 的不同范围划分到不同 Region 上,每个Region都负责一定范围的数据存储和访问。每个表一开始只有一个 Region,随着数据不断插入表,Region 不断增大,当增大到一个阀值的时候,Region 就会等分成两个新的 Region。当table中的行不断增多,就会有越来越多的 Region。
    另外,Region 是 Hbase 中分布式存储和负载均衡的最小单元,不同的 Region 可以分布在不同的 HRegion Server上。但一个Hregion是不会拆分到多个server上的。
  3. Row
    HBase 表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey 的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以 RowKey 的设计十分重要。
  4. .RowKey
    RowKey的概念与关系型数据库中的主键相似,HBase 使用 RowKey 来唯一标识某行的数据。
    访问 HBase 数据的方式有三种:
    • 基于 RowKey的单行查询;
    • 基于RowKey的范围查询;
    • 全表扫描查询。
  5. Column Family
    Column Family 即列族,HBase 基于列划分数据的物理存储,一个列族可以包含包意多列。
    一般同一类的列会放在一个列族中,每个列族都有一组存储属性:
    是否应该缓存在内存中;
    数据如何被压缩或行键如何编码等。
    HBase 在创建表的时候就必须指定列族。HBase的列族不是越多越好,官方荐一个表的列族数量最好小于或者等于3,过多的列族不利于 HBase 数据的管理和索引。
  6. Column
    HBase 中的每个列都由 Column Family (列族)和 Column Qualifier(列限定符)进行限定,例如 info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义。
  7. Time Stamp
    用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入 HBase 的时间。
  8. Cell
    由{rowkey, column Family:column Qualifier, time Stamp}唯一确定的单元。cell 中的数据是没有类型的,全部是字节码形式存储。

6.4 Hbase写流程

在这里插入图片描述

  1. Client 先访问 zookeeper;获取 元数据位于哪个 Region Server。
  2. 访问返回的Region Server;查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 Region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
  3. HBase Client 向 Region Server 发送写 Hlog 请求,将数据顺序写入(追加)到 HLog。;Region Server 会通过顺序写入磁盘的方式,将 Hlog 存储在 HDFS 上。
  4. 将数据写入对应的 MemStore,数据会在 MemStore 进行排序。
  5. 当写 Hlog 和写 MemStore 的都成功完成之后,将反馈给 HBase Client。
  6. 等达到 MemStore 的刷写时机后,将数据刷写到 HFile
    刷写时机:
    1. 当某个 memstroe 的大小达到了 阈值,其所在 region 的所有 memstore 都会刷写。
    2. 当 region server 中 memstore 的总大小达到阈值,region 会按照其所有 memstore 的大小顺序(由大到小)依次进行刷写
    3. 到达自动刷写的时间,也会触发 memstore flush。
    4. 当 WAL 文件的数量超过阈值(已废弃,无需手动设置)

6.5 Hbase读流程

在这里插入图片描述

  1. HBase Client 请求 ZooKeeper 获取元数据表所在的 Region Server的地址。
  2. HBase Client 请求 RegionServer 获取需要访问的元数据,查询出目标数据位于哪个 Region Server 中的哪个 Region 中。并将该 table 的 region 信息以 及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
  3. HBase Client 请求数据所在的 Region Server,获取所需要的数据。 Region 首先在 MemStore 中查找,若命中则返回;如果在MemStore 中找不到,则通过 BloomFilter 判断数据是否存在;如果存在,则在:StoreFile 中扫描并将结果返回客户端。

6.6 StoreFile Compaction

由于 memstore 每次刷写都会生成一个新的 HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的 HFile 中,因此查询时需要遍历所有的 HFile。为了减少 HFile 的个数,以及清理掉过期和删除的数据,会进行 StoreFile Compaction。
Compaction 分为两种,分别是 Minor Compaction 和 Major Compaction。Minor Compaction 会将临近的若干个较小的 HFile 合并成一个较大的 HFile,但不会清理过期和删除的数据。Major Compaction 会将一个Store 下的所有的 HFile 合并成一个大 HFile,并且会清理掉过期和删除的数据
在这里插入图片描述

6.7 Region Split

默认情况下,每个 Table 起初只有一个 Region,随着数据的不断写入,Region 会自动进行拆分。刚拆分时,两个子 Region 都位于当前的 Region Server,但处于负载均衡的考虑,HMaster 有可能会将某个 Region 转移给其他的 Region Server。
Region Split 时机:
1.当1 个 region 中的某个 Store 下所有 StoreFile 的总大小超过hbase.hregion.max.filesize,该Region 就会进行拆分(0.94 版本之前)。
2. 当1 个 region 中的某个 Store 下所有 StoreFile 的总大小超过Min(R^2 * “hbase.hregion.memstore.flush.size”,hbase.hregion.max.filesize"),该Region 就会进行拆分,其中 R 为当前 Region Server 中属于该 Table 的个数(0.94 版本之后)。
在这里插入图片描述

7. flink

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值