2009-11-13 2 views
0

확인이,당신은이 방법으로도 마 유형 4 UUID의

List<String> list = new ArrayList<String>(); 
    for (int i = 0; i < 10000; i++) { 
     String value = (""+UUID.randomUUID().getLeastSignificantBits()).substring(3, 20); 
     assertFalse(list.contains(value)); 
     assertTrue(value.length() < 18); 
     list.add(value); 
    } 

이 방법은 마법처럼 통과를 말한다. 그리고 나는 가장 중요한 것보다는 중요한 비트를 취하는 것이 약간 낫다는 인상을 받고있다. 왜냐하면 가장 중요한 비트에서 일부 정보에 대해서는 6 비트가 고정되어 있고 중요하지는 않은 경우가 있기 때문입니다. 따라서 평균적으로 우리는 가장 중요한 비트와의 충돌을 얻기 위해 2^29 UUID를 생성해야하지만, 최하위 비트는 2^32 개의 UUID를 생성해야합니다. Ref : SO Thread. 내가 그 가정에 맞습니까?

이제 여기에서 메소드에서 얻은 최하위 비트의 최상위 2 자리를 자르고 있습니다. 그 부분 문자열을 사용하고 있습니다. 주의 사항 2 자리 숫자와 부호 비트를 잘라내는 중입니다. 이제 평균적으로 충돌을 얻기 위해 2^31 UUID를 생성해야한다는 의미는 아닙니까?

정확히 17 자리 길이를 초과하지 않아야하는 고유 식별자를 생성하려고합니다. 그리고 자바 타입의 의미가 아닌 정수 여야합니다. 내 접근 방식은 얼마나 신뢰할 수 있습니까?

메타 정보 : 사실

, 우리는 일부 레거시 시스템과의 통합, 그리고 우리는 몇 가지 고유 번호 이상 17 자리를 입력해야합니다. 그들은 데이터베이스 고유 키로 생각하고 있습니다. 이 경우에도 시퀀스를 사용할 수 있으며, 먼저이를 제안했습니다. 그러나 그들은 대신에 난수를 생각해 내면 좋다고 말했습니다. 그래서 소비자는 짐작할 수 없습니다.

Java에서 UUID의 유형 -4 구현에 관해서는 충돌을 얻기 위해 평균 2^61 UUID를 생성해야합니다. 이것은 우리가 2^32를 생성하여 가장 중요한 비트에서 충돌을 얻고, 2^29를 생성하여 가장 중요한 비트에서 충돌을 가져와야 함을 의미합니까? 그렇다면 우리가 평균 2^31을 생성하여 2를 자르고 대부분의 자릿수를 남긴 후 최하위 비트에 충돌을 일으킬 필요가 있다고 가정하는 것이 올바르지 않습니까?

나는 SecureRandom도 사용하려고 시도했지만, 19 자리 길이의 값을 주었다. 그러므로 나는 그것의 자리까지 잘게 자른다. 아래는 그 코드입니다. 내가 생각할 수있는

List<String> list = new ArrayList(); 
    Random random = new SecureRandom(); 
    for (int i = 0; i < 10000; i++) { 
     String value = ""+random.nextLong().substring(2, 19); 
     assertFalse(list.contains(value)); 
     assertTrue(value.length() < 18); 
     list.add(value); 
    } 

다른 옵션은 형식 "yyMMddHHmmssSSS + 2-SEQ 자리"날짜를 사용하는 것입니다. 하지만 그건 프로세서 의존적 일 것이고 추측 할 만하다. 왜냐하면 99 라운드 이후에 밀리 초 단위로 변화가 일어 났는지 확신 할 수 없기 때문입니다. 내가 하겠지만 프로세서 속도에 달려있다. 99 개의 동시 요청은 거의 발생하지 않습니다.

+0

실제 질문은 무엇입니까? –

+0

알았어 물음표를 달고있다. 미안합니다. –

답변

3

임의의 비트를 생성하고 숫자로 변환하려면 임의 또는 SecureRandom을 사용하는 것이 좋습니다. 그것은 더 이식성이 있어야합니다.

숫자 자르기에 대한 요점을 이해하지 못합니다. 장주기 PRNG에서 충분한 비트 수에서 17 (십진수) 자릿수를 생성한다고 가정하면 생성 된 모든 쌍의 충돌에 대해 10 ** 17의 확률을 가져야합니다. 소스가 좋고 충분한 비트를 사용한다면 "자르기"는 중요하지 않습니다. ...

10**17의 1은 충분히 좋지 않습니다. 특정 시간에 얼마나 많은 숫자가 (영구 저장소에) 존재할 것인가에 달려 있습니다. 예를 들어 4 천 4 백만 개의 숫자가 있으면 적어도 한 쌍 사이의 충돌 확률은 약 1 %입니다.

일부 번호를 Birthday Paradox Calculator에 연결해보십시오.

EDIT : 필자는 생성주기가 긴주기 길이의 64 비트 의사 난수와 절대 생성 할 수없는 것보다 더 많은 숫자의 반복을 절대적으로 보장하는 생성기를 필요로한다고 생각합니다. 또한 발전기의 상태를 지속하고 다시 시작할 수 있어야합니다. 그런 다음 17 진수 "임의의"숫자를 얻으려면 발전기에서 다음 값을 가져 와서 범위가 0 ... 10**17 - 1인지 테스트합니다. 그럴 경우 반복하지 않을 경우 사용하십시오.

발전기를 올바르게 관리하면 시스템 수명 동안 반복되는 일이 없으므로 충돌 위험이 없습니다. 그러나 PRNG (진정한 RNG가 아님)를 사용하고 올바른 속성을 가진 PRNG를 선택하는 것이 중요합니다.

내가 알 수있는 것으로부터, Random 클래스는주기 길이가 2**48 인 PRNG를 제공합니다. 즉, 숫자가 반복되기 전에 2**48 숫자를 받아야합니다 (예 : getLong() 메소드 사용). OTOH, SecureRandom은주기가 매우 긴 임의의 랜덤 또는 의사 랜덤을 제공하지만 작지만 0이 아닌 각 호출마다 번호를 반복 할 확률이 높습니다.

+0

설명해 주셔서 감사합니다. 나는 충돌을 얻는 것이이 어떤 골동품과도 거의 같지 않을 것이라고 생각한다. 그러나 여전히 기회가 있습니다. 나는 이것을 위해'yyyyMMdd + db-seq (9)'를 사용하려고 생각하고있다. 이 방법으로 하루 999999999 개의 항목을 제한합니다. 또는'yyMMddHHmmss + db-seq (5)'는 1 초에 99999 개의 항목을 제한한다는 것을 의미합니다. 둘 다 괜찮습니다. 감사. –

+0

마지막 경우 BPC는 45 개의 숫자가 발행 된 후 1 %의 충돌 확률을 얻는다 고 전합니다. 즉, 평균 발간 속도가 초당 45 인 경우 주어진 초마다 충돌 가능성이 1 %입니다. –

+0

SecureRandom이 길고 17 자릿수의 long 값을 얻기 위해 자르는 것을 의미합니까? –

0

UUID 알고리즘은 구현에 따라 다릅니다.

guid를 작은 수로 잘라내는 것은 동일한 고유성 확산 또는 보증을 수행하지 않습니다. 저장하는 비트가 실제로 그렇게 중요합니까?

+0

Java에서 UUID의 type-4 구현에 관해서는 충돌을 얻기 위해 평균 2^61 UUID를 생성해야합니다. 이것은 우리가 2^32를 생성하여 가장 중요한 비트에서 충돌을 얻고, 2^29를 생성하여 가장 중요한 비트에서 충돌을 가져와야 함을 의미합니까? 그렇다면 우리가 평균 2^31을 생성하여 2를 자르고 대부분의 자릿수를 남긴 후 최하위 비트에 충돌을 일으킬 필요가 있다고 가정하는 것이 올바르지 않습니까? –

+0

사실, 우리는 기존 시스템과 통합하고 있으며 17 자리 이하의 고유 번호를 제공해야합니다.그들은 데이터베이스 고유 키로 생각하고 있습니다. 이 경우에도 시퀀스를 사용할 수 있으며, 먼저이를 제안했습니다. 그러나 그들은 대신에 난수를 생각해 내면 좋다고 말했습니다. 그래서 comsumer는 추측 할 수 없습니다. –

1

OK, 몇 가지 질문, 난 당신이 하위 비트에 공모가있는 경우가 아닌 상위 비트에, 당신은 여전히 ​​uique ID가

  1. 최선을 다하겠습니다. 반대의 경우도 마찬가지입니다. 따라서 담합을 위해서는 2^61 숫자가 필요합니다.
  2. 가능성 있음.5, + 기호가 작성되지 않으므로 3 자리 자르고 있습니다. 따라서 총 2^41 개의 가능한 숫자가 있으므로 담합의 샘플 크기는 2^21입니다. (10^18 = ~ 2^41)
  3. 결과를 얻는 방법을 봅시다. Random.getLong()이 두 번 호출 된 다음 일부 비트 (임의의 비트 PRNG이 생성됨)가 제거됩니다. Random.getLong() 또는 getInt()를 호출하는 것보다 더 안정적인지 알 수 없습니다.

당신이 17 자리 숫자를해야하는 경우, 왜 다음을 수행하지 : 그것은 대칭 분포를 제공하지 않습니다

String id = String.valueOf(random.nextLong) % 1000000000000000000L); 

공지 사항 - MAX_LONG가 9223372036854775807L 때문에 범위에서 번호 [023372036854775807] 조금 더 나은 기회가 나타날 것입니다.

또한 메소드와이 둘 모두 고유 ID를 보장하지 않습니다.

+0

감사합니다. Okay here, http://stackoverflow.com/questions/325443/generate-uuid-in-java. 그는 우리가 아무것도 자르지 않고 가장 중요한 비트를 그대로 얻지 못하면 평균적으로 충돌을 얻기 위해 2^29 UUID를 생성해야한다고 그는 말하고 있습니다. 틀렸어? 최소 중요하지 않은 경우 2^32이어야합니다. 나 맞아? 그렇다면 3 자리를 자르고 2^16이되는 방법은 무엇입니까? –

+0

답을 고쳤습니다. 모든 17 자리 숫자의 상한선으로 10^18을 사용합시다. 대략 2^41에 해당합니다. –