Java 与下载有关的 ssl 性能问题
Java ssl performance issue in connection with downloads
我目前正在开发一个小型 swift 客户端,在下载文件时遇到了一些性能问题。
经过数千次检查后,我通过 ssl 下载文件定位了问题。
正常下载 (http) 工作正常,没有任何问题(或性能问题)。
但是 SSL 下载炸毁了我的 CPU ...单个内核达到 100% 负载(对于单个线程)
我写了一个没有整个程序的小测试类,可以证实我之前的观察。
package testDownload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class Downloader {
public Downloader(boolean sslTrigger) throws IOException {
try {
this.allowSelfSignCerts();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URL url;
// Http Download
if (sslTrigger) {
System.out.println("HTTPS-Mode");
url = new URL("HTTPS LINK");
} else {
System.out.println("HTTP-Mode");
url = new URL("HTTP LINK");
}
URLConnection conn = url.openConnection();
InputStream input = conn.getInputStream();
OutputStream output = new FileOutputStream(new File(System.getProperty("user.home")+System.getProperty("file.separator")+"test.dat"));
ReadableByteChannel inputChannel = Channels.newChannel(input);
WritableByteChannel outputChannel = Channels.newChannel(output);
System.out.println("start download");
this.fastChannelCopy(inputChannel, outputChannel);
inputChannel.close();
outputChannel.close();
System.out.println("finish");
}
private void fastChannelCopy(ReadableByteChannel src, WritableByteChannel dest) throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1) {
buffer.flip();
dest.write(buffer);
buffer.compact();
}
buffer.flip();
while (buffer.hasRemaining()) {
dest.write(buffer);
}
}
private void allowSelfSignCerts() throws NoSuchAlgorithmException, KeyManagementException {
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
}
使用java-版本
java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
有没有人有解决这个问题的想法?
Normal downloads(http) works fine without any problems(or performance issues). But SSL downloads blow up my CPU ... a single core goes up to 100 % load (for a single thread)
这可能取决于商定的密码客户端和服务器。非常常见的是 AES 密码。但是,虽然 AES 在特殊硬件上速度很快,但在软件中完成时却非常慢且 CPU 受限。 Java 在历史上硬件加速不可用。但看起来他们已经在 Java 8 中添加了它,即使仅适用于服务器 JVM。
有关详细信息,请参阅 AES acceleration for Java and AES-NI intrinsics enabled by default?。
我目前正在开发一个小型 swift 客户端,在下载文件时遇到了一些性能问题。
经过数千次检查后,我通过 ssl 下载文件定位了问题。
正常下载 (http) 工作正常,没有任何问题(或性能问题)。 但是 SSL 下载炸毁了我的 CPU ...单个内核达到 100% 负载(对于单个线程)
我写了一个没有整个程序的小测试类,可以证实我之前的观察。
package testDownload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class Downloader {
public Downloader(boolean sslTrigger) throws IOException {
try {
this.allowSelfSignCerts();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URL url;
// Http Download
if (sslTrigger) {
System.out.println("HTTPS-Mode");
url = new URL("HTTPS LINK");
} else {
System.out.println("HTTP-Mode");
url = new URL("HTTP LINK");
}
URLConnection conn = url.openConnection();
InputStream input = conn.getInputStream();
OutputStream output = new FileOutputStream(new File(System.getProperty("user.home")+System.getProperty("file.separator")+"test.dat"));
ReadableByteChannel inputChannel = Channels.newChannel(input);
WritableByteChannel outputChannel = Channels.newChannel(output);
System.out.println("start download");
this.fastChannelCopy(inputChannel, outputChannel);
inputChannel.close();
outputChannel.close();
System.out.println("finish");
}
private void fastChannelCopy(ReadableByteChannel src, WritableByteChannel dest) throws IOException {
ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
while (src.read(buffer) != -1) {
buffer.flip();
dest.write(buffer);
buffer.compact();
}
buffer.flip();
while (buffer.hasRemaining()) {
dest.write(buffer);
}
}
private void allowSelfSignCerts() throws NoSuchAlgorithmException, KeyManagementException {
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
}
使用java-版本
java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
有没有人有解决这个问题的想法?
Normal downloads(http) works fine without any problems(or performance issues). But SSL downloads blow up my CPU ... a single core goes up to 100 % load (for a single thread)
这可能取决于商定的密码客户端和服务器。非常常见的是 AES 密码。但是,虽然 AES 在特殊硬件上速度很快,但在软件中完成时却非常慢且 CPU 受限。 Java 在历史上硬件加速不可用。但看起来他们已经在 Java 8 中添加了它,即使仅适用于服务器 JVM。
有关详细信息,请参阅 AES acceleration for Java and AES-NI intrinsics enabled by default?。