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?