赞
踩
命名服务(Name Service)也是分布式系统中比较常见的一类场景,在《Java网络高级编程》一书中提到,命名服务是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等——这些我们都可以统称他们为名字(Name),其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供者的信息等。
Java语言中的JNDI便是一种典型的命名服务。JNDI是Java命名与目录接口(Java Naming and Directory Interface)的缩写,是J2EE体系中重要的规范之一,标准的J2EE容器都提供了对JNDI规范的实现。因此,在实际开发中,开发人员常常使用应用服务器自带的JNDI实现来完成数据源的配置与管理——使用JNDI方式后,开发人员可以完全不需要关心与数据库相关的任何信息,包括数据库类型、JDBC驱动类型以及数据库账户等。
ZooKeeper提供的命名服务功能与JNDI技术有相似的地方,都能够帮助应用系统通过一个资源引起的方式来实现对资源的定位与使用。另外,广义上命名服务的资源定位都不是真正意义的实体资源——在分布式环境中,上层应用仅仅需要一个全局唯一的名字,类似于数据库中的唯一主键。下面我们来看看如何使用ZooKeeper来实现一套分布式全局唯一ID的分配机制。
所谓ID,就是一个能够唯一标识某个对象的标识符。在我们熟悉的关系型数据库中,各个表都需要一个主键来唯一标识每条数据库记录,这个主键就是这样的唯一ID。在过去的单库单表型系统中,通常可以使用数据库字段自带的auto_increment属性来自动为每条数据库记录生成一个唯一的ID,数据库会保证生成的这个ID在全局唯一。但是随着数据库数据规模的不断增大,分库分表随之出现,而auto_increment属性仅能针对单一表中的记录自动生成ID,因此在这种情况下,就无法再依靠数据库的auto_increment属性来唯一标识一条记录了。于是,我们必须寻求一种能够在分布式环境下生成全局唯一ID的方法。
一说起全局唯一ID,相信读者都会联想到UUID。没错,UUID是通用唯一识别码(Universally Unique Identifier)的简称,是一种在分布式系统中广泛使用的用于唯一标识元素的标准,最典型的实现是GUID(Globally Unique Identifier,全局唯一标识符),主流ORM框架Hibernate有对UUID的直接支持。
确实,UUID是一个非常不错的全局唯一ID生成方式,能够非常简便的保证分布式环境中的唯一性。一个标准的UUID是一个包含32位字符和4个短线的字符串,例如“e79f1357-f260-46ff-a32d-53a086c57ade”。UUID的优势自然不必多说,我们重点来看看他的缺陷。
UUID最大的问题就在于生成的字符串过长。显然,和数据库中的INT类型相比,存储一个UUID需要花费更多的空间。
上面我们已经看到一个典型的UUID是类似于“e79f1357-f260-46ff-a32d-53a086c57ade”的一个字符串。根据这个字符串,开发人员从字面上基本看不出任何其表达的含义,这将会大大影响问题排查和开发调试的效率。
接下来,我们结合一个分布式任务调度系统来看看如何使用ZooKeeper来实现这类全局唯一ID的生成。
通过调用ZooKeeper节点创建的API接口可以创建一个顺序节点,并且在API返回值中会返回这个节点的完整名字。利用这个特性,我们就可以借助ZooKeeper来生成全局唯一的ID了,如下图所示。
结合 上图,我们来讲解对于一个任务列表的主键,使用ZooKeeper生成唯一ID的基本步骤。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。