분산 잠금 Zookeep

분산 잠금은 무엇입니까

개요

분산 시스템에서 여러 프로세스 간의 상호 간섭을 방지하기 위해, 우리는 이러한 프로세스를 일정을 분산 조정 기술이 필요합니다. 그리고 이것은이 달성하기 위해 분산 조정의 핵심 기술이다 분산 잠금을 .

분산 잠금 조건이 있어야합니다

  • 분산 시스템 환경에서, 방법은 동시에 기계의 하나 개의 스레드에 의해 수행 될 수있다
  • 고 가용성 잠금을 획득하고 잠금을 해제
  • 고성능 액세스를 잠그고 잠금을 해제
  • 특징은 재진입을 포함
  • 잠금 실패 메커니즘
  • 잠금 기능을 직접 리턴 로크 실패를 취득한다 로크를 획득하지 즉 비 차단을 포함

분산 잠금 실현 무엇

  • Memcached가 : 사용 memcached를 add명령을 사용합니다. 이 명령은 원자 동작이다 만으로 key하기 위해서는 부재의 add성공, 상기 스레드가 고정되어 있음을 의미한다.
  • 레디 스는 : 사용 setnx명령을 사용합니다. 이 명령은 원자 작업입니다, 만에 key순서의 부재에 set성공.
  • 사육사 : 잠금 및 분산 큐를 달성하기 위해 임시 순서를 사용하여 사육사 노드입니다. 원래 설계 사육사는 분산 락 서비스를 달성하는 것입니다.
  • 풍만는 구글이 회사는 대단위 분산 락 서비스의 Paxos 합의 알고리즘의 기본 사용을 달성했다.

레디 스 분산 잠금 구현

자물쇠

setnx(lock_sale_商品ID, 1)

의 스레드 구현하면 setnx수익 1을 나타내는, key원래는 록의 성공에, 스레드가 존재하지 않습니다 스레드가 실행되면 setnx수익을 0나타내는, key이미 존재는 스레드 잠금 실패를 잡아.

잠금 해제

스레드가 잠긴 작업이 실행 완료 얻을 때 다른 스레드가 입력 할 수 있도록, 당신은 잠금을 해제해야합니다. 가장 쉬운 방법은 잠금 해제 수행하는 del명령, 다음의 의사 코드를 :

del(lock_sale_商品ID)

잠금을 해제 한 후, 다른 스레드는 실행을 계속할 수 setnx잠금을 얻을 수있는 명령을 사용합니다.

잠그

스레드가 명시 적으로 잠금을 해제하기 위해, 너무 늦게 전화를 끊고 작업을 실행하는 동안 액세스 할 수없는 상황이 발생하면,이 자원은 항상 다른 스레드가 더 이상도 오는에 대해 생각 할 수 없다, (교착 상태) 잠 깁니다. 따라서, 필요가 명시 적으로 해제되지 경우에도 잠금이 일정 시간 후 자동으로 해제되어야 함을 확인하기 위해 시간 제한을 설정합니다. 다음과 같이 슈퍼마켓 추가 교육의 필요성, 그래서 의사 코드는 매개 변수를 지원하지 않습니다 :setnxkeysetnx

expire(lock_sale_商品ID, 30)

통합 의사 코드

if(setnx(lock_sale_商品ID, 1) == 1){
    expire(lock_sale_商品ID, 30)
    try {
        do something
    } finally {
        del(lock_sale_商品ID)
    }
}

무엇이 잘못

setnx그리고 expire비 원자

setnx그것은 수신 시간 제한을 지원하지 않습니다,하지만 당신은 사용할 수있는 set명령을하고, 선택적 매개 변수를 추가합니다 :

set(lock_sale_商品ID, 1, 30, NX)

del 실수로 삭제에 리드

del잠금을 해제하기 전에 판단을하기 위해선, 잠금 장치는 현재 자신의 잠금을 추가 확인하지 않습니다. 특정 구현 : 잠겨 때와 현재의 thread의 ID를 저장 value하고 삭제하기 전에 확인 key해당이 value자신의 스레드 ID가 아닙니다.

잠금 :

String threadId = Thread.currentThread().getId()
set(key, threadId, 30, NX)

새로운 문제가 발생할 : 잠금 해제 분석 자료와 두 개의 별도의 작업이 원자되지 않습니다 잠급니다.

if(threadId.equals(redisClient.get(key))){
    del(key)
}

분산 잠금, 교착 상태의 가능성을 감소해야하고, 작업의 원 자성을 보장하기 위해

사육사 무엇입니까

개요

사육사는 메인 프레임 관리를위한 분산 조정 서비스입니다. 분산 환경에서, 조정 및 관리 서비스는 복잡한 과정이다. 사육사는 매우 간단한 아키텍처 및 API에 의해이 문제를 해결합니다.

사육사 데이터 모델

사육사 많은 트리의 데이터 구조와 같은 데이터 모델, 너무 많이와 같은 파일 시스템 디렉토리.

트리 노드로 구성, 사육사의 데이터 저장이 동일한 노드를 기반으로, 같은 노드는 Znode 작동합니다. 트리의 다른 노드의 경우, 참조의 Znode는 파일 경로와 유사한 경로 참조입니다 :/动物/猫 /汽车/宝马

사육사 데이터 모델

원소 함유 Znode

  • 데이터 : 데이터 저장 Znode.
  • ACL : 액세스 Znode 기록, 액세스 또는 어떤 IP 노드가있는 사람들이.
  • STAT : Znode는 트랜잭션 ID, 버전 번호, 시간 스탬프 및 크기 등의 각종 메타 데이터를 포함.
  • 아이 : 현재 노드 참조의 아이입니다.

참고 : 사육사를 읽고 약간의 장면 설계를 작성하기위한. Znode 대규모 비즈니스 데이터를 저장하는 데 사용되지 않고, 상태 및 구성 정보의 작은 양을 저장하는 데 사용되며, 각 노드에 대한 최대 데이터 크기는 1MB를 초과 할 수 없다 .

사육사 的 Znode

사육사의 기본 동작

  • 노드 만들기 create
  • 노드 삭제 delete
  • 노드가 있는지 여부를 확인합니다 exists
  • 노드의 데이터를 취득 getData
  • 노드의 데이터를 설정 setData
  • 노드의 모든 노드를 가져옵니다 getChildren

상기 식에서, exests, getData, getChildren판독 동작에 속하는. 읽기 작업을 요청할 때 사육사 클라이언트, 당신은 설정할지 여부를 선택할 수 있습니다 시계 .

사육사 이벤트 알림

우리는 할 수 시계 특정 Znode 트리거에 등록하는 것으로 이해. Znode이 변경된 경우, 그 호출은 create, delete, setData클라이언트가 비동기 통지를 수신 시계 요청 시간 및 다른 방법은 해당 이벤트 등록 Znode 시작할 것이다.

특정 상호 작용 :

  • 클라이언트는 호출 getData메소드 watch매개 변수를 true. 서버가 요청을 수신하고, 상기 데이터 노드를 반환하고 시계 Znode 경로에 삽입하고, 관찰자 목록은 해시 테이블에 대응.
  • Znode이 삭제되면 시계, 서버는 모든 당직자는 Znode 해당 클라이언트의 비동기 통지를 찾아 키 - 값을 해당하는 해시 테이블을 삭제하는 해시 테이블을 찾습니다.

사육사의 일관성

독립 실행 형 멈춘를 방지하기 위해, 분산 시스템 조정 서비스로 사육사, 사육사는 클러스터 유지합니다.

사육사의 일관성

사육사 서비스 클러스터 마스터 멀티 슬레이브 구조입니다.

데이터를 업데이트 할 때, 마스터 노드의 첫번째 업데이트 노드에 동기화 (노드 본원 znode하지 서버를 말한다).

데이터를 읽을 때, 모든 노드에서 직접 읽을.

为了保证主从节点的数据一致性,Zookeeper 采用 ZAB协议,这种协议非常类似于一致性算法那 Paxos 和 Raft。

什么是ZAB协议

Zookeeper Atomic Broadcast,有效解决了 Zookeeper 集群崩溃恢复,以及主从同步数据的问题。

ZAB 协议定义的三种节点状态

  • Looking:选举状态。
  • Following:Follower节点(从节点)所处的状态。
  • Leading:Leader节点(主节点)所处状态。

最大 ZXID

最大 ZXID 也就是节点本地的最新事务编号,包含 epoch 和计数两部分。epoch是纪元的意思,相当于Raft算法选主时候的 term。

ZAB 崩溃恢复

加入 Zookeeper 当前主节点挂掉了,集群会进行奔溃恢复。ZAB 的奔溃恢复分成三个阶段:

  • Leader Election

    1. 选举阶段,此时集群中的节点处于 Looking 状态。它们会向其他节点发起投票,投票当中包含自己的服务器ID 和最新事务ID(ZXID)。
    2. 接下来,节点会用自身的 ZXID 和从其他节点接收到的 ZXID 作比较,如果发现别人家的 ZXID 比自己大,也就是数据比自己新,那么就重新发起投票,投票给目前已知最大的ZXID所属节点。
    3. 每次投票后,服务器都会统计投票数量,判断是否有某个节点得到半数以上的投票。如果存在这样的节点,该节点就会成为准 Leader,状态变成 Leading。其他节点的状态变为 Following。
  • Discovery

    发现阶段,用于在从节点中发现最新的 ZXID和事务日志(为了防止某些意外的情况,比如因网络原因在上一阶段产生了多个Leader的情况)。

    1. 在这一阶段,Leader 集思广益,接受所有Follower发来各自的最新 epoch 值。Leader从中选出最大的epoch,基于此值加 1,生成新的 epoch 分发给各个 Follower。
    2. 各个 Follower 收到全新的 epoch 后,返回 ACK 给Leader,带上各自最大的 ZXID 和历史事务日志。Leader 选出最大的ZXID,并更新自身历史日志。
  • Synchronization

    同步阶段,把 Leader 刚才收集得到的最新历史事务日志,同步给集群中所有的 Follower。只有当半数 Follower 同步成功,这个准 Leader 才能成为正式的 Leader。

    自此,故障恢复正式完成。

ZAB 的数据写入

ZAB 的数据写入涉及到 Broadcast 阶段,简单来说,就是 Zookeeper 常规情况下更新数据的时候,由 Leader 广播到所有的 Follower。其过程如下:

  • 客户端发出写入数据请求给任意 Follower。
  • Follower 把写入数据请求转发给 Leader。
  • Leader 采用二阶段提交方式,先发送 Propose 广播给 Follower。
  • Follower 接收到 Propose 消息,写入日志成功后,返回 ACK 消息给 Leader。
  • Leader 接收到半数以上 ACK 消息,返回成功给客户端,并且广播 Commit 请求给 Follower。

사육사 的 ZAB

总结

ZAB 协议既不是强一致性,也不是若一致性,而是处于两者之间的单调一致性(顺序一致性)。它依靠事务 ID 和版本号,保证了数据的更新和读取是有序的。

Zookeeper 的应用场景

分布式锁

利用 Zookeeper 的临时顺序节点,可以轻松实现分布式锁。

服务注册和发现

利用 Znode 和 Watcher,可以实现分布式服务的注册和发现。

共享配置和状态信息

Redis 的分布式解决方案 Codis,就利用了 Zookeeper 来存放数据路由表和 codis-proxy 节点的元信息。同时 codis-config 发起的命令都会通过 Zookeeper 同步到各个存活的 codis-proxy。

此外, Kafka、HBase、Hadoop,也都依靠 Zookeeper 同步节点信息,实现高可用。

Zookeeper 分布式锁

什么是临时顺序节点

Zookeeper 的数据结构就像一棵树,这棵树由节点组成,这种节点叫做 Znode。

Znode 分为四种类型:

  • 持久节点 Persistent

    默认的节点类型。创建节点的客户端与 Zookeeper 断开连接后,该节点依旧存在。

  • 持久节点顺序节点 Persistent_Sequential

    所谓顺序节点,就是在创建节点时,Zookeeper 根据创建的时间顺序给该节点名称进行编号。

  • 临时节点 Ephemeral

    与持久节点相反,当创建节点的客户端与 Zookeeper 断开连接后,临时节点会被删除。

  • 临时顺序节点 Ephemeral_Sequential

    临时顺序节点结合 临时节点和顺序节点的特点:在创建节点时,Zookeeper 根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与 Zookeeper 断开连接后,临时节点会被删除。

Zookeeper 分布式锁的原理

获取锁

  • 首先,在 Zookeeper 当中创建一个持久节点 ParentLock。当第一个客户端想要获得锁时,需要在 ParentLock 这个节点下面创建一个临时顺序节点 Lock1
  • 之后,Client1 查找 ParentLock 下面所有的临时顺序节点并排序,判断自己所创建的节点 Lock1 是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。
  • 这时候,如果再有一个客户端 Client2 前来获取锁,则在 ParentLock 下再创建一个临时顺序节点 Lock2。
  • Client2 查找 ParentLock 下面所有的临时顺序节点并排序,判断自己所创建的节点 Lock2 是不是顺序最靠前的一个,结果发现 Lock2 并不是最小的。
  • 于是,Client2 向排序仅比它靠前的节点 Lock1 注册 Watcher,用于监听 Lock1 节点是否存在。这意味着 Client2 抢锁失败,进入了等待状态。
  • 这时候,如果又有一个客户端 Client3 前来获取锁,则在 ParentLock 下载再创建一个临时顺序节点 Lock3。
  • Client3 查找 ParentLock 下面所有的临时顺序节点并排序,判断自己所创建的节点 Lock3 是不是顺序最靠前的一个,结果同样发现节点 Lock3 并不是最小的。
  • 于是,Client3 向排序仅比它靠前的节点 Lock2 注册 Watcher,用于监听 Lock2 节点是否存在。这意味着 Client3 同样抢锁失败,进入了等待状态。
  • 这样一来,Client1 得到了锁,Client2 监听了 Lock1,Client3 监听了 Lock2。这恰恰形成了一个等待队列。

释放锁

释放锁的分为两种情况:

任务完成,客户端显示释放

当任务完成时,Client1 会显示调用删除节点 Lock1 的指令。

任务执行过程中,客户端崩溃

  • 获得锁的 Client1 在执行任务过程中,如果崩溃,则会断开与 Zookeeper 服务端的链接。根据临时节点的特性,相关联的节点 Lock1 会随之自动删除。

  • 由于 Client2 一致监听着 Lock1 的存在状态,当 Lock1 节点被删除, Client2 会立即收到通知。
  • 这时候Client2 会再次查询 ParentLock 下面的所有节点,确认自己创建的 Lock2 是不是目前最小的节点。如果是最小,则 Client2 顺理成章地获得了锁。

Zookeeper 和 Redis 分布式锁的比较

分布式锁 优点 缺点
Zookeeper 1. 有封装好的框架,容易实现。
2. 有等待锁的队列,大大提升抢锁效率。
添加和删除节点性能低。
Redis Set 和 Del 指令的性能较高。 1. 구현의 복잡성, 시간 제한, 원자, 실수로 삭제 및 기타 상황을 고려하십시오.
2. 잠금 대기중인 큐는 잠금이 비효율적, 클라이언트 등 회전 할 수 없습니다.

에서 마무리 본 논문 (https://www.funtl.com/zh/apache-dubbo-zookeeper/)

추천

출처www.cnblogs.com/jianminglin/p/11442105.html