分布式id生成算法SnowFlake的使用(Scala版本)

1. 源码和使用场景

源码地址位于github snowFlake

SnowFlake可以保证:

  • 所有生成的id按时间趋势递增
  • 整个分布式系统内不会产生重复id(使用datacenterId和workerId来区分)

2. 基于源码进行修改

修改后的程序如下

/** Copyright 2010-2012 Twitter, Inc.*/

/** 根据如下的源码进行修改的
 * https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala */


/**
 * An object that generates IDs.
 * This is broken into a separate class in case
 * we ever want to support multiple worker threads
 * per process
 */
class IdWorker(val workerId: Long, val datacenterId: Long, var sequence: Long = 0L) {

  val twepoch = 1288834974657L

  private[this] val workerIdBits = 5L
  private[this] val datacenterIdBits = 5L
  private[this] val maxWorkerId = -1L ^ (-1L << workerIdBits)
  private[this] val maxDatacenterId = -1L ^ (-1L << datacenterIdBits)
  private[this] val sequenceBits = 12L

  private[this] val workerIdShift = sequenceBits
  private[this] val datacenterIdShift = sequenceBits + workerIdBits
  private[this] val timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits
  private[this] val sequenceMask = -1L ^ (-1L << sequenceBits)

  private[this] var lastTimestamp = -1L

  // sanity check for workerId
  if (workerId > maxWorkerId || workerId < 0) {
    throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0".format(maxWorkerId))
  }

  if (datacenterId > maxDatacenterId || datacenterId < 0) {
    throw new IllegalArgumentException("datacenter Id can't be greater than %d or less than 0".format(maxDatacenterId))
  }

  println(s"worker starting. timestamp left shift ${timestampLeftShift}, " +
    s"datacenter id bits ${datacenterIdBits}, worker id bits ${workerIdBits}, " +
    s"sequence bits ${sequenceBits}, workerid ${workerId}")


  def get_worker_id(): Long = workerId
  def get_datacenter_id(): Long = datacenterId
  def get_timestamp() = System.currentTimeMillis

  def nextId(): Long = synchronized {
    var timestamp = timeGen()

    if (timestamp < lastTimestamp) {
      printf(s"clock is moving backwards.  Rejecting requests until ${lastTimestamp}.")
      throw new RuntimeException("Clock moved backwards.  Refusing to generate id for %d milliseconds".format(
        lastTimestamp - timestamp))
    }

    if (lastTimestamp == timestamp) {
      sequence = (sequence + 1) & sequenceMask
      if (sequence == 0) {
        timestamp = tilNextMillis(lastTimestamp)
      }
    } else {
      sequence = 0
    }

    lastTimestamp = timestamp
    ((timestamp - twepoch) << timestampLeftShift) |
      (datacenterId << datacenterIdShift) |
      (workerId << workerIdShift) |
      sequence
  }

  protected def tilNextMillis(lastTimestamp: Long): Long = {
    var timestamp = timeGen()
    while (timestamp <= lastTimestamp) {
      timestamp = timeGen()
    }
    timestamp
  }

  protected def timeGen(): Long = System.currentTimeMillis()

}

3. 生成分布式的ID

import java.net.InetAddress

object IdWorkerTest {

  def main(args: Array[String]): Unit = {

    // 暂时采用获取IP,然后取模的方法。可能会存在两台服务器产生相同的workId,产生相同的ID
    val ip:String = InetAddress.getLocalHost().getHostAddress()
    val workerId:Long = ip.replaceAll("\\.", "").toLong

    val idWorker = new IdWorker(workerId % 32, 1)
    for (index <- 1 to 10) {
      println(idWorker.nextId())
    }


  }

}

运行程序,结果如下

worker starting. timestamp left shift 22, datacenter id bits 5, worker id bits 5, sequence bits 12, workerid 7
1535189744345051136
1535189744345051137
1535189744345051138
1535189744345051139
1535189744345051140
1535189744345051141
1535189744345051142
1535189744345051143
1535189744345051144
1535189744345051145

猜你喜欢

转载自blog.csdn.net/yy8623977/article/details/125225414