我一般在过去使用数据库序列实现序列号生成.
例如,使用Postgres SERIAL类型http://www.neilconway.org/docs/sequences/
我很好奇,因为如何为没有数据库的大型分布式系统生成序列号.对于多个客户端,是否有任何经验或建议以线程安全的方式生成序列号生成的最佳实践?
好的,这是一个非常古老的问题,我现在才开始看到.
您需要区分序列号和唯一ID(可选)按特定条件(通常为生成时间)进行松散排序.真正的序列号意味着知道所有其他工作者所做的事情,因此需要共享状态.没有简单的方法以分布式,高规模的方式这样做.您可以查看网络广播,每个工作程序的窗口范围以及唯一工作程序ID的分布式哈希表等内容,但这需要做很多工作.
唯一ID是另一个问题,有几种以分散方式生成唯一ID的好方法:
a)您可以使用Twitter的Snowflake ID网络服务.雪花是:
网络服务,即您进行网络呼叫以获取唯一ID;
它产生64位唯一ID,按生成时间排序;
该服务具有高度可扩展性和(可能)高度可用性; 每个实例每秒可以生成数千个ID,您可以在LAN/WAN上运行多个实例;
用Scala编写,在JVM上运行.
b)您可以使用从UUID和Snowflake ID的制作方法得出的方法在客户端本身生成唯一ID .有多种选择,但有以下几点:
最重要的40位左右:时间戳; ID的生成时间.(我们使用时间戳的最高位来按生成时间对ID进行排序.)
接下来的14位左右:每个发生器计数器,每个生成器为每个生成的新ID递增1.这可确保在同一时刻生成的ID(相同时间戳)不重叠.
最后10位:每个发生器的唯一值.使用它,我们不需要在生成器之间进行任何同步(这非常困难),因为所有生成器都会因为此值而生成非重叠的ID.
c)您可以仅使用时间戳和随机值在客户端上生成ID .这避免了需要知道所有生成器,并为每个生成器分配唯一值.另一方面,这些ID不能保证全局唯一,它们很可能是唯一的.(要碰撞,一个或多个生成器必须在同一时间创建相同的随机值.)以下内容:
最重要的32位:时间戳, ID的生成时间.
最低有效32位:32位随机性,为每个ID重新生成.
d)简单的方法,使用UUID/GUID.
现在有更多的选择.
你这个问题是"老",我来到这里,所以我认为留下我所知道的选项(到目前为止)可能是有用的:
你可以试试Hazelcast.在它的1.9版本中,它包含了java.util.concurrent.AtomicLong的Distributed实现
您也可以使用Zookeeper.它提供了创建序列节点的方法(附加到znode名称,我更喜欢使用节点的版本号).你要小心这一点:如果你不想在你的序列中错过数字,它可能不是你想要的.
干杯
您可以让每个节点都有一个唯一的ID(无论如何都可以使用),然后将其添加到序列号中.
例如,节点1生成序列001-00001 001-00002 001-00003等,节点5生成005-00001 005-00002
独特 :-)
或者,如果你想要某种集中式系统,你可以考虑让你的序列服务器以块的形式给出.这显着降低了开销.例如,不是从中央服务器请求必须分配的每个ID的新ID,而是从中央服务器请求10,000个块的ID,然后在用完时只需要执行另一个网络请求.
它可以用Redisson完成.它实现了分布式和可扩展的版本AtomicLong
.这是一个例子:
Config config = new Config(); config.addAddress("some.server.com:8291"); Redisson redisson = Redisson.create(config); RAtomicLong atomicLong = redisson.getAtomicLong("anyAtomicLong"); atomicLong.incrementAndGet();
如果它真的必须是全局顺序的,而不仅仅是唯一的,那么我会考虑创建一个简单的服务来分配这些数字.
分布式系统依赖于大量的小服务交互,对于这种简单的任务,您真的需要或者您真的会从其他复杂的分布式解决方案中受益吗?
有一些策略; 但我知道的任何一个都不能真正分布并给出真实的序列.
有一个中央数字生成器.它不一定是一个大数据库. memcached
有一个快速的原子计数器,在绝大多数情况下它对你的整个集群来说足够快.
为每个节点分隔一个整数范围(如Steven Schlanskter的回答)
使用随机数或UUID
使用某些数据块,与该节点的ID一起,和散列它的所有(或HMAC它)
就个人而言,我倾向于UUID,或者如果我想拥有一个大部分连续的空间,那就是memcached.