Java 分布式序列号生成?

Java 分布式序列号生成?,java,apache-zookeeper,sequences,Java,Apache Zookeeper,Sequences,过去我通常使用数据库序列来实现序列号生成 e、 g.使用Postgres串行类型 不过,我很好奇如何为没有数据库的大型分布式系统生成序列号。是否有人对以线程安全的方式为多个客户端生成序列号的最佳实践有任何经验或建议?您可以让每个节点都有一个唯一的ID(无论如何都可以),然后在序列号前面加上该ID 例如,节点1生成序列001-00001 001-00002 001-00003等,节点5生成005-00001 005-00002 唯一:-) 交替地,如果你想要某种集中式系统,你可以考虑让你的序列服务

过去我通常使用数据库序列来实现序列号生成

e、 g.使用Postgres串行类型


不过,我很好奇如何为没有数据库的大型分布式系统生成序列号。是否有人对以线程安全的方式为多个客户端生成序列号的最佳实践有任何经验或建议?

您可以让每个节点都有一个唯一的ID(无论如何都可以),然后在序列号前面加上该ID

例如,节点1生成序列001-00001 001-00002 001-00003等,节点5生成005-00001 005-00002

唯一:-)

交替地,如果你想要某种集中式系统,你可以考虑让你的序列服务器在块中发布。这大大减少了开销。例如,您不必为每个必须分配的ID从中央服务器请求新ID,而是从中央服务器请求10000个块的ID,然后在用完时只需执行另一个网络请求。

为什么不使用(线程安全的)UUID生成器

我可能应该对此进行详细阐述

UUID保证是全局唯一的(如果您避免使用基于随机数的UUID,其中唯一性非常可能)

无论使用多少UUID生成器,每个UUID的全局唯一性都可以满足您的“分布式”需求

选择“线程安全”UUID生成器可以满足您的“线程安全”要求

假设每个UUID的保证全局唯一性满足您的“序列号”要求


请注意,许多数据库序列号实现(例如Oracle)不能保证序列号单调递增或(甚至)递增(基于每个“连接”)。这是因为在每个连接的基础上,在“缓存”块中分配连续的一批序列号。这保证了全局唯一性并保持足够的速度。但是当多个连接分配时,实际分配的序列号(随着时间的推移)可能会混淆分布式系统依赖于大量的小型服务交互,对于这类简单的任务,您真的需要或者真的会从其他复杂的分布式解决方案中获益吗?

有几种策略;但我所知道的没有一个能真正分布并给出真正的序列

  • 有一个中央号码发生器。它不必是一个大数据库
    memcached
    有一个快速的原子计数器,在绝大多数情况下,它对于整个集群来说都足够快
  • 为每个节点分隔一个整数范围(类似)
  • 使用随机数或UUID
  • 使用一些数据和节点的ID,并将其全部(或全部)散列

  • 就我个人而言,如果我想拥有一个大部分连续的空间,我会倾向于使用uuid或memcached。

    现在有了更多的选择

    虽然这个问题是“老问题”,但我到了这里,所以我认为留下我知道的选项(到目前为止)可能会有用:

    • 你可以试试。在1.9版本中,它包括java.util.concurrent.AtomicLong的分布式实现
    • 您也可以使用。它提供了创建序列节点的方法(附加到znode名称之后,尽管我更喜欢使用节点的版本号)。但要注意这一点:如果你不希望序列中出现遗漏的数字,它可能不是你想要的

    干杯

    好的,这是一个非常老的问题,我现在第一次看到这个问题。

    您需要区分序列号唯一ID,它们(可选)可以根据特定标准(通常是生成时间)进行松散排序。真正的序列号意味着知道所有其他工作人员都做了什么,因此需要共享状态。没有一种简单的方法可以以分布式、大规模的方式实现这一点。您可以查看网络广播、每个工作人员的窗口范围等内容,但这需要大量的工作

    唯一ID是另一个问题,有几种以分散方式生成唯一ID的好方法:

    a)您可以使用。雪花是:

    • 网络服务,即您通过网络呼叫获取唯一ID
    • 生成按生成时间排序的64位唯一ID
    • 该服务具有高度可扩展性和(潜在)高可用性;每个实例每秒可以生成数千个ID,您可以在LAN/WAN上运行多个实例
    • 用Scala编写,在JVM上运行
    b) 您可以使用派生自的方法在客户机上生成唯一的ID,并生成Snowflake的ID。有多个选项,但大致如下:

    • 最高有效位约40位:时间戳ID的生成时间。(我们使用时间戳的最高有效位使ID可以按生成时间排序。)

    • 接下来的14位左右:每个生成器一个计数器,每个生成器为生成的每个新ID递增一位。这确保了在同一时刻(相同的时间戳)生成的ID不会重叠

    • 最后10位左右:每个生成器都有一个唯一的值。使用这个值,我们不需要在生成器之间进行任何同步(这非常困难),因为所有生成器都会因为这个值而生成不重叠的ID

    c) 您可以在客户机上生成ID,只需使用时间戳和随机值。这避免了了解所有ge的需要
    Config config = new Config();
    config.addAddress("some.server.com:8291");
    
    Redisson redisson = Redisson.create(config);
    RAtomicLong atomicLong = redisson.getAtomicLong("anyAtomicLong");
    atomicLong.incrementAndGet();
    
    CREATE DATABASE example;
    USE example;
    CREATE TABLE offsets (partition INTEGER, offset LONG, PRIMARY KEY (partition));
    INSERT offsets VALUES (1,0);
    
    SELECT @offset := offset from offsets WHERE partition=1 FOR UPDATE;
    UPDATE offsets set offset=@offset+1 WHERE partition=1;
    
    SELECT @offset := offset from offsets WHERE partition=1 FOR UPDATE;
    UPDATE offsets set offset=@offset+100 WHERE partition=1;