네트워크 프로토콜을 구현하고 있으며 패킷에 고유 식별자가 있어야합니다. 지금까지 임의의 32 비트 정수를 생성했으며 프로그램 / 연결 수명 동안 충돌이 발생할 가능성이 천문학적이라고 가정합니다. 이것은 일반적으로 프로덕션 코드에서 허용되는 관행으로 간주됩니까, 아니면 충돌을 방지하기 위해보다 복잡한 시스템을 고안해야합니까?
네트워크 프로토콜을 구현하고 있으며 패킷에 고유 식별자가 있어야합니다. 지금까지 임의의 32 비트 정수를 생성했으며 프로그램 / 연결 수명 동안 충돌이 발생할 가능성이 천문학적이라고 가정합니다. 이것은 일반적으로 프로덕션 코드에서 허용되는 관행으로 간주됩니까, 아니면 충돌을 방지하기 위해보다 복잡한 시스템을 고안해야합니까?
답변:
생일 역설을 조심하십시오 .
크기 N 세트 (경우에 따라 N = 2 ^ 32)에서 임의의 값을 일관되게 (일관 적으로, 독립적으로) 생성한다고 가정합니다.
그런 다음 생일 역설 의 경험 법칙에 따르면 sqrt (N) 값에 대해 일단 생성하면 충돌이 발생할 가능성이 최소 50 % 일 수 있습니다. 즉, 두 개의 동일한 값이 생성 된 시퀀스.
N = 2 ^ 32의 경우 sqrt (N) = 2 ^ 16 = 65536입니다. 약 65k 개의 식별자를 생성 한 후 두 개가 충돌하지 않을 가능성이 높습니다! 초당 식별자를 생성하면 하루 미만으로 발생합니다. 말할 것도없이, 많은 네트워크 프로토콜이 그보다 빠르게 작동합니다.
이 숫자에 충분한 비트가 있으면 고유 한 난수에 의존하는 것이 일반적으로 허용되는 것으로 간주됩니다. 난수를 반복하면 전체 보안이 손상되는 암호화 프로토콜이 있습니다. 그리고 난수 생성기에 사용되는 심각한 취약점이 없다면 문제가되지 않습니다.
UUID 생성 알고리즘 중 하나는 122 개의 임의 비트로 구성된 ID를 효과적으로 생성하고 고유 한 것으로 가정합니다. 다른 두 알고리즘은 고유 한 122 비트로 잘린 해시 값에 의존하며, 이는 거의 동일한 충돌 위험이 있습니다.
따라서 임의의 ID를 고유하게 만들기에 충분한 122 비트에 의존하는 표준이 있지만 32 비트로는 충분하지 않습니다. 32 비트 ID의 경우 충돌 위험이 50 %에 도달하기 전에 약 2¹⁶ ID 만 사용합니다. 2¹⁶ ID의 경우 각각 2³¹ 쌍에 가깝기 때문에 충돌 할 수 있습니다.
새로운 디자인에서 권장하는 것보다 122 비트도 적습니다. 일부 표준화를 따르는 것이 중요하다면 UUID를 사용하십시오. 그렇지 않으면 122 비트보다 큰 것을 사용하십시오.
160 비트 출력의 SHA1 해시 함수는 더 이상 안전한 것으로 간주되지 않습니다. 160 비트는 출력의 고유성을 보장하기에 충분하지 않기 때문입니다. 최신 해시 함수의 출력은 224에서 512 비트입니다. 무작위로 생성 된 ID는 동일한 크기를 목표로하여 안전 마진이 우수한 고유성을 보장해야합니다.
sqrt(2^122)
= 2.3 quadrillion quadrillion UUID
urandom
것은 UUID 라이브러리를 사용하는 것보다 더 효과적이지 않습니다. 방금 비교를 위해 둘 다 Python으로 구현했으며 각 메소드는 정확히 25 문자의 소스 코드였습니다.
나는 이것을 나쁜 습관이라고 부를 것이다. 난수는 단순히 고유 한 숫자를 생성하지 않고 난수를 생성합니다. 무작위 분포에는 중복이 포함될 수 있습니다. 시간 요소를 추가하여이 상황을 수용하기 어렵게 만들 수 있습니다. 시스템 시계에서 현재 시간을 밀리 초 단위로 가져옵니다. 이 같은:
parseToInt(toString(System.currentTimeMillis()) + toString(Random.makeInt()))
먼 길을 갈 것입니다. 분명히 독창성을 보장하려면 UUID / GUID를 사용해야합니다. 그러나 랜덤 생성이 동일한 밀리 초에 복제본을 갖는 경우 오버랩의 유일한 가능성이기 때문에 생성 비용이 많이들 수 있습니다.
currentTimeMillis
감쌀 때까지 최대 1 %의 패킷에서 충돌 확률이 0 % 입니다.
System.currentTimeMillis
하고 다른 하나는 포함 Random.makeInt()
) 인 경우 충돌 가능성이 크게 줄어 듭니다. 그러나이 예제의 코드는 그렇지 않습니다. 주어 모든 전회 랜덤 값 및 모든 현재 시간, 충돌 확률은 처음에 충돌 개의 난수의 확률과 동일하다.
실패 확률과 실패 결과에 따라 다릅니다.
나는 하드웨어 사람들이 잘못된 결과를 낼 가능성이 작은 알고리즘 (100 년 동안 1 번의 실패와 같은 것)이 받아 들여질 것이라고 생각한 소프트웨어와 하드웨어 사람들 사이의 논쟁을 기억하고, 소프트웨어 사람들은 이것이 혐오라고 생각했다. 하드웨어 담당자는 정기적으로 예상되는 실패율을 계산했으며, 예를 들어 우주선으로 인한 교란으로 인해 모든 것이 때때로 잘못된 답을 줄 것이라는 생각에 매우 익숙했습니다. 그들은 소프트웨어 사람들이 100 %의 신뢰성을 기대한다는 것이 이상하다고 생각했습니다.
임의의 숫자는 고유하다고 가정해도되지만주의해야합니다.
임의의 숫자가 균등하게 분포되어 있다고 가정하면 충돌 확률은 대략 (n 2 / 2) / k입니다. 여기서 n은 생성하는 임의의 숫자이고 k는 "임의"숫자가 취할 수있는 가능한 값의 수입니다.
천문학적으로는 숫자를 입력하지 않을 것이므로 2 30 분의 1 (대략 10 억)에이를 수 있습니다. 2 30 패킷 을 생성한다고 가정 해 봅시다 (각 패킷이 약 킬로바이트의 데이터를 나타내는 경우 총 1 테라 바이트의 총 데이터를 의미하지만 상상할 수는 없습니다). 최소 289 개의 가능한 값을 가진 난수가 필요하다는 것을 알았습니다 .
먼저 임의의 숫자가 충분히 커야합니다. 32 비트 난수는 최대 32 개의 가능한 값을 가질 수 있습니다 . 어디에도 근접하지 않은 사용량이 많은 서버의 경우.
둘째, 난수 생성기는 내부 상태가 충분히 커야합니다. 난수 생성기에 32 비트 내부 상태 만있는 경우 생성 한 값이 아무리 크더라도 최대 32 개의 가능한 값만 얻을 수 있습니다.
셋째, 연결 내에서가 아닌 연결 전체에서 난수가 고유해야하는 경우 난수 생성기를 잘 시드해야합니다. 프로그램이 자주 다시 시작되는 경우 특히 그렇습니다.
일반적으로 프로그래밍 언어의 "정규"난수 생성기는 이러한 용도에 적합하지 않습니다. 암호화 라이브러리에서 제공하는 난수 생성기는 일반적으로 있습니다.
많은 사람들이 이미 높은 수준의 답변을 주었지만 몇 가지 사소한 점을 추가하고 싶습니다. 먼저 생일 역설에 관한 @nomadictype의 점은 훌륭 합니다.
또 다른 요점 : 무작위성은 사람들이 평상시 생각하는 것처럼 생성하고 정의하는 것만 큼 간단하지 않습니다. (실제로 무작위성에 대한 통계 테스트가 있습니다).
그럼에도 불구하고 사람들이 독립적 인 사건이 어떻게 든 서로에게 영향을 준다고 가정하는 통계적 오류 인 도박꾼의 오류를 인식하는 것이 중요합니다 . 랜덤 이벤트는 일반적으로 통계적으로 서로 독립적입니다. 즉, "10"을 무작위로 생성하더라도 향후 "10"을 더 많이 생성 할 확률은 변경되지 않습니다. (아마도 누군가 그 규칙에 대한 예외를 내놓을 수는 있지만 거의 모든 난수 생성기의 경우가 될 것으로 기대합니다).
내 대답은 충분히 긴 난수 시퀀스가 고유하다고 가정 할 수 있다면 분명한 통계 패턴이기 때문에 실제로 난수는 아닐 것입니다. 또한 예를 들어 10을 생성하면 미래의 10을 생성 할 확률이 0 % (가능하지 않을 수 있음)가 될 것이므로 10 개의 새로운 숫자가 독립적 인 이벤트가 아니라는 것을 의미합니다. 즉, 10 이외의 숫자를 얻을 확률이 높아집니다 (즉, 생성하는 숫자가 많을수록 나머지 숫자 각각의 확률이 높아집니다).
한 가지 더 고려해야 할 사항 : 단일 게임에서 Powerball을 이길 수있는 기회는 내가 이해하는 것처럼 약 1 억 7 천 5 백만입니다. 그러나 누군가 이길 확률은 그보다 훨씬 높습니다. 특정 숫자 "승리"/ 복제 확률보다 누군가 "승리"(예 : 복제) 확률에 더 관심이 있습니다 .