zookeepeer ID生成器 (一)

目录

  • 写在前面
  • 1.1. ZK 的分布式命名服务
  • 1.1.1. 分布式 ID 生成器的类型
  • UUID方案
  • 1.1.2. ZK生成分布式ID
  • 写在最后
  • 疯狂创客圈 亿级流量 高并发IM 实战 系列

疯狂创客圈 Java 分布式聊天室【 亿级流量】实战系列之 -25【 博客园 总入口


写在前面

? 大家好,我是作者尼恩。目前和几个小伙伴一起,组织了一个高并发的实战社群【疯狂创客圈】。正在开始高并发、亿级流程的 IM 聊天程序 学习和实战

? 前面,已经完成一个高性能的 Java 聊天程序的四件大事:

接下来,需要进入到分布式开发的环节了。 分布式的中间件,疯狂创客圈的小伙伴们,一致的选择了zookeeper,不仅仅是由于其在大数据领域,太有名了。更重要的是,很多的著名框架,都使用了zk。

? 本篇介绍 ZK 的分布式命名服务 中的 分布式ID生成器。

1.1. ZK 的分布式命名服务

zookeeper的命名服务,主要是利用zookeepeer节点的树型分层结构和子节点的次序维护能力,为分布式系统中的资源命名与标识能力。

zookeeper的分布式命名服务,典型的应用场景有:

(1)提供分布式JNDI的API目录服务功能。

可以把系统中各种API接口服务的名称、链接地址放在zookeeper的树形分层结果中,提供分布式的API调用能力。著名的分布式框架,就是应用了zookeeper的分布式的JNDI能力。

开源的分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务,维护全局的服务接口API地址列表。在Dubbo实现中,provider服务提供者在启动的时候,向ZK上的指定节点/dubbo/${serviceName}/providers文件夹下写入自己的API地址,这个操作就相当于服务的公开。

consumer服务消费者启动的时候,订阅节点/dubbo/{serviceName}/providers文件夹下的provider服务提供者URL地址,获得所有的访问提供者的API。

(2)制作分布式的ID生成器,为分布式系统中的每一个数据资源,提供的唯一的标识能力。

在单体服务环境下,我们唯一标识一个数据资源,通常利用数据库的主键自增功能。但是在大量服务器集群的场景下,依赖单体服务的数据库主键自增生成唯一ID,没有办法满足高并发和高负载的需求。

(3)分布式节点的命名服务

一个分布式系统会有很多的节点组成,而且,节点的数量是不断动态变化的。根据业务的膨胀需要和迎接流量洪峰,可能会加入大量的动态很多节点。流量洪峰过去,就需要下线大量的节点。或者说,由于机器或者网络的原因,一些节点主动的离开的集群。

如何为大量的动态节点命名呢?一种简单的办法是,可以通过配置文件,手动的进行每一个节点的命名。但是如果节点数据量太大,或者说变动频繁,手动命名是不现实的,这就需要用到分布式节点的命名服务。

疯狂创客圈的分布式IM实战项目,也会使用分布式命名服务,为每一个IM节点动态命名。

1.1.1. 分布式 ID 生成器的类型

在分布式系统中,ID生成器的使用场景,非常非常多:

(1)大量的数据记录,需要分布式ID

(2)大量的系统消息,需要分布式ID

(3)大量的请求日志,如http请求记录,需要唯一标识,以便进行后续的用户行为分析和调用链路分析,等等等等。

传统的数据库自增主键,或者单体的自增主键,已经不能满足需求。在分布式系统环境中,迫切需要一个全新的唯一ID的系统,这个系统需要满足以下需求:

(1)全局唯一:不能出现重复ID

(2)高可用:ID生成系统是基础系统,被许多关键系统调用,一旦宕机,会造成严重影响。

分布式唯一ID生成分案有很多种:

(1) java的UUID

(2) 利用分布式缓存Redis生成ID

利用Redis的原子操作INCR和INCRBY,生成全局唯一的ID。

(3) Twitter的snowflake算法

(4) ZooKeeper生成ID

利用ZooKeeper 的顺序节点,生成全局唯一的ID。

(5) MongoDb的ObjectId

利用分布式Nosql MongDB,生成全局唯一的ID。

首先分析一下java语言中的 UUID方案。

UUID方案

UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符。UUID在其他语言中也叫GUID,在java中,生成UUID的代码很简单:

String uuid = UUID.randomUUID().toString()

一个UUID是16字节长的数字,一共128位。通常以36字节的字符串表示,比如:3F2504E0-4F89-11D3-9A0C-0305E82C3301。 使用的时候,可以把中间的4个中划线去掉,剩下32位字符串。

UUID经由一定的算法机器生成,为了保证UUID的唯一性,规范定义了包括网卡MAC地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,以及从这些元素生成UUID的算法。UUID的只能由计算机生成。

UUID的优点:本地生成ID,不需要进行远程调用,时延低,性能高。

UUID的缺点:UUID过长,16字节128位,通常以36长度的字符串表示,很多场景不适用,比如,由于UUID没有排序,无法保证趋势递增,用做数据库索引字段的效率就很低,新增记录存储入库时性能差

从高并发,高可用的角度出发,通过ZooKeeper实现分布式系统唯一ID的方案,是最为合适的解决方案之一。

1.1.2. ZK生成分布式ID

通过创建ZK的顺序模式的节点,可以生成全局唯一的ID。

代码如下:


    private String createSeqNode(String pathPefix) {
      try {
            // 创建一个 ZNode 顺序节点
            String destPath = client.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.*EPHEMERAL_SEQUENTIAL*)
//避免zookeeper的顺序节点暴增,可以删除创建的顺序节点
                    .forPath(pathPefix);
            return destPath;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

节点创建完成后,会返回节点的完整的层次路径,生成的序号,放置在路径的末尾。一般为10位数字字符。

通过截取路径末尾的数字,作为新生成的ID。截取数字的代码如下:

public String makeId(String nodeName) {
    String str = createSeqNode(nodeName);
    if (null == str) {
        return null;
    }
    int index = str.lastIndexOf(nodeName);
    if (index >= 0) {
        index += nodeName.length();
        return index <= str.length() ? str.substring(index) : "";
    }
    return str;
}

调用的代码如下:

*/\*** ** create by 尼恩 @ 疯狂创客圈* **\*/*@Slf4j
public class IDMakerTester {
    @Test
    public void testMakeId() {
        IDMaker idMaker = new IDMaker();
        idMaker.init();
        String nodeName = "/test/IDMaker/ID-";
        for (int i = 0; i < 10; i++) {
            String id = idMaker.makeId(nodeName);
            log.info("第"+ i + "个创建的id为:" + id);
        }
        idMaker.destroy();
    }
}

下面是部分的运行输出:


第0个创建的id为:0000000010

第1个创建的id为:0000000011

写在最后

?

? 下一篇:基于 zookeeper 实现snowflake 算法 。


疯狂创客圈 亿级流量 高并发IM 实战 系列

  • Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战
  • Netty 源码、原理、JAVA NIO 原理
  • Java 面试题 一网打尽
  • 疯狂创客圈 【 博客园 总入口 】

原文地址:https://www.cnblogs.com/crazymakercircle/p/10226849.html

时间: 2024-11-05 20:41:27

zookeepeer ID生成器 (一)的相关文章

分布式ID生成器 zz

简介 这个是根据twitter的snowflake来写的.这里有中文的介绍. 如上图所示,一个64位ID,除了最左边的符号位不用(固定为0,以保证生成的ID都是正数),还剩余63位可用. 下面的代码与图中的位数分配略有不同,除了中间部分10bit工作机器id不变,时间戳和序列号的位数是可以根据自己的需求变化的,就是说,你可以把中间的工作机器ID往左挪一挪,或往右挪一挪. 代码 /// <summary> /// 64位ID生成器,最高位为符号位,始终为0,可用位数63. /// 实例编号占10

业务系统需要什么样的ID生成器

业务系统需要什么样的ID生成器 ID 生成器在微博我们一直叫发号器,微博就是用这样的号来存储,而我微博里讨论的时候也都是以发号器为标签.它的主要目的确如平常大家理解的“为一个分布式系统的数据object产生一个唯一的标识”,但其实在一个真实的系统里可能也可以承担更多的作用.概括起来主要有以下几点: 唯一性 时间相关 粗略有序 可反解 可制造 下面我会分别讲每个作用后面的考虑和权衡,也会对比介绍一下业界已知的几种 ID 设计. 要唯一性,是否需要全局唯一? 说起全局唯一,通常大家都会在想到发号器服

Jedis使用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】(转)

前段时间细节的了解了Jedis的使用,Jedis是redis的java版本的客户端实现.本文做个总结,主要分享如下内容: [pipeline][分布式的id生成器][分布式锁[watch][multi]][redis分布式]好了,一个一个来.一. Pipeline官方的说明是:starts a pipeline,which is a very efficient way to send lots of command and read all the responses when you fin

DRP之id生成器及锁的思考

写这篇博文的背景,是发生在前段时间的评教系统,评教系统出现瘫痪,为了找出问题,大家加班加点,找出的问题就是一个字:"锁",由于评教系统会频繁的出现学生对数据库的查询,修改,查询,修改,这样就产生了一个进程资源不够,产生死锁! 在进行DRP项目中,id生成器的原理与我原先评教系统的机制是大致相同的,id加1,然后接着查询id,反复进行此操作,如果一个人,小数据量的在进行,系统不会报错,但是,米老师一直提出"大数据",我们做出的软件不是一个人在使用.如何避免这样的问题.

全局唯一ID生成器(Snowflake ID组成)

Snowflake ID组成 Snowflake ID有64bits长,由以下三部分组成: time—42bits,精确到ms,那就意味着其可以表示长达(2^42-1)/(1000360024*365)=139.5年,另外使用者可以自己定义一个开始纪元(epoch),然后用(当前时间-开始纪元)算出time,这表示在time这个部分在140年的时间里是不会重复的,官方文档在这里写成了41bits,应该是写错了.另外,这里用time还有一个很重要的原因,就是可以直接更具time进行排序,对于twi

分布式唯一id生成器的想法

0x01 起因 前端时间遇到一个问题,怎么快速生成唯一的id,后来采用了hashid的方法.最近在网上读到了美团关于分布式唯一id生成器的解决方案, 其中提到了三种生成法:(建议看一下这篇文章,写得很详细,分析到位) UUID 数据库生成 类snowflake方案 0x02 问题 文中提到了如下几个问题 1.全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求. 2.趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数

分布式全局ID生成器设计

项目是分布式的架构,需要设计一款分布式全局ID,参照了多种方案,博主最后基于snowflake的算法设计了一款自用ID生成器.具有以下优势: 保证分布式场景下生成的ID是全局唯一的 生成的全局ID整体上是呈自增趋势的,也就是说整体是粗略有序的 高性能,能快速产生ID,本机(I7-6400HQ)单线程可以达到每秒生成近40万个ID 只占64bit位空间,可以根据业务需求扩展在前缀或后缀拼接业务标志位转化为字符串. UUID方案 UUID:UUID长度128bit,32个16进制字符,占用存储空间多

高并发场景下System.currentTimeMillis()的性能问题的优化 以及SnowFlakeIdWorker高性能ID生成器

package xxx; import java.sql.Timestamp; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; /** * 高并发场景下System.currentTimeMillis()的性能问题的优化 * <p><p> * System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我还没测试过,有人说是100

分布式唯一ID生成器Twitter

分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成. /** * Twitter_Snowflake<br> * SnowFlake的结构如下(每部分用-分开):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 -