Spark流处理相关知识点(包含:SparkStreaming,Kafka,Flume,HBase)

HBase

  • 优势:
  • 线性扩展
  • 数据存储储在hbase上,备份机制健全
  • 通过zookeeper协调查找数据,访问速度快
  • 特点:
  • 海量存储
  • 列式存储
  • 极易扩展
  • 高并发
  • 稀疏
  • 数据模型

spark 设置 parquet 文件大小 spark文件流_spark

  • ROW KEY
  • 时间戳TimeStamp
  • 列族
  • CELL单元格
  • cell没有类型,全部使用字节码储存
  • HLog
  • 角色
  • HMaster,可以有多个主节点
  • 监控 RegionServer
  • 处理 RegionServer 故障转移
  • 处理元数据的变更
  • 处理 region 的分配或移除
  • 在空闲时间进⾏数据的负载均衡
  • 通过 Zookeeper 发布⾃⼰的位置给客⼾端
  • 多个从节点,HregionServer
  • 负责存储 HBase 的实际数据
  • 处理分配给它的 Region
  • 刷新缓存到 HDFS
  • 维护 HLog
  • 执⾏压缩
  • 负责处理 Region 分⽚
  • 架构
  • 组件说明
  • Write-Ahead logs
  • HBase的修改记录
  • HFile
  • 保存在磁盘的原始数据,是实际的存储文件
  • Store
  • 一个Store对应一个列族,HFile存储在Store中
  • MemStore
  • 内存存储,用来保存当前的数据操作,当数据存在WAL之后,RegionServer 会在内存中存储键值对。
  • Region
  • Hbase 表的分⽚,HBase 表会根据 RowKey 值被切分成不同的 region 存储在 RegionServer 中,在⼀个 RegionServer 中可以有多个不同的 region。
  • HBase JAVA API
  • 表结构操作
  • 初始化
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum","node01:2181,....");
Connection connection = ConnectionFactory.createConnection(conf);
admin = connection.getAdmin();
- 判断表是否存在
TableName tableName = TableName.valueOf("Student");
boolean res = admin.tableExists(tableName);
- 创建表
String tableName = "Test";
String[] columnFamily = {"info","education"};
if(admin.tableExists(TableName.valueOf(tableName))){
    System.out.println("表" + tableName + "已存在");
    //退出 JVM
    System.exit(0);
 }else{
    //创建表属性对象,表名需要转字节
    HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));
    //创建多个列族
    for(String cf : columnFamily){
      descriptor.addFamily(new HColumnDescriptor(cf));
   }
    //根据对表的配置,创建表
    admin.createTable(descriptor);
    //修改表结构
    //admin.modifyTable(TableName.valueOf(tableName),descriptor);
    System.out.println("表" + tableName + "创建成功!");
 }
- 删除表
String tableName = "Test";
  if(admin.tableExists(TableName.valueOf(tableName))){
    //禁用此表
    admin.disableTable(TableName.valueOf(tableName));
    //启用表
    //admin.enableTable(TableName.valueOf(tableName));
    //删除表
    admin.deleteTable(TableName.valueOf(tableName));
    System.out.println("表" + tableName + "删除成功!");
 }else{
    System.out.println("表" + tableName + "不存在!");
 }
- 查询库中所有表
TableName[] ts = admin.listTableNames();
  • 表数据操作
  • 初始化
String tableName = "Student";
    //1. 创建HBase的配置对象
    Configuration conf = HBaseConfiguration.create();
    conf.set("hbase.zookeeper.quorum","node01:2181,node02:2181,node03:2181");
    //2. 创建一个客户端,即连接对象
    conn = ConnectionFactory.createConnection(conf);
    //3. 创建 Table对象
    table = conn.getTable(TableName.valueOf(tableName));
- 添加数据和更新数据
//!!添加单条数据!!

//初始化Put对象,并设置RowKey
Put put = new Put(Bytes.toBytes("10003"));
  //2. 增加列和数据【参数分别为:列族名,列名,列的数据】
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("wangwu"));
  //3. 增加第2列数据
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes("16"));
  //4. 插入数据到表中
table.put(put);

//!!添加多条数据!!
List<Put> puts = new ArrayList<Put>();
Put put1 = new Put(Bytes.toBytes("10002"));

put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("lisi"));
puts.add(put1);
Put put2 = new Put(Bytes.toBytes("10003"));
put.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes("wangwu"));
puts.add(put2);

table.put(puts);
- 删除数据
//1. 创建删除对象,添加 rowKey
  Delete del = new Delete(Bytes.toBytes("10001"));
  //2. 可以向del中添加列信息,以便删除此行的某一列数据【其实就是某一个单元格的数据】
  //如果不添加某一列,则删除该行的全部信息
  del.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"));
  //3. 执行删除操作:也可以像put一样同时删除多个Delete实例
  table.delete(del)
- 查询数据
//!!GET查询!!

//1. 创建 Get 对象
  Get get = new Get(Bytes.toBytes("10001"));
  //2. 设置获取的最大的版本数
  get.setMaxVersions(3);
  //3. 指定获取哪一列的数据
  get.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"));
  //4. 按照 get 实例执行查询操作,获取结果集
  Result res = table.get(get);
  //5. 遍历结果集获取结果 rawCells()获取单元格数组
  for(Cell c:res.rawCells()){
    System.out.print("RowKey: " + new String(CellUtil.cloneRow(c)) + ", ");
    System.out.print("时间戳: " + c.getTimestamp() + ", ");
    System.out.print("列名: " + new String(CellUtil.cloneQualifier(c)) + ", ");
    System.out.println("值: " + new String(CellUtil.cloneValue(c)));
 }

//!!扫描查询!!
String  beginRowKey = "10002";//开始行健
  String endRowKey = "10004";//结束行健
  //1. 创建 Scan 实例
  Scan scan = new Scan();
  //2. 配置 Scan
  //inclusive表示扫描时是否应包括开始行
  scan.withStartRow(Bytes.toBytes(beginRowKey),true);
  //与上面类似,只不过默认是不包含结束行
  scan.withStopRow(Bytes.toBytes(endRowKey));
  scan.setMaxVersions(3);//设置扫描的最大版本数
  //设置缓存行数:较高的缓存值将启用更快的扫描程序,但将使用更多的内存。
  scan.setCaching(20);
  //设置批处理数:在分页查询时有用。注意:使用过滤器时不能使用
  scan.setBatch(10);
  //3. 执行扫描操作
  ResultScanner rs = table.getScanner(scan);
  //4. 遍历结果输出
  for(Result r:rs){
    //遍历每一个 Result
    for(Cell c:r.rawCells()){
      System.out.print("RowKey: " + new String(CellUtil.cloneRow(c)));
      System.out.print("时间戳: " + c.getTimestamp());
      System.out.print("列名: " + new String(CellUtil.cloneQualifier(c)));
      System.out.println("值: " + new String(CellUtil.cloneValue(c)));
   }
 }

//!!过滤查询!!

//1. 创建一个行健过滤器,指定比较运算符和比较器
  //三个参数:运算符,比较器,行健的值
  Filter filter1 = new RowFilter(CompareFilter.CompareOp.LESS_OR_EQUAL,new
BinaryComparator(Bytes.toBytes("10002")));
  //2. 创建 Scan 对象
  Scan scan1 = new Scan();
  scan1.setFilter(filter1);
  ResultScanner rs1 = table.getScanner(scan1);
  for(Result r:rs1){
    System.out.println(r);
 }
  rs1.close();
  System.out.println("---------------------------");
  //3. 创建一个值过滤器
  //三个参数:运算符,比较器,比较的值
  Filter filter2 = new ValueFilter(CompareFilter.CompareOp.EQUAL,new
SubstringComparator("16"));
  Scan scan2 = new Scan();
  scan2.setFilter(filter2);
  ResultScanner rs2 = table.getScanner(scan2);
  //输出数据中等于 8 的值的结果
  for(Result r:rs2){
    System.out.println(r);
 }
  rs2.close();
  System.out.println("---------------------------");
  //4. 创建一个列过滤器
  Filter filter3 = new QualifierFilter(CompareFilter.CompareOp.LESS_OR_EQUAL,new
BinaryComparator(Bytes.toBytes("age")));
  Scan scan3 = new Scan();
  scan3.setFilter(filter3);
  ResultScanner rs3 = table.getScanner(scan3);
  //输出数据中等于 8 的值的结果
  for(Result r:rs3){
    System.out.println(r);
 }
  rs3.close();
  • 协处理器

Flume

  • Flume是一个分布式、可靠、高可用的海量日志聚合系统,支持在系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据的简单处理,并写到各种数据接收方的能力。

spark 设置 parquet 文件大小 spark文件流_kafka_02

  • 特点
  • 可靠性
  • 当节点出现故障时,日志能够被传送到其他节点上而不会丢失。
  • 可恢复性
  • 还是靠Channel。推荐使用FileChannel,事件持久化在本地文件系统里(性能较差)。
  • 三个核心组件:
  • source
  • Source是数据的收集端,负责将数据捕获后进行特殊的格式化,将数据封装到事件(event) 里,然后将事件推入Channel中。
  • channel
  • Channel是连接Source和Sink的组件,大家可以将它看做一个数据的缓冲区(数据队列),它可以将事件暂存到内存中也可以持久化到本地磁盘上, 直到Sink处理完该事件。
  • sink
  • Flume Sink取出Channel中的数据,进行相应的存储文件系统,数据库,或者提交到远程服务器。
  • 其他组件:
  • Agent
  • Agent 是一个 JVM 进程,它以事件的形式将数据从源头送至目的地。Agent 由 Source 、Channel、Sink 三部分组成。
  • Event
  • 数据的传输单元。也就是事件,类似于Java中的bean类。
  • 流的设计
  • 多Flume设计,串联flume
  • 合并设计
  • 多输出设计

Kafka

  • Apache Kafka®是⼀个分布式流平台,是⼀个基于发布/订阅模式的消息队列,主要应⽤于实时流处理领域。
  • 消息队列的两种模式
  • 点对点模式
  • (⼀对⼀,消费者主动拉取数据,消息收到后消息清除)
  • 发布/订阅模式
  • (⼀对多,数据⽣产后,推送给所有订阅者)
  • 为什么使用消息队列
  • 解耦
  • 冗余
  • 扩展性
  • 灵活性
  • 可恢复性
  • 顺序保证
  • 缓冲
  • 异步通信
  • 基本架构
  • Producer
  • 消息生产者
  • Consumer
  • 消息消费者
  • Topic
  • 队列
  • Consumer Group
  • 广播
  • Broker
  • 一个Kafka服务器就是一个broker,一个broker可以容纳多个topic
  • Partition
  • 分区
  • 分区
  • 一个topic可以配置多个Partition,produce发送的消息分发到不同的partition中。consumer接受数据的时候是按照group来接受,kafka确保每个partition只能同一个group中的同一个consumer消费,如果想要重复消费,那么需要其他的组来消费。Zookeerper中保存这每个topic下的每个partition在每个group中消费的offset
  • 分区策略
  • 轮询策略
  • 随机策略
  • 按Key保存策略

SparkStreaming

  • Spark Streaming接收Kafka、Flume、HDFS等各种来源的实时输入数据,进行处理后,处理结构保存在HDFS、DataBase等各种地方。
  • Dstream:Spark Streaming提供了表示连续数据流的、高度抽象的被称为离散流的DStream。Dstream可以看做一组RDDs,即RDD的一个序列。
  • 架构:
  • Master:记录Dstream之间的依赖关系或者血缘关系,并负责任务调度以生成新的RDD
  • Worker:从网络接收数据,存储并执行RDD计算
  • Client:负责向Spark Streaming中灌入数据
  • Spark Streaming 窗口操作:
  • 两个参数:
  • – 窗口总长度(window length):你想计算多长时间的数据
  • – 滑动时间间隔(slide interval):你每多长时间去更新一次
  • SparkStreaming累加器和广播变量
  • 待补充
  • SparkStreaming算子
  • 无状态转化算子
  • map(func)
  • 返回⼀个新的RDD,该RDD由每⼀个输⼊元素经过func函数转换后组成
  • flatMap(func)
  • 类似于map,但是每⼀个输⼊元素可以被映射为0或多个输出元素(所以func应该返回⼀个序列,⽽不是单⼀元素),⼀对多
  • filter(func)
  • 返回⼀个新的RDD,该RDD由经过func函数计算后返回值为true的输⼊元素组成,,过滤数据
  • repartition(numPartitions)
  • 通过创建或减少partition的数量,来改变DStream的并行度
  • union(otherStream)
  • 将源DStream和另一个DStream内元素联合,生成一个新的DStream并返回
  • count()
  • 返回DStream中每个RDD包含的元素数量,并返回以氮元素为内容的RDDs的新DStream
  • reduce(func)
  • countByValue()
  • reduceByKey(func,[numTasks]):
  • join(otherStram,[numTasks])
  • transform(func)
  • 可以对DStream中每个RDD执行RDD=>RDD操作
  • 有状态转化操作:
  • 基于窗口的操作都需要两个参数,窗口时长以及滑动步长,两者必须是StreamContext的批次间隔的整数倍。
  • window()
  • 最简单的窗口操作,它返回一个新的DStream来表示所请求的窗口操作的结果数据。
  • reduceByWindow()&reduceByKeyAndWindow()
  • 对每个窗口更高效的进行归约操作
  • countByWindow&countByValueAndWindow
  • 前者返回一个表示每个窗口中元素个数的DStream
  • 后者返回的DStream则包含窗口中每个值得个数
  • updateStateByKey
  • 解决跨批次维护状态问题
  • 返回一个新状态(sate)的DStream,其每个key的状态由给定的func函数根据先前状态的Key和Key的新值计算而来,每个Key的数据可以用来保存任何状态的数据类型(通常情况下流式计算是无状态的顺序计算方式,这个函数为我们提供了一种记录状态的可能,比如累加网站的点击量的实例,就可以使用该函数很方便地实现)。
  • 常用输出操作(Action算子)
  • print()
  • 打印在Driver节点运行的流式应用中前十条元素
  • saveAsObjectFiles(prefix,[suffix])
  • 将Dstream中的内容以Java序列化对象的序列化文件进行存储
  • saveAsHdoopFiles(prefix,[suffix])
  • 将Dstream中的内容保存为一个hadoop文件,输出到HDFS上。
  • foreachRDD(func)
  • 会将传入的func函数应用在Dstream中的每个RDD上,通常func会将RDD种的数据输出到外部系统中。func需要包含Action操作,以此推动RDDs的运算。

写的不太好,欢迎评论补充~