我有以下代码来生成唯一的eventId。这不是一个纯粹的GUID生成器,而是一种跨不同机器/进程生成唯一id的方法。
import java.util.concurrent.atomic.AtomicInteger
object EventIdGenerator extends Serializable {
val totalBits = 64
private val epochBits = 42
private val partitionIdBits = 10
private val sequenceBits = 12
private val sequenceInt = new AtomicInteger(0)
private val maxPartitionId = (Math.pow(2, partitionIdBits) - 1).toInt
private val maxSequenceId = (Math.pow(2, sequenceBits) - 1).toInt
def nextEventId(partitionId: Int): Long = {
assert(partitionId <= maxPartitionId)
val nextSequence = sequenceInt.incrementAndGet() % maxSequenceId
val timestamp = if (nextSequence == 0) {
Thread.sleep(1)
System.currentTimeMillis()
} else System.currentTimeMillis()
timestamp << (totalBits - epochBits) |
partitionId << (totalBits - epochBits - partitionIdBits) |
nextSequence
}
}这应该是从运行在不同机器上的几个JVM上的分布式程序调用的。在这里,分区id在不同的JVM和机器上是唯一的。
当我在单线程中运行这个程序时,它工作得很好。但是,当我在多个线程中运行它时,每个线程都使用唯一的分区id调用nextEventId,有时我会得到重复的事件id。我不知道下面的代码出了什么问题。
发布于 2019-06-08 16:06:46
您只有1024个不同的nextSequence值。因此,如果您的请求速率超过每毫秒1024 (对于一个分区),则有大约100%的机会发生冲突。事实上,我相信由于时钟精度的原因,碰撞将以更小的速率出现。
我看到如果您检测到nextSequence溢出,您会尝试使用sleep(1)来避开它。但它不能在多线程环境中工作。特定分区甚至可能永远不会看到nextSequence等于0。
https://stackoverflow.com/questions/56502044
复制相似问题