Zookeeper:分布式命名服务
关于“分布式命名服务”
“命名服务”是为系统中的资源提供标识能力。
ZooKeeper的命名服务主要是利用 ZooKeeper节点的树形分层结构和子节点的顺序维护能力,来为分布式系统中的资源命名。
应用场景
分布式API目录:为分布式系统中各种API接口服务的名称、链接地址,提供类似 JNDI(Java命名和目录接口)中的文件系统的功能。
- 借助于 ZooKeeper 的树形分层结构就能提供分布式的API调用功能。
- 著名的 Dubbo 分布式框架就是应用了 ZooKeeper 的分布式的 JNDI 功能,大致的思路为:
- 服务提供者(Service Provider)在启动的时候,向 ZooKeeper 上的指定节点“/dubbo/${serviceName}/providers”写入自己的API地址,这个操作就相当于服务的公开。
- 服务消费者(Consumer)启动的时候,订阅节点“/dubbo/{serviceName}/providers”下的服务提供者的 URL 地址,获得所有服务提供者的API。
分布式的ID生成器:在分布式系统中,为每一个数据资源提供唯一性的ID标识功能。
- 在单体服务环境下,通常来说,可以利用数据库的主键自增功能,唯一标识一个数据资源。但是,在大量服务器集群的场景下,依赖单体服务的数据库主键自增生成唯一ID的方式,则没有办法满足高并发和高负载的需求。这时,就需要分布式的ID生成器,保障分布式场景下的ID唯一性。
- 在分布式系统中,分布式ID生成器的使用场景非常之多:
- 大量的数据记录,需要分布式ID。
- 大量的系统消息,需要分布式ID。
- 大量的请求日志,如RESTful的操作记录,需要唯一标识,以便进行后续的用户行为分析和调用链路分析。
- 分布式节点的命名服务,往往也需要分布式ID。
分布式节点的命名:一个分布式系统通常会由很多的节点组成,节点的数量不是固定的,而是不断动态变化的。
- 比如说,当业务不断膨胀和流量洪峰到来时,大量的节点可能会动态加入到集群中。而一旦流量洪峰过去了,就需要下线大量的节点。再比如说,由于机器或者网络的原因,一些节点会主动离开集群。
- 如何为大量的动态节点命名呢?一种简单的办法是可以通过配置文件,手动为每一个节点命名。但是,如果节点数据量太大,或者说变动频繁,手动命名则是不现实的,这就需要用到分布式节点的命名服务。
ID生成器
在分布式系统环境中,唯一ID系统需要满足以下需求:
- 全局唯一:不能出现重复ID。
- 高可用:ID生成系统是基础系统,被许多关键系统调用,一旦宕机,就会造成严重影响。
很明显,传统的数据库自增主键或者单体的自增主键,已经不能满足需求。
可能的分布式ID生成器方案:
- Java的UUID。
- 分布式缓存Redis生成ID:利用 Redis 的原子操作 INCR 和 INCRBY,生成全局唯一的ID。
- Twitter 的 SnowFlake 算法。
- ZooKeeper 生成ID:利用ZooKeeper的顺序节点,生成全局唯一的ID。
- MongoDb 的 ObjectId:【???】
- MongoDB是一个分布式的非结构化 NoSQL 数据库,每插入一条记录会自动生成全局唯一的一个“_id”字段值,它是一个 12 字节的字符串,可以作为分布式系统中全局唯一的ID。
P.S. 关于“UUID”:
UUID 是“Universally Unique Identifier”的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符,所以,UUID 在其他语言中也叫“GUID”。 在Java中,生成UUID的代码: String uuid = UUID.randomUUID().toString() UUID是经由一定的算法机器生成的,为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。【UUID只能由计算机生成】 优点:UUID的优点是本地生成ID,不需要进行远程调用,时延低,性能高。 缺点: 1、UUID过长,16字节共128位,通常以36字节长的字符串来表示,在很多应用场景不适用。 2、UUID没有排序,无法保证趋势递增。
Zookeeper:分布式命名服务
ZooKeeper 实现分布式命名服务(分布式ID、分布式节点命名),主要是利用其顺序节点的特性:
ZooKeeper 的每一个节点都会为它的第一级子节点维护一份顺序编号(自动为创建后的节点路径在末尾加上一个数字),用于记录每个子节点创建的先后顺序,这个顺序编号是分布式同步的,也是全局唯一的。 例如,在创建节点的时候只需要传入节点“/test_”,ZooKeeper自动会在“test_”后面补充数字顺序,例如“/test_0000000010”。 note:这个顺序值的最大上限就是整型的最大值。
在 ZooKeeper 节点的四种类型中,有两种自动编号的节点:
- PERSISTENT_SEQUENTIAL:持久化顺序节点,节点持久有效,可用于实现“分布式ID”。
- EPHEMERAL_SEQUENTIAL:临时顺序节点,节点随会话失效而删除,可用于实现“分布式节点命名”。