클라이언트 세션을 생성하려면 애플리케이션 코드가 각각 ZooKeeper 서버에 해당하는 쉼표로 구분된 호스트:포트 쌍 목록을 포함하는 연결 문자열을 제공해야 한다. (예: "127.0.0.1:4545" 또는 "127.0.0.1:3000,127.0.0.1 :3001,127.0.0.1:3002"). ZooKeeper 클라이언트 라이브러리는 임의의 서버를 선택하고 연결을 시도한다. 이 연결이 실패하거나 어떤 이유로 클라이언트가 서버에서 연결이 끊어지면 클라이언트는 연결이 (재)설정될 때까지 목록의 다음 서버를 자동으로 시도한다.
클라이언트가 ZooKeeper 서비스에 대한 핸들을 가져오면 ZooKeeper는 64비트 숫자로 표시되는 ZooKeeper 세션을 생성하여 클라이언트에 할당한다. 클라이언트가 다른 ZooKeeper 서버에 연결하면 연결 핸드셰이크의 일부로 세션 ID를 보낸다. 보안 조치로 서버는 ZooKeeper 서버가 확인할 수 있는 세션 ID에 대한 암호를 생성한다. 암호는 클라이언트가 세션을 설정할 때 세션 ID와 함께 클라이언트에 전송된다. 클라이언트는 새 서버와 세션을 다시 설정할 때마다 세션 ID와 함께 이 암호를 보낸다.
ZooKeeper 세션을 생성하기 위한 ZooKeeper 클라이언트 라이브러리 호출에 대한 매개변수 중 하나는 세션 시간 초과(밀리초)이다. 클라이언트는 요청된 시간 초과를 보내고 서버는 클라이언트에 제공할 수 있는 시간 초과로 응답한다. 현재 구현에서는 시간 제한이 tickTime의 최소 2배(서버 구성에서 설정됨)와 최대 tickTime의 20배가 되어야 한다. ZooKeeper 클라이언트 API는 협상된 시간 제한에 대한 액세스를 허용한다.
클라이언트(세션)가 ZK 서비스 클러스터에서 분할되면 세션 생성 중에 지정된 서버 목록을 검색하기 시작한다. 결국 클라이언트와 적어도 하나의 서버 간의 연결이 다시 설정되면 세션은 다시 "연결됨" 상태로 전환되거나(세션 시간 초과 값 내에서 다시 연결된 경우) "만료됨" 상태로 전환된다. (세션 시간 초과 후 다시 연결된 경우). 연결 해제를 위해 새 세션 개체(새 ZooKeeper.class 또는 c 바인딩의 Zookeeper 핸들)를 만드는 것은 권장되지 않는다. ZK 클라이언트 라이브러리가 재연결을 처리한다. 특히 "군집 효과" 등과 같은 것을 처리하기 위해 클라이언트 라이브러리에 휴리스틱을 내장하고 있다.
세션 만료는 클라이언트가 아닌 ZooKeeper 클러스터 자체에서 관리한다. ZK 클라이언트가 클러스터와 세션을 설정할 때 위에서 설명한 "시간 초과" 값을 제공한다. 이 값은 클러스터에서 클라이언트 세션이 만료되는 시기를 결정하는 데 사용된다. 만료는 클러스터가 지정된 세션 시간 초과 기간(즉, 하트비트 없음) 내에 클라이언트로부터 응답하지 않을 때 발생한다. 세션 만료 시 클러스터는 해당 세션이 소유한 모든 임시 노드를 삭제하고 연결된 모든 클라이언트(해당 znode를 보고 있는 모든 사용자)에게 즉시 변경 사항을 알린다. 이 시점에서 만료된 세션의 클라이언트는 여전히 클러스터에서 연결이 끊기며 클러스터에 대한 연결을 다시 설정할 수 있을 때까지/하지 않는 한 세션 만료를 알리지 않는다.
만료된 세션의 Watch자가 보는 만료된 세션의 상태 전환 예:
ZooKeeper 세션 설정 호출에 대한 또 다른 매개변수는 기본 Watch자이다. 클라이언트에서 상태 변경이 발생하면 Watch자에게 알림이 전송된다. 예를 들어, 클라이언트가 서버에 대한 연결이 끊어지면 클라이언트에게 알림이 전송되거나 클라이언트의 세션이 만료되는 경우 등… 이 Watch자는 초기 상태가 연결이 끊어진 것으로 간주해야 한다. (상태 변경 이벤트가 Watch자에게 전송되기 전에 클라이언트 라이브러리) 새로운 연결의 경우 Watch자에게 보내는 첫 번째 이벤트는 일반적으로 세션 연결 이벤트이다.
세션은 클라이언트가 보낸 요청에 의해 활성 상태로 유지된다. 세션이 시간 초과되는 시간 동안 세션이 유휴 상태인 경우 클라이언트는 세션을 활성 상태로 유지하기 위해 PING 요청을 보낸다. 이 PING 요청을 통해 ZooKeeper 서버는 클라이언트가 여전히 활성 상태임을 알 수 있을 뿐만 아니라 클라이언트가 ZooKeeper 서버에 대한 연결이 여전히 활성 상태인지 확인할 수 있다. PING의 타이밍은 연결이 끊긴 것을 감지하고 새 서버에 다시 연결할 수 있는 합리적인 시간을 보장할 만큼 충분히 보수적이다.
서버에 대한 연결이 성공적으로 설정(연결)되면 기본적으로 동기 또는 비동기 작업이 수행되고 다음 중 하나가 유지된다.
서버 목록 업데이트 각각 ZooKeeper 서버에 해당하는 호스트:포트 쌍의 쉼표로 구분된 새 목록을 제공하여 클라이언트가 연결 문자열을 업데이트할 수 있도록 한다. 이 함수는 새 목록의 서버당 예상되는 균일한 수의 연결을 달성하기 위해 클라이언트가 현재 호스트에서 연결을 끊을 수 있는 확률적 로드 밸런싱 알고리즘을 호출한다. 클라이언트가 연결된 현재 호스트가 새 목록에 없는 경우 이 호출은 항상 연결을 끊는다. 그렇지 않으면 서버 수가 증가 또는 감소했는지 여부와 그 정도에 따라 결정이 내려진다.
예를 들어, 이전 연결 문자열에 3개의 호스트가 포함되어 있고 이제 목록에 이러한 3개의 호스트와 2개의 추가 호스트가 포함된 경우 3개의 호스트 각각에 연결된 클라이언트의 40%가 로드 균형을 맞추기 위해 새 호스트 중 하나로 이동한다. 알고리즘은 클라이언트가 0.4 확률로 연결된 현재 호스트에 대한 연결을 끊도록 하고 이 경우 클라이언트가 무작위로 선택된 2개의 새 호스트 중 하나에 연결하도록 한다.
또 다른 예 - 5개의 호스트가 있고 이제 호스트 중 2개를 제거하도록 목록을 업데이트한다고 가정하면 나머지 3개의 호스트에 연결된 클라이언트는 연결된 상태로 유지되는 반면 제거된 2개의 호스트에 연결된 모든 클라이언트는 다음 중 하나로 이동해야 한다. 무작위로 선택된 3명의 호스트. 연결이 끊어지면 클라이언트는 라운드 로빈이 아닌 확률적 알고리즘을 사용하여 연결할 새 서버를 선택하는 특수 모드로 이동한다.
첫 번째 예시에서 각 클라이언트는 확률 0.4로 연결을 끊기로 결정하지만 일단 결정이 내려지면 임의의 새 서버에 연결을 시도하고 새 서버에 연결할 수 없는 경우에만 이전 서버에 연결을 시도한다. 것. 서버를 찾거나 새 목록의 모든 서버를 시도하고 연결에 실패한 후 클라이언트는 connectString에서 임의의 서버를 선택하고 연결을 시도하는 정상 작동 모드로 다시 이동한다. 실패하면 라운드 로빈에서 다른 임의 서버를 계속 시도한다. (처음에 서버를 선택하는 데 사용된 알고리즘 위 참조)
ZooKeeper의 모든 읽기 작업은 세 가지를 통해 이루어진다. getData() , getChildren() exists() 이는 Watch를 사이드 이팩트로 설정하는 옵션이 있다. 다음은 Watch에 대한 ZooKeeper의 정의이다. Watch 이벤트는 Watch를 설정한 클라이언트로 전송되는 일회성 트리거로, Watch가 설정된 데이터가 변경될 때 발생한다. Watch 정의에서 고려해야 할 세 가지 핵심 사항이 있다.
Watch는 클라이언트가 연결된 ZooKeeper 서버에서 로컬로 유지 관리된다. 이를 통해 Watch를 경량으로 설정, 유지 관리 및 발송할 수 있다. 클라이언트가 새 서버에 연결하면 모든 세션 이벤트에 대해 Watch가 트리거된다. 서버와의 연결이 끊어진 상태에서는 Watch가 수신되지 않는다. 클라이언트가 다시 연결되면 이전에 등록된 모든 Watch가 다시 등록되고 필요한 경우 트리거된다. 일반적으로 이 모든 것이 투명하게 발생한다. Watch를 놓칠 수 있는 한 가지 경우가 있다. 연결이 끊긴 상태에서 znode가 생성되고 삭제되면 아직 생성되지 않은 znode의 존재에 대한 Watch가 누락된다.
ZooKeeper의 상태를 읽는 세 가지 호출(exists, getData 및 getChildren)로 Watch를 설정할 수 있다. 다음 목록은 Watch가 트리거할 수 있는 이벤트와 이를 활성화하는 함수 호출에 대해 자세히 설명한다.
removeWatches를 호출하여 znode에 등록된 Watch를 제거할 수 있다. 또한 ZooKeeper 클라이언트는 로컬 플래그를 true로 설정하여 서버 연결이 없더라도 로컬에서 Watch를 제거할 수 있다. 다음 목록은 Watch가 성공적으로 제거된 후 트리거될 이벤트를 자세히 설명한다.
Watch와 관련하여 ZooKeeper는 다음과 같은 보증을 유지한다.
ZooKeeper는 ACL을 사용하여 znode(ZooKeeper 데이터 트리의 데이터 노드)에 대한 액세스를 제어한다. ACL 구현은 UNIX 파일 액세스 권한과 매우 유사한다. 권한 비트를 사용하여 노드 및 비트가 적용되는 범위에 대한 다양한 작업을 허용/비허용한다. 표준 UNIX 권한과 달리 ZooKeeper 노드는 사용자(파일 소유자), 그룹 및 세계(기타)에 대한 세 가지 표준 범위로 제한되지 않는다. ZooKeeper에는 znode의 소유자라는 개념이 없다. 대신 ACL은 해당 ID와 연결된 권한 및 ID 세트를 지정한다.
또한 ACL은 특정 znode에만 적용된다. 특히 어린이에게는 적용되지 않는다. 예를 들어 /app 이 ip:172.16.16.1에서만 읽을 수 있고 /app/status 가 전 세계에서 읽을 수 있는 경우 누구나 /app/status 를 읽을 수 있다 . ACL은 재귀적이지 않는다.
ZooKeeper는 플러그형 인증 체계를 지원한다. ID는 schema:expression 형식을 사용하여 지정된다. 여기서 scheme 은 ID가 해당하는 인증 체계이다. 유효한 표현식 세트는 체계에 의해 정의된다. 예를 들어, ip:172.16.16.1 은 ip 체계 를 사용 하는 주소가 172.16.16.1 인 호스트의 id 이고, digest:bob:password 는 다이제스트 체계 를 사용하는 bob 이름을 가진 사용자의 id이다 .
클라이언트가 ZooKeeper에 연결하고 자신을 인증하면 ZooKeeper는 클라이언트에 해당하는 모든 ID를 클라이언트 연결과 연결한다. 이 ID는 클라이언트가 노드에 액세스하려고 할 때 znode의 ACL에 대해 확인된다. ACL은 (scheme:expression, perms) 쌍으로 구성 된다. 표현식 의 형식은 체계에 따라 다릅다. 예를 들어, 쌍 (ip:19.22.0.0/16, READ) 은 19.22로 시작하는 IP 주소를 가진 모든 클라이언트에 읽기 권한을 부여한다.
ZooKeeper는 고성능의 확장 가능한 서비스이다. 읽기와 쓰기 작업은 모두 빠르도록 설계되었지만 읽기는 쓰기보다 빠릅다. 그 이유는 읽기의 경우 ZooKeeper가 이전 데이터를 제공할 수 있기 때문이며 이는 ZooKeeper의 일관성 보장 때문이다.
이러한 일관성 보장을 사용하면 ZooKeeper 클라이언트에서만 리더 선택, 장벽, 대기열 및 읽기/쓰기 취소 가능한 잠금과 같은 더 높은 수준의 기능을 쉽게 구축할 수 있다(ZooKeeper에 추가할 필요 없음).
Note
때때로 개발자는 실수로 ZooKeeper가 실제로 하지 않는 다른 보증을 가정 한다. * 동시적으로 일관된 클라이언트 간 보기* : ZooKeeper는 모든 인스턴스에서 두 개의 서로 다른 클라이언트가 ZooKeeper 데이터에 대해 동일한 보기를 가질 것이라고 보장하지 않는다. 네트워크 지연과 같은 요인으로 인해 한 클라이언트는 다른 클라이언트가 변경 사항을 알리기 전에 업데이트를 수행할 수 있다. 두 클라이언트 A와 B의 시나리오를 고려하십시오. 클라이언트 A가 znode /a의 값을 0에서 1로 설정하고 클라이언트 B에게 /a를 읽도록 지시하면 클라이언트 B는 어떤 서버에 따라 이전 값 0을 읽을 수 있다. 에 연결되어 있다. 클라이언트 A와 클라이언트 B가 동일한 값을 읽는 것이 중요한 경우 클라이언트 B는 sync()읽기를 수행하기 전에 ZooKeeper API 메서드에서 메서드를 가져옵다. 따라서 ZooKeeper 자체는 변경 사항이 모든 서버에서 동기적으로 발생하는 것을 보장하지 않지만 ZooKeeper 기본 요소를 사용하여 유용한 클라이언트 동기화를 제공하는 더 높은 수준의 기능을 구성할 수 있다.
ZooKeeper 클라이언트 라이브러리는 Java 및 C의 두 가지 언어로 제공된다. 다음 섹션에서는 이에 대해 설명한다.
ZooKeeper Java 바인딩을 구성하는 두 가지 패키지가 있다. org.apache.zookeeper 및 org.apache.zookeeper.data . ZooKeeper를 구성하는 나머지 패키지는 내부적으로 사용되거나 서버 구현의 일부이다. org.apache.zookeeper.data 패키지 는 단순히 컨테이너로 사용되는 생성된 클래스로 구성된다.
ZooKeeper Java 클라이언트에서 사용하는 기본 클래스는 ZooKeeper 클래스이다. 두 생성자는 선택적 세션 ID와 암호만 다릅다. ZooKeeper는 프로세스 인스턴스 간의 세션 복구를 지원한다. Java 프로그램은 세션 ID와 암호를 안정적인 저장소에 저장하고 프로그램의 이전 인스턴스에서 사용한 세션을 다시 시작하고 복구할 수 있다.
ZooKeeper 개체가 생성되면 IO 스레드와 이벤트 스레드라는 두 개의 스레드도 생성된다. 모든 IO는 IO 스레드에서 발생한다(Java NIO 사용). 모든 이벤트 콜백은 이벤트 스레드에서 발생한다. ZooKeeper 서버에 다시 연결하고 하트비트를 유지하는 것과 같은 세션 유지 관리는 IO 스레드에서 수행된다. 동기 메서드에 대한 응답도 IO 스레드에서 처리된다. 비동기 메서드 및 Watch 이벤트에 대한 모든 응답은 이벤트 스레드에서 처리된다. 이 디자인에서 알 수 있는 몇 가지 사항이 있다.
마지막으로 종료와 관련된 규칙은 간단한다. ZooKeeper 개체가 닫히거나 치명적인 이벤트(SESSION_EXPIRED 및 AUTH_FAILED)를 받으면 ZooKeeper 개체가 무효화된다. 닫히면 두 스레드가 종료되고 Zookeeper 핸들에 대한 추가 액세스는 정의되지 않은 동작이므로 피해야 한다.
이제 ZooKeeper를 알게 되었다. 빠르고 간단하며 응용 프로그램이 작동하지만 잠시만 기다려 주십시오. 뭔가 잘못되었다. 다음은 ZooKeeper 사용자가 빠지는 몇 가지 함정이다.