一.引言:

 

Spark Streaming 支持通过 Receiver 自定义数据流,实现之后由于接受客户端的不稳定时常造成streaming程序的崩溃,最早的想法是在Receiver实现中加入try catch,通过异常处理使得数据不会中断,但是Receiver整体的中断还是会迫使程序退出,不受Reciver内部的Try Catch控制,所以需要新的策略重启Receiver,好在Spark官方早就给出了解决方案,下面看看怎么使用。

二.源码:

Spark Doc中共有三种restart方案,可以根据自己的需求选择,不过大同小异主要的诉求就是Receiver出问题后重启:

1.Dirver接收消息

def restart(message: String): Unit
Restart the receiver. This method schedules the restart and returns immediately. 
The stopping and subsequent starting of the receiver (by calling onStop() and 
onStart()) is performed asynchronously in a background thread. The delay between 
the stopping and the starting is defined by the Spark configuration 
spark.streaming.receiverRestartDelay. The message will be reported to the driver.

重新启动接收器。此方法安排重新启动并立即返回。接收器的停止和随后的启动(通过调用onStop()和onStart())是在后台线程中异步执行的。停止和启动之间的延迟由spark配置定义spark.streaming.receiverRestartDelay. 消息将报告给Dirver端。

2.Diver接收消息+异常

def restart(message: String, error: Throwable): Unit
Restart the receiver. This method schedules the restart and returns immediately. 
The stopping and subsequent starting of the receiver (by calling onStop() and 
onStart()) is performed asynchronously in a background thread. The delay between 
the stopping and the starting is defined by the Spark configuration 
spark.streaming.receiverRestartDelay. The message and exception will be reported to 
the driver.

重新启动接收器。此方法安排重新启动并立即返回。接收器的停止和随后的启动(通过调用onStop()和onStart())是在后台线程中异步执行的。停止和启动之间的延迟由spark配置定义spark.streaming.receiverRestartDelay. 消息和异常将报告给Dirver端。

3.直接重启

def restart(message: String, error: Throwable, millisecond: Int): Unit
Restart the receiver. This method schedules the restart and returns immediately. 
The stopping and subsequent starting of the receiver (by calling onStop() and 
onStart()) is performed asynchronously in a background thread.

重新启动接收器。此方法安排重新启动并立即返回。接收器的停止和随后的启动(通过调用onStop()和onStart())是在后台线程中异步执行的。

三.实现

之前实现过Demo版本的Receiver,如果想了解可以参考Spark 自定义Receiver

主要改动在Reveriver内部的 onStart()方法 和 onStop()方法:

1.onStart()

Old Version:

老版本直接起了一个线程去执行接收数据,异常处理在receiver中。

def onStart(): Unit = {
      new Thread() {
        override def run(): Unit = {
          receive()
        }
      }.start()
    }

New Version:

为了增加鲁棒性,需要在onStart方法中加入异常处理,并调用restart恢复。这里使用了第二种restart方法,将消息与异常传回dirver。

def onStart(): Unit = {
      new Thread() {
        override def run(): Unit = {
          try {
            receive()
          } catch {
            case e: ConnectException => {
              restart("Connect Failed...", e)
            }
            case t: Throwable => {
              restart("Error receiving data...", t)
            }
          }
        }
      }.start()
    }

2.onStop()

Old Version:

之前实现的onStop出现异常就直接退出了,所以程序经常会终止。

def onStop: Unit = {
      if (Thread.currentThread.isInterrupted) {
        sys.exit(1)
      }
    }

New Version:

修改后取消了直接退出的逻辑,新增了report逻辑,这里类似restart向dirver汇总数据一样,可以在report内定义自己的汇报逻辑,当然也可以不实现任何方法。

def onStop: Unit = {
      report()
    }

四.效果

经过 onStrat() 新增重启机制 和 onSrop() 的取消退出机制+回传机制,Streaming稳定性得到保障。可以看到图中接收数据有明显的跃阶,其中的间隔就是上面提到的 spark.streaming.receiverRestartDelay 参数定义的,可以自定义也可以使用默认,换到之前逻辑跃阶处会导致Streaming程序异常退出,数据的完整性将受到影响。其次restart的调用位置可以放在receiver()函数内,也可以放在onStart()函数内,区别不是很大,因为三种restart方法都会异步重新调用onStop()和onStart(),所以将restart逻辑写在receiver函数逻辑内应该也没有问题,有需求的同学可以尝试~

spark 重新设置Conf spark重启命令_streaming