Problem

Java를 사용하고 리눅스 환경에서 Random Number를 생성할 때 약 10초 이상의 지연이 발생했다. SecureRandom1을 사용하고 있었고, Random을 필요로 하는 클래스에서 클래스가 생성될 때 랜덤 시드를 설정해주고 있었다. 참고로 윈도우 환경의 같은 코드에서는 문제가 없었다. 참고로 문제가 있었던 코드의 일부는 다음과 같다.

public Signature(String key) {
    ...

    try {
        random = SecureRandom.getInstance("SHA1PRNG");
        byte[] seed = random.generateSeed(NONCE_BYTE_LENGTH);
        random.setSeed(seed);

    } catch (NoSuchAlgorithmException e) {
    }

    Security.addProvider(new BouncyCastleProvider());
}

Solution

  1. Avoiding JVM Delays Caused by Random Number Generation2 설명이 되있듯이 Java는 기본 /dev/random를 사용하고 있고 이것은 플랫폼(운영체제)에 의존성이 있는데, 시스템에 노이즈 신호를 기다려 그것을 랜덤 함수 결과를 생성하는데 이용하기 때문에 지연현상이 발생할 수 있다. $JAVA_HOME/jre/lib/security/java.security를 수정해서 /dev/urandom으로 변경하면 결과를 빠르게 얻을 수 있지만 /dev/random이 더 안전한 방식이다.

  2. 또는, 1의 방법을 톰캣 실행시 옵션을 추가해서 수정할 수도 있다.3

  3. 이번 경우에는 1,2를 수정해줘도 해결되지 않았는데 코드에도 문제가 있었기 때문이었다. SecureRandom를 초기화하고 seed를 설정하는 부분을 아래와같이 초기화 시 한번만 실행되도록 변경하는 것으로 해결했다.4

    try {
        if (random == null) { // random is static variable
            random = SecureRandom.getInstance("SHA1PRNG");
            byte[] seed = random.generateSeed(NONCE_BYTE_LENGTH);
            random.setSeed(seed);
        }

    } catch (NoSuchAlgorithmException e) {
    }
  1. 그리고 추가로 Security Provider를 설정하는 부분도 중복해서 처리되지 않도록 변경해 주었다.
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
        Security.addProvider(new BouncyCastleProvider());
    }

References