Amazon web services 在spark MapTask中调用http请求和读取inputstream的有效方法是什么
请参阅下面的代码示例Amazon web services 在spark MapTask中调用http请求和读取inputstream的有效方法是什么,amazon-web-services,apache-spark,amazon-s3,java-7,Amazon Web Services,Apache Spark,Amazon S3,Java 7,请参阅下面的代码示例 JavaRDD<String> mapRDD = filteredRecords .map(new Function<String, String>() { @Override public String call(String url) throws Exception { BufferedReader in = nul
JavaRDD<String> mapRDD = filteredRecords
.map(new Function<String, String>() {
@Override
public String call(String url) throws Exception {
BufferedReader in = null;
URL formatURL = new URL((url.replaceAll("\"", ""))
.trim());
try {
HttpURLConnection con = (HttpURLConnection) formatURL
.openConnection();
in = new BufferedReader(new InputStreamReader(con
.getInputStream()));
return in.readLine();
} finally {
if (in != null) {
in.close();
}
}
}
});
这段代码非常慢。IP和端口是随机的,负载是分布式的,所以IP可以有20个不同的端口值,所以我看不到瓶颈
当我评论
in = new BufferedReader(new InputStreamReader(con
.getInputStream()));
return in.readLine();
代码太快了。
注:要处理的输入数据为10GB。使用spark从S3读取数据
BufferedReader或InputStreamReader有什么问题吗?还有其他选择吗。
我不能在spark中使用foreach,因为我必须从服务器获取响应,并且需要将JAVARdd保存为HDFS上的文本文件
如果我们使用mappartition代码,如下所示
JavaRDD<String> mapRDD = filteredRecords.mapPartitions(new FlatMapFunction<Iterator<String>, String>() {
@Override
public Iterable<String> call(Iterator<String> tuple) throws Exception {
final List<String> rddList = new ArrayList<String>();
Iterable<String> iterable = new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return rddList.iterator();
}
};
while(tuple.hasNext()) {
URL formatURL = new URL((tuple.next().replaceAll("\"", ""))
.trim());
HttpURLConnection con = (HttpURLConnection) formatURL
.openConnection();
try(BufferedReader br = new BufferedReader(new InputStreamReader(con
.getInputStream()))) {
rddList.add(br.readLine());
} catch (IOException ex) {
return rddList;
}
}
return iterable;
}
});
JavaRDD mapRDD=filteredRecords.mapPartitions(新的FlatMapFunction(){
@凌驾
公共Iterable调用(迭代器元组)引发异常{
最终列表rddList=newarraylist();
Iterable Iterable=新的Iterable(){
@凌驾
公共迭代器迭代器(){
返回rddList.iterator();
}
};
while(tuple.hasNext()){
URL formatURL=新URL((tuple.next().replaceAll(\“”,“”))
.trim());
HttpURLConnection con=(HttpURLConnection)formatURL
.openConnection();
try(BufferedReader br=新的BufferedReader(新的InputStreamReader)(con
.getInputStream())){
添加(br.readLine());
}捕获(IOEX异常){
返回rddList;
}
}
返回可编辑;
}
});
这里还有我们正在做的每一条记录。不是吗?您当前正在使用的 映射函数 它为分区中的每一行创建url请求 你可以用 地图分割
这将使代码运行得更快,因为它只创建到服务器的连接一次,即每个分区只有一个连接。设置TCP/HTTPS连接是一个巨大的成本。这一事实加剧了这一点,即使您只读取第一个连接(短)一个大文件的行,为了更好地重复使用HTTP/1.1连接,现代HTTP客户机尝试将()读取到文件的末尾,以避免中断连接。这对于小文件是一个很好的策略,但对于MB大小的文件则不适用 这里有一个解决方案:在读取时设置内容长度,以便只读取较小的块,从而降低close()的成本;然后,连接循环可以降低HTTPS设置成本。这就是最新的Hadoop/Spark S3A客户端在连接上设置fadvise=random时所做的:请求块,而不是整个多GB文件。请注意:如果要逐字节地遍历一个文件,这种设计实际上非常糟糕
JavaRDD<String> mapRDD = filteredRecords.mapPartitions(new FlatMapFunction<Iterator<String>, String>() {
@Override
public Iterable<String> call(Iterator<String> tuple) throws Exception {
final List<String> rddList = new ArrayList<String>();
Iterable<String> iterable = new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return rddList.iterator();
}
};
while(tuple.hasNext()) {
URL formatURL = new URL((tuple.next().replaceAll("\"", ""))
.trim());
HttpURLConnection con = (HttpURLConnection) formatURL
.openConnection();
try(BufferedReader br = new BufferedReader(new InputStreamReader(con
.getInputStream()))) {
rddList.add(br.readLine());
} catch (IOException ex) {
return rddList;
}
}
return iterable;
}
});