2014-11-24 4 views
3

우리는 6 노드 Red Hat 4.4.7/Linux 2.6.32 네트워크를 가지고 있으며, 각 노드는 Hibernate 3.3.2.GA를 사용하여 중앙 Oracle 데이터베이스에 레코드를 생성하는 Java 애플리케이션을 실행합니다.중복 된 UUID를 생성하는 최대 절전 모드

Hibernate에서 중복 된 UUID를 생성하는 문제가 발생했습니다. 다음과 같은 문제

Java 클래스가 정의 :

@Entity 
@Table(name = "X_Y") 
@GenericGenerator(name = "x-y-uuid", strategy = "uuid") 
public class XY implements ... { 
    @Id 
    @Column(name = "X_Y_ID") 
    @GeneratedValue(generator = "x-y-uuid") 
    private String id; 
    ... 
} 

우리는 잠시 동안 성공적으로 사용하고이 정의를 사용하여, 우리는 중복 X_Y_ID 키의 문제로 달렸다. X_Y_ID에 대한 고유 제한 조건을 사용 불가능으로 설정하고 프로세스를 재개합니다. 그 사이에, 우리는 Hibernate 코드뿐만 아니라 우리 코드에서 발생할 수있는 오류를 찾아 내기 시작했다. Hibernate의 UUIDHexGenerator을 보면 UUID의 처음 8 문자는 기기의 IP 주소를 기반으로하며, 두 번째 8 문자는 JVM 시작 시간을 기반으로합니다.

X_Y_ID에 대한 사용 불가능한 고유 제한 조건을 사용한 프로세스가 완료된 후 결과 UUID를 분석했습니다. 사실 59 개의 중복 된 X_Y_ID 값이 있음을 발견했습니다. 우리 놀랍게도 , 쿼리 :

select SUBSTR(X_Y_ID,1,8), COUNT(*) 
from X_Y 
group by SUBSTR(X_Y_ID,1,8) 

는 6 개 시스템이 동일한 처음 8 개 문자가있는 것으로 나타났다. 쿼리 :

select SUBSTR(X_Y_ID,9,8), COUNT(*) 
from X_Y 
group by SUBSTR(X_Y_ID,9,8) 

는 당신이 볼 수 있듯이 행의 마지막 가진 약 두 배 수에 5 개 행이

"49d99de6" 2148309 
"49d99e3c" 2044966 
"49d99def" 2228095 
"49d99df2" 2091068 
"49d99dee" 4110661 

했다. 이것은 놀랍지 않습니다. (모두 그것은 서로 다른 두 머신의 JVM이 서로 256ms 이내에 시작되었음을 의미합니다).

조금 더 조사해 보았을 때 처음 8 자에 대해 생성 된 값인 ff808081은 IP 주소 127.0.0.1 인 localhost에 해당합니다. 이러한 시스템 중 하나에서 ifconfig 실행

(예를 들어) 제공합니다

eth0  Link encap:Ethernet HWaddr 00:50:56:81:2C:20 
      inet addr:10.191.8.50 Bcast:10.191.63.255 Mask:255.255.192.0 
      inet6 addr: fe80::250:56ff:fe81:2c20/64 Scope:Link 
      ... 

lo  Link encap:Local Loopback 
      inet addr:127.0.0.1 Mask:255.0.0.0 
      inet6 addr: ::1/128 Scope:Host 
      ... 

내 질문

은 다음과 같습니다

  • 가 어떻게이 최대 절전 모드에서 볼 수있는 IP 주소가 127.0.0.1 수 있음 10.191.8.50을 말하지 않습니까?
  • 배포 된 시스템에서이를 방지하려면 어떻게해야합니까?
+0

이것은 분명히 Hibernate의 버그이며, 그 편이 고정되어 있어야합니다. 그러나'grep $ HOSTNAME/etc/hosts' 그리고'127.0.0.1 yourhostname' 항목이 있는지 확인하십시오. –

+2

@JasonC Hibernate가 보편적이거나 고유하지 않은 UUID를 생성하는 버그가 아닌 이유는 무엇입니까? 그들이 [RFC] (http://www.ietf.org/rfc/rfc4122.txt)를 따라 가면서 자신의 것을 뒤쫓아왔다면, 이것은 일어나지 않았을 것입니다. –

+0

@thatotherguy 예, 사실,'UUIDHexGenerator'를 조금 더 자세히 들여다 보았습니다. 나는 그것이 어땠는지 알지 못했습니다 ... 저는 이것을 반영하기 위해 약간 아래에서 제 대답을 다시 고쳐야 할 것입니다. –

답변

2

@thatotherguy 댓글에서 지적 하듯이, AbstractUUIDGeneratorUUIDHexGenerator의 최대 절전 모드 구현은 꽤 멀리 RFC-4122 호환되는 것입니다. 더 자세히 살펴볼 때까지 구현이 얼마나 어려운지 전혀 알지 못했습니다. 제외하고, 그것이 무엇인지에 대한 구현을 복용하여 문제의 근본 원인이 여기에 InetAddress.getLocalHost() (AbstractUUIDGenerator를 통해)의 UUIDHexGenerators 사용으로 귀결

는 "독특한"값이 올 수 있습니다. 호스트 이름에 대한 이름 조회가 127.0.0.1 (예 : /etc/hosts 파일에 있음)이거나 호스트 이름이 "지역"인 경우이 이름이 사용됩니다.이 옵션의 경우,

  1. 당신은 당신의 호스트 이름에 대한 LAN IP를 포함 /etc/hosts를 업데이트 할 수 있습니다 :

    당신은 몇 가지 옵션이 있습니다. 그래도 적절한 UUID를 사용하지 않을 것입니다 (다음 요점의 마지막 부분과 동일).

  2. 최대 절전 모드 알고리즘이 충분하지 않은 경우 사용자 지정 IdentifierGenerator을 정의하고 작업에보다 적합한 더 나은 UUID 생성 알고리즘을 제공 할 수 있습니다. Java의 내장 된 UUID을 기반으로합니다. 그러나 UUIDHexGenerator을 확장하고 protected int getIP()을 오버라이드하여 정확한 IP 주소를 반환 할 수 있습니다. 이는 AbstractUUIDGenerators implementation의 해킹 (귀하의 getIP()은 더 이상 그 IP 인스턴스 필드의 값을 반환하지 않을 것입니다) 그리고 여전히 적절한 UUID가 아니기 때문에 해킹입니다. 충분할 수도 있지만 추천하지 않습니다.

  3. 발전기를 사용하는 대신 수동 ID 할당을 지정하고 직접 UUID를 생성하십시오. 다시 말하지만 Java의 UUID이 여기에서 유용 할 수 있습니다.

  4. UUIDGenerator을 사용하는 새로운 UUID 생성기 전략 "uuid2"가 있습니다. 3.6.2에서는 새로운 기능을 제공하지 않습니다. 그것의 출처는 is available입니다. 나는이 전략을 전에 사용하지 않았으며 그것을 위해 말할 수 없다. 그러나 앤드류 스타 인 (Andrew Stein)이 아래의 의견에서 관찰 한 바와 같이, 출처를 조사한 결과, provides a strategy built around Java's UUID 인 것으로 나타 났으며, 좋은 내기가 될 가능성이 있으며, 이전의 AbstractUUIDGenerator 유사 변형보다 우수합니다. 정말 잘 형성 UUID를 생성하지 않습니다, 다시 당신을 위해 작동하지만, 유지 보수/배포 문제가있을 수 있고 경우

옵션 1은 간단한 빠른 수정합니다. 장기적으로, UUID (또는 적절한 전략과 함께 옵션 4)을 사용하는 옵션 2가 아마도 가장 정확할 것입니다.

article describing various UUID assignment strategies for Hibernate이 있으며 더 유용한 통찰력과 예제가 포함되어있을 수 있습니다.

+0

안녕하세요 @ JasonC, 정말 고마워요. 중요한 점은 "uuid2"에 의해 사용되는 기본 'UUIDGenerator'는 소스 코드에서 볼 수 있듯이 자바의 UUID에 종속된다는 것입니다 : https://github.com/hibernate/hibernate-orm/blob/master /hibernate-core/src/main/java/org/hibernate/id/uuid/StandardRandomStrategy.java –

+0

@AndrewStein 아, 잘 알고 있습니다. 그들이하는 일은 옳았습니다. 나는 그 길로 갔기 때문에 기쁩니다. –