Apache HttpClient 4.2.1
我有一个Java进程,该进程从一个CouchDB A下载多个文件并将其上传到另一个CouchDBB。使用ExecutorService使用40个工作线程完成下载和上传。
当文件计数很高(〜25k)时,由于Linux打开文件描述符的限制,该进程将引发SocketException“打开的文件过多”。我认为这可能是由于资源泄漏引起的,然后继续分析以下代码:
启动工作线程
private boolean copyDocumentsFromAtoB(Array ids) {
ExecutorService downloader = Executors.newFixedThreadPool(50);
ExecutorService uploader = Executors.newFixedThreadPool(50);
for (String id: ids) {
downloader.execute(new DownloaderThread(id, downloadedDocs));
}
for (JsonElement doc: downloadedDocs) {
uploader.execute(new UploaderThread(doc));
}
}
可运行的下载程序类(UploaderThread类具有类似的实现)
private static final class DocumentDownloader implements Runnable {
private final String documentId;
private final JsonArray downloadedDocs;
DocumentDownloader(String documentId, JsonArray downloadedDocs) {
this.documentId = documentId;
this.downloadedDocs = downloadedDocs;
}
@Override
public void run() {
InputStream docStream = null;
String url = buildUrl(documentId);
HttpGet doc = new HttpGet(url);
try {
//doc.setHeaders()
HttpClient httpClient = new DefaultHttpClient();
HttpResponse docResponse = httpClient.execute(doc);
docStream = docResponse.getEntity().getContent();
//document parsing and adding to downloadedDocs. Not important
} catch (Exception e) {
//handle exceptions
} finally {
if (docStream != null) {
try {
docStream.close();
} catch (IOException e) {
LOGGER.debug("Cannot close input stream", e);
}
}
}
}
}
发现:
httpClient.getConnectionManager().shutdown();
在Runnable类的末尾,则打开的文件数减少了。问题:
为什么原始实现在复制过程中打开的文件描述符的数量增加了?多个HttpClient实例对此有何贡献?
docStream.close();
块中的finally
是否关闭在进程和数据库之间创建的Http连接?
当它所属的线程终止时,HttpClient实例是否被破坏(释放进程中的所有开放资源)? (这可以解释为什么复制过程过早终止后打开的文件数会减少)
除了使用单个全局HttpClient之外,我是否还可以进行其他优化(就资源泄漏而言)?
是否有我可以用来获取该方案针对不同实现的量化统计信息的工具?
我可以按照哪些步骤找到最佳工人人数
setMaxTotal
和setDefaultMaxPerRoute
线程(对于
PoolingClientConnectionManager)?