在Spark Streaming作业中启动一次JDBC连接

时间:2017-01-06 12:12:29

标签: java apache-spark spark-streaming hazelcast

环境

  • 从Kafka读取Spark Streaming作业,微批量大小30秒(Durations.seconds(30))
  • 具有参考状态的内存存储(Hazelcast)。这是一个非静态状态,由Spark Workers实时更新
  • 与Hazelcast相关的Spark Workers

当前方法   - 使用kafkaStream.foreachRDD (new VoidFunction<JavaRDD<String>>() { @Override public void call(JavaRDD<String> microBatch) throws Exception { ClientConfig clientConfig = new ClientConfig(); clientConfig.addAddress("myHost:5701"); //Define connection HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig); //Do processing } } 对数据进行操作,并为每个微批(RDD)建立连接。这种情况每30秒发生一次(Durations.seconds(30))。

COPY atomic.events 
FROM 's3://path-to/bucket/THE_FILE_NAME.extension' 
CREDENTIALS 'aws_access_key_id=xxx;aws_secret_access_key=xxx' 
REGION AS 'eu-west-1' 
DELIMITER '\t' 
MAXERROR 1 
EMPTYASNULL 
FILLRECORD 
TRUNCATECOLUMNS 
TIMEFORMAT 'auto' 
ACCEPTINVCHARS 
LZOP;

提问:想要在每个Spark工作者上打开一次连接(提交作业时),而不是每个微批次的新连接。什么是实现这一目标的正确方法?

2 个答案:

答案 0 :(得分:0)

由于Spark序列化作业并将其分发到Workers,因此重写反序列化方法以执行 init 任务(创建JDBC连接,初始化变量等)有助于Spark Streaming。

覆盖默认反序列化方法(Java)

@Override
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
                in.defaultReadObject();
        //Init 1
            ClientConfig clientConfig = new ClientConfig();
            clientConfig.addAddress("myHost:5701");    //Define connection
            HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);
       //Init 2
            kafkaProducer=new KafkaProducer<>(kafkaProducerProps);
            }

或者,可以使用static hack进行初始化任务,直到Cloudera / Databricks人员添加init support inherently in Spark

答案 1 :(得分:0)

您需要的信息在这里得到了很好的解释: https://spark.apache.org/docs/latest/streaming-programming-guide.html#design-patterns-for-using-foreachrdd

dstream.foreachRDD { rdd =>
  rdd.foreachPartition { partitionOfRecords =>
    // ConnectionPool is a static, lazily initialized pool of connections
    val connection = ConnectionPool.getConnection()
    partitionOfRecords.foreach(record => connection.send(record))
    ConnectionPool.returnConnection(connection)  // return to the pool for future reuse
  }
}

在foreachPartition中,主体在执行程序中本地执行。在那里,您可以建立静态客户端连接(例如,每个工作人员将使用其自己的静态对象)

希望对您有帮助。

谢谢