命名服务(Name Service)也是分布式系统中比较常见的一类场景,是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等——这些我们都可以统称它们为名字(Name),其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供者的信息等。
ZooKeeper 提供的命名服务功能能够帮助应用系统通过一个资源引用的方式来实现对资源的定位与使用。另外,广义上命名服务的资源定位都不是真正意义的实体资源——在分布式环境中,上层应用仅仅需要一个全局唯一的名字,类似于数据库中的唯一主键。
所以接下来。我们来看看如何使用ZooKeeper来实现一套分布式全局唯一ID的分配机制所谓ID,就是一个能够唯一标识某个对象的标识符。在我们熟悉的关系型数据库中,各个表都需要一个主键来唯一标识每条数据库记录,这个主键就是这样的唯一ID。在过去的单库单表型系统中,通常可以使用数据库字段自带的auto_increment属性来自动为每条数据库记录生成一个唯一的ID,数据库会保证生成的这个ID在全局唯一。但是随着数据库数据规模的不断增大,分库分表随之出现,而auto_increment属性仅能针对单一表中的记录自动生成ID,因此在这种情况下,就无法再依靠数据库的auto_increment属性来唯一标识一条记录了。于是,我们必须寻求一种能够在分布式环境下生成全局唯一ID的方法。
一说起全局唯一 ID,相信大家都会联想到 UUID。没错,UUID 是通用唯一识别码(Universally Unique Identifier)的简称,是一种在分布式系统中广泛使用的用于唯一标识元素的标准 确实,UUID是一个非常不错的全局唯一ID生成方式,能够非常简便地保证分布式环境中的唯一性。一个标准的 UUID 是一个包含 32 位字符和 4 个短线的字符串,例如“e70f1357-f260-46ff-a32d-53a086c57ade”。UUID的优势自然不必多说,我们重点来看看它的缺陷。
长度过长
UUID 最大的问题就在于生成的字符串过长。显然,和数据库中的 INT 类型相比,存储一个UUID需要花费更多的空间。
含义不明
上面我们已经看到一个典型的 UUID 是类似于“e70f1357-f260-46ff-a32d-53a086c57ade”的一个字符串。根据这个字符串,开发人员从字面上基本看不出任何其表达的含义,这将会大大影响问题排查和开发调试的效率。
所以接下来,我们结合一个分布式任务调度系统来看看如何使用ZooKeepe来实现这类全局唯一ID的生成。 之前我们已经提到,通过调用ZooKeeper节点创建的API接口可以创建一个顺序节点,并且在API返回值中会返回这个节点的完整名字。利用这个特性,我们就可以借助ZooKeeper来生成全局唯一的ID了,如下图:
全局唯一ID生成的ZooKeeper节点示意图
说明,对于一个任务列表的主键,使用ZooKeeper生成唯一ID的基本步骤:
所有客户端都会根据自己的任务类型,在指定类型的任务下面通过调用create()接口来创建一个顺序节点,例如创建“job-”节点。
节点创建完毕后,create()接口会返回一个完整的节点名,例如“job-0000000003”。
客户端拿到这个返回值后,拼接上 type 类型,例如“type2-job-0000000003”,这就可以作为一个全局唯一的ID了。
在ZooKeeper中,每一个数据节点都能够维护一份子节点的顺序顺列,当客户端对其创建一个顺序子节点的时候 ZooKeeper 会自动以后缀的形式在其子节点上添加一个序号,在这个场景中就是利用了ZooKeeper的这个特性。
猜你喜欢:
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/253711.html