好久沒有寫了!!!記錄一下 :
最近有個小夥伴問我,使用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);}
}