spark版本定制四:Spark Streaming的Exactly-One的事务处理

本期内容:

1、Exactly once

2、输出不重复

 事务概念:比如银行转账,数据一定会被处理,且只被处理一次,能够输出,且只能输出一次,A转账给B只输出一次,B接收且只接收一次,双方要么同时成功或者同时失败!

一、Exactly once

Spark Core是怎么处理一个Job的?具体过程如下图所示:

 

流程说明:InputStream不断的输入数据,Executor中的Reciver不停的接收数据,为了保证接收到的数据不丢失,Receiver把接收到数据通过BlockManager写入内存和磁盘,或者通过WAL机制记录日志,然后把元数据metedata信息汇报给Driver,Driver收到数据后,为了数据安全,在运行前会把元数据写入磁盘或者HDFS上(checkpointer),最后真正执行Job是在Executor,当然可以有多个Executor;

可能出现的问题:

      问题:Receiver中接收到的数据达到一定的阈值后,才会触发WAL,如果数据收到一半,Receiver挂掉了,也会存在数据丢失的可能?

      解决:通过Kafka发送数据给Receiver,如果Receiver挂掉,数据会缓存在Kafka中,待Receiver恢复后,会重新接收到Kafka中的数据;

 

数据丢失及其具体的解决方式:

在Receiver收到数据且通过Driver的调度Executor开始计算数据的时候如果Driver突然崩溃,则此时Executor会被Kill掉,那么Executor中的数据就会丢失,此时就必须通过例如WAL的方式让所有的数据都通过例如HDFS的方式首先进行安全性容错处理,此时如果Executor中的数据丢失的话就可以通过WAL恢复回来;

 

Exactly Once的事务处理:

1,数据零丢失:必须有可靠的数据来源和可靠的Receiver,且整个应用程序的metadata必须进行checkpoint,且通过WAL来保证数据安全;

2,Spark Streaming 1.3的时候为了避免WAL的性能损失和实现Exactly Once而提供了Kafka Direct API,把Kafka作为文件存储系统!!!此时兼具有流的优势和文件系统的优势,至此,Spark Streaming+Kafka就构建了完美的流处理世界!!!所有的Executors通过Kafka API直接消费数据,直接管理Offset,所以也不会重复消费数据;实务实现啦!!!此时数据在Kafka中所以一定会被处理,且只被处理一次;

 

为什么说Spark Streaming+Kafka的方式是完美的呢?

1.数据不需要拷贝副本;

2.不需要进行WAL,避免了不必要的性能损耗;

3.Kafka比Hdfs高效很多,因为Kafka内部会进行memory-copy;

 

二、输出不重复

为了解决第一点中出现的各类问题,演变出了如下的架构图:

 

数据重复读取的情况:

在Receiver收到数据且保存到了HDFS等持久化引擎但是没有来得及进行updateOffsets,此时Receiver崩溃后重新启动就会通过管理Kafka的ZooKeeper中元数据再次重复读取数据,但是此时SparkStreaming认为是成功的,但是Kafka认为是失败的(因为没有更新offset到ZooKeeper中),此时就会导致数据重新消费的情况。

现在Zookeeper和Kafka都很成熟了,所以数据重复读取的情况出现的概率较小;

 

问题:数据重复消费的问题怎么解决?

答:可以在程序中处理,程序读取到元数据后,放入内存数据库中,每次处理的时候读取内存数据库,处理过后打个标记,下次再处理的时候通过标记判断,已处理的就不再处理

      第一点中的“Exactly Once的事务处理”第二小点,Spark Streaming 1.3的时候为了避免WAL的性能损失和实现Exactly Once而提供了Kafka Direct API,天然的解决了数据重复消费的问题;

 

性能损失:

1,通过WAL方式会极大的损伤Spark Streaming中Receivers接受数据的性能;(实际生产环境中,用Receiver的情况并不多,更多的是直接基于Kafka  API进行处理)

2,如果通过Kafka的作为数据来源的话,Kafka中有数据,然后Receiver接受的时候又会有数据副本,这个时候其实是存储资源的浪费;

 

关于Spark Streaming数据输出多次重写及其解决方案:

1,为什么会有这个问题,因为Spark Streaming在计算的时候基于Spark Core,Spark Core天生会做以下事情导致Spark Streaming的结果(部分)重复输出:

  Task重试;

  慢任务推测

  Stage重复;

  Job重试;

2,具体解决方案:

  设置spark.task.maxFailures次数为1;最大允许失败的次数,设为1就没有task、stage、job等的重试;

  设置spark.speculation为关闭状态(因为慢任务推测其实非常消耗性能,所以关闭后可以显著提高Spark Streaming处理性能)

  Spark Streaming on Kafka的话,Job失败会导致任务失败,Job失败后可以设置auto.offset.reset为“largest”的方式;

 

最后再次强调可以通过transform和foreachRDD基于业务逻辑代码进行逻辑控制来实现数据不重复消费和输出不重复!这两个方式类似于Spark Streaming的后门,可以做任意想象的控制操作!

 

特别感谢王家林老师的独具一格的讲解:

王家林老师名片:

中国Spark第一人

新浪微博:http://weibo.com/ilovepains

微信公众号:DT_Spark

博客:http://blog.sina.com.cn/ilovepains

QQ:1740415547

YY课堂:每天20:00现场授课频道68917580

posted on 2016-05-07 16:58  Harvey.Sun  阅读(212)  评论(0编辑  收藏  举报

导航