Приложение My Spark Streaming хранит данные в MongoDB.

К сожалению, каждый рабочий Spark открывает слишком много соединений при сохранении его в MongoDB

enter image description here

Ниже приведен мой код Spark - код Mongo DB:

public static void main(String[] args) {

    int numThreads = Integer.parseInt(args[3]);
    String mongodbOutputURL = args[4];
    String masterURL = args[5];

    Logger.getLogger("org").setLevel(Level.OFF);
    Logger.getLogger("akka").setLevel(Level.OFF);

//    Create a Spark configuration object to establish connection between the application and spark cluster
    SparkConf sparkConf = new SparkConf().setAppName("AppName").setMaster(masterURL);

    // Configure the Spark microbatch with interval time
    JavaStreamingContext jssc = new JavaStreamingContext(sparkConf, new Duration(60*1000));

    Configuration config = new Configuration();
    config.set("mongo.output.uri", "mongodb://host:port/database.collection");

//    Set the topics that should be consumed from Kafka cluster
    Map<String, Integer> topicMap = new HashMap<String, Integer>();
    String[] topics = args[2].split(",");
    for (String topic: topics) {
      topicMap.put(topic, numThreads);
    }

//    Establish the connection between kafka and Spark
    JavaPairReceiverInputDStream<String, String> messages =
            KafkaUtils.createStream(jssc, args[0], args[1], topicMap);

    JavaDStream<String> lines = messages.map(new Function<Tuple2<String, String>, String>() {
      @Override
      public String call(Tuple2<String, String> tuple2) {
        return tuple2._2();
      }
    });

    JavaPairDStream<Object, BSONObject> save = lines.mapToPair(new PairFunction<String, Object, BSONObject>() {
        @Override
        public Tuple2<Object, BSONObject> call(String input) {
            BSONObject bson = new BasicBSONObject();
            bson.put("field1", input.split(",")[0]);
            bson.put("field2", input.split(",")[1]);
            return new Tuple2<>(null, bson);
        }
    });
    // Store the records in database    
    save.saveAsNewAPIHadoopFiles("prefix","suffix" ,Object.class, Object.class, MongoOutputFormat.class, config);

    jssc.start();
    jssc.awaitTermination();
  }

Как контролировать количество подключений у каждого рабочего?

Мне не хватает каких-либо параметров конфигурации?

Обновление 1:

Я использую Spark 1.3 с Java API.

Мне не удалось выполнить coalesce(), но я смог выполнить операцию repartition(2).

Сейчас никакие связи не контролировались.

Но я думаю, что соединения не закрываются или не используются повторно на worker.

Пожалуйста, найдите скриншот ниже:

Интервал потоковой передачи 1 минута и 2 раздела введите описание изображения здесь

3
Vijay Innamuri 23 Дек 2015 в 17:14

2 ответа

Лучший ответ

Мне удалось решить проблему с помощью foreachRDD.

Я устанавливаю соединение и закрываю его после каждого DStream.

myRDD.foreachRDD(new Function<JavaRDD<String>, Void>() {
            @Override
            public Void call(JavaRDD<String> rdd) throws Exception {
                rdd.foreachPartition(new VoidFunction<Iterator<String>>() {
                    @Override
                    public void call(Iterator<String> record) throws Exception {
                MongoClient mongo = new MongoClient(server:port);
                DB db = mongo.getDB(database);
                DBCollection targetTable = db.getCollection(collection);
                BasicDBObject doc = new BasicDBObject();
                while (record.hasNext()) {
                    String currentRecord = record.next();
                    String[] delim_records = currentRecord.split(",");
                    doc.append("column1", insert_time);
                    doc.append("column2", delim_records[1]);
                    doc.append("column3",delim_records[0]);
                    targetTable.insert(doc);
                    doc.clear();                        
                }
                mongo.close();                  
                }
                });
                return null;
            }
        });
0
Vijay Innamuri 13 Янв 2016 в 05:55

Вы можете попробовать разделить карту, которая работает на уровне раздела, а не на уровне записи, т.е. задача, выполняемая на одном узле, будет совместно использовать одно соединение с базой данных, а не для каждой записи.

Также я думаю, вы можете использовать предварительный раздел (а не поток RDD). Spark достаточно умен, чтобы использовать это для уменьшения перетасовки.

0
xuanyue 23 Дек 2015 в 18:53