使用foreachPartition將結果寫入外部存儲

好久沒有寫了!!!記錄一下 :

最近有個小夥伴問我,使用spark處理的數據存入mysql中老是導致mysql鏈接超時或中斷,我看了一下他的代碼,想揍人,

其代碼如下:

dstream.foreachRDD {rdd =>
  rdd.foreachPartition{ partitionRecords =>
  val connection = createNewConnection
  //將結果存入外部存儲系統中
    partitionRecords.foreach(record => connection.send(record))
  }
}

這種方式不可行!!!

最不濟可以這樣寫:

dstream.foreachRDD {rdd =>
  rdd.foreachPartition{ partitionRecords =>
  val connection = createNewConnection
  //將結果存入外部存儲系統中
    partitionRecords.foreach(record => connection.send(record))
	connection.close()  //記得要關閉
  }
}

這樣可以保證每個partition只需要鏈接一次外部存儲系統,最起碼不會造成鎖死等問題,提高了性能,但是並不能使不同的partition直接可以重複利用鏈接,爲了重複利用此鏈接可以使用連接池來解決,使其不同partition之間可以共享鏈接:

dstream.foreachRDD {rdd =>
  rdd.foreachPartition{ partitionRecords =>
  val connection = ConnectionPool.getConnection  //使用連接池使不同partition之間共享鏈接
  //將結果存入外部存儲系統中
    partitionRecords.foreach(record => connection.send(record))
	//重用連接池
	ConnectionPool.returnConnection(connection)
  }
}

提高了效率,又不會阻塞鏈接

另有連接池:

public class ConnectionPool {
    private static LinkedList<Connection> connectionQueue;

    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public synchronized static Connection getConnection() {
        try {
            if (connectionQueue == null) {
                connectionQueue = new LinkedList<Connection>();
                for (int i = 0; i < 5; i++) {
                    Connection conn = DriverManager.getConnection(
                            "jdbc:mysql://ip地址:3306/所處路徑",
                            "username",
                            "password");
                    connectionQueue.push(conn);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connectionQueue.poll();

    }
	
    public  static void returnConnection(Connection conn){connectionQueue.push(conn);}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章