分布式ID生成器
最近会写一篇分布式的ID生成器的文章,先占位。借鉴Mongodb的ObjectId的生成:
4byte时间戳 + 3byte机器标识 + 2byte PID + 3byte自增id
简单代码:
import com.google.common.base.Objects;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.Enumeration;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * <p>A globally unique identifier for objects.</p>
 * <p/>
 * <p>Consists of 12 bytes, divided as follows:</p>
 * <table border="1">
 * <caption>ObjectID layout</caption>
 * <tr>
 * <td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td>
 * </tr>
 * <tr>
 * <td colspan="4">time</td><td colspan="3">machine</td> <td colspan="2">pid</td><td colspan="3">inc</td>
 * </tr>
 * </table>
 * <p/>
 * <p>Instances of this class are immutable.</p>
 */
public class ObjectId implements Comparable<ObjectId>, java.io.Serializable {
    private final int _time;
    private final int _machine;
    private final int _inc;
    private boolean _new;
    private static final int _genmachine;
    private static AtomicInteger _nextInc = new AtomicInteger((new java.util.Random()).nextInt());
    private static final long serialVersionUID = -4415279469780082174L;
    private static final Logger LOGGER = Logger.getLogger("org.bson.ObjectId");
    /**
     * Create a new object id.
     */
    public ObjectId() {
        _time = (int) (System.currentTimeMillis() / 1000);
        _machine = _genmachine;
        _inc = _nextInc.getAndIncrement();
        _new = true;
    }
    /**
     * Gets a new object id.
     *
     * @return the new id
     */
    public static ObjectId get() {
        return new ObjectId();
    }
    /**
     * Checks if a string could be an {@code ObjectId}.
     *
     * @param s a potential ObjectId as a String.
     * @return whether the string could be an object id
     * @throws IllegalArgumentException if hexString is null
     */
    public static boolean isValid(String s) {
        if (s == null)
            return false;
        final int len = s.length();
        if (len != 24)
            return false;
        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            if (c >= '0' && c <= '9')
                continue;
            if (c >= 'a' && c <= 'f')
                continue;
            if (c >= 'A' && c <= 'F')
                continue;
            return false;
        }
        return true;
    }
    /**
     * Converts this instance into a 24-byte hexadecimal string representation.
     *
     * @return a string representation of the ObjectId in hexadecimal format
     */
    public String toHexString() {
        final StringBuilder buf = new StringBuilder(24);
        for (final byte b : toByteArray()) {
            buf.append(String.format("%02x", b & 0xff));
        }
        return buf.toString();
    }
    /**
     * Convert to a byte array.  Note that the numbers are stored in big-endian order.
     *
     * @return the byte array
     */
    public byte[] toByteArray() {
        byte b[] = new byte[12];
        ByteBuffer bb = ByteBuffer.wrap(b);
        // by default BB is big endian like we need
        bb.putInt(_time);
        bb.putInt(_machine);
        bb.putInt(_inc);
        return b;
    }
    private int _compareUnsigned(int i, int j) {
        long li = 0xFFFFFFFFL;
        li = i & li;
        long lj = 0xFFFFFFFFL;
        lj = j & lj;
        long diff = li - lj;
        if (diff < Integer.MIN_VALUE)
            return Integer.MIN_VALUE;
        if (diff > Integer.MAX_VALUE)
            return Integer.MAX_VALUE;
        return (int) diff;
    }
    public int compareTo(ObjectId id) {
        if (id == null)
            return -1;
        int x = _compareUnsigned(_time, id._time);
        if (x != 0)
            return x;
        x = _compareUnsigned(_machine, id._machine);
        if (x != 0)
            return x;
        return _compareUnsigned(_inc, id._inc);
    }
    /**
     * Gets the timestamp (number of seconds since the Unix epoch).
     *
     * @return the timestamp
     */
    public int getTimestamp() {
        return _time;
    }
    /**
     * Gets the timestamp as a {@code Date} instance.
     *
     * @return the Date
     */
    public Date getDate() {
        return new Date(_time * 1000L);
    }
    /**
     * Gets the current value of the auto-incrementing counter.
     *
     * @return the current counter value.
     */
    public static int getCurrentCounter() {
        return _nextInc.get();
    }
    static {
        try {
            // build a 2-byte machine piece based on NICs info
            int machinePiece;
            {
                try {
                    StringBuilder sb = new StringBuilder();
                    Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
                    while (e.hasMoreElements()) {
                        NetworkInterface ni = e.nextElement();
                        sb.append(ni.toString());
                    }
                    machinePiece = sb.toString().hashCode() << 16;
                } catch (Throwable e) {
                    // exception sometimes happens with IBM JVM, use random
                    LOGGER.log(Level.WARNING, e.getMessage(), e);
                    machinePiece = (new Random().nextInt()) << 16;
                }
                LOGGER.fine("machine piece post: " + Integer.toHexString(machinePiece));
            }
            // add a 2 byte process piece. It must represent not only the JVM but the class loader.
            // Since static var belong to class loader there could be collisions otherwise
            final int processPiece;
            {
                int processId = new java.util.Random().nextInt();
                try {
                    processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
                } catch (Throwable t) {
                }
                ClassLoader loader = ObjectId.class.getClassLoader();
                int loaderId = loader != null ? System.identityHashCode(loader) : 0;
                StringBuilder sb = new StringBuilder();
                sb.append(Integer.toHexString(processId));
                sb.append(Integer.toHexString(loaderId));
                processPiece = sb.toString().hashCode() & 0xFFFF;
                LOGGER.fine("process piece: " + Integer.toHexString(processPiece));
            }
            _genmachine = machinePiece | processPiece;
            LOGGER.fine("machine : " + Integer.toHexString(_genmachine));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ObjectId that = (ObjectId) o;
        return Objects.equal(this.serialVersionUID, that.serialVersionUID) &&
                Objects.equal(this.LOGGER, that.LOGGER) &&
                Objects.equal(this._time, that._time) &&
                Objects.equal(this._machine, that._machine) &&
                Objects.equal(this._inc, that._inc) &&
                Objects.equal(this._new, that._new) &&
                Objects.equal(this._nextInc, that._nextInc) &&
                Objects.equal(this._genmachine, that._genmachine);
    }
    @Override
    public int hashCode() {
        return Objects.hashCode(serialVersionUID, LOGGER, _time, _machine, _inc, _new,
                _nextInc, _genmachine);
    }
    public static void main(String[] args) {
        System.out.println(new ObjectId().toHexString());
        System.out.println(new ObjectId().toHexString());
        System.out.println(new ObjectId().toHexString());
    }
}
参考资料:
- https://github.com/mongodb/mongo-java-driver/blob/master/src/main/org/bson/types/ObjectId.java
- http://docs.mongodb.org/manual/reference/object-id/
分布式ID生成器的更多相关文章
- c#分布式ID生成器
		c#分布式ID生成器 简介 这个是根据twitter的snowflake来写的.这里有中文的介绍. 如上图所示,一个64位ID,除了最左边的符号位不用(固定为0,以保证生成的ID都是正数),还剩余 ... 
- 基于redis的分布式ID生成器
		基于redis的分布式ID生成器 
- 分布式ID生成器PHP+Swoole实现(上) - 实现原理
		1.发号器介绍 什么是发号器? 全局唯一ID生成器,主要用于分库分表唯一ID,分布式系统数据的唯一标识. 是否需要发号器? 1)是否需要全局唯一. 分布式系统应该不受单点递增ID限制,中心式的会涉及到 ... 
- go语言实现分布式id生成器
		本文:https://chai2010.cn/advanced-go-programming-book/ch6-cloud/ch6-01-dist-id.html 分布式id生成器 有时我们需要能够生 ... 
- 分布式ID生成器的解决方案总结
		在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID.退款ID等.那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们应该采用哪种适合自己的解决方案是十分重要 ... 
- 来吧,自己动手撸一个分布式ID生成器组件
		在经过了众多轮的面试之后,小林终于进入到了一家互联网公司的基础架构组,小林目前在公司有使用到架构组研究到分布式id生成器,前一阵子大概看了下其内部的实现,发现还是存在一些架构设计不合理之处.但是又由于 ... 
- CosId 通用、灵活、高性能的分布式 ID 生成器
		CosId 通用.灵活.高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用.灵活.高性能的分布式系统 ID 生成器. 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS ... 
- CosId 1.0.0 发布,通用、灵活、高性能的分布式 ID 生成器
		CosId 通用.灵活.高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用.灵活.高性能的分布式系统 ID 生成器. 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS ... 
- CosId 1.0.3 发布,通用、灵活、高性能的分布式 ID 生成器
		CosId 通用.灵活.高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用.灵活.高性能的分布式系统 ID 生成器. 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS ... 
- CosId 1.1.0 发布,通用、灵活、高性能的分布式 ID 生成器
		CosId 通用.灵活.高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用.灵活.高性能的分布式系统 ID 生成器. 目前提供了俩大类 ID 生成器:SnowflakeId (单机 TPS ... 
随机推荐
- 无法连接windows虚拟机oracle的解决办法
			在mac机上玩基于oracle db的开发真心不容易,oracle公司死活不出oracle express edition for mac OS,曾经发布过的oracle 10 for mac下载地址 ... 
- Silverlight:针式打印机文字模糊的改善办法
			SL的打印功能,如果使用针式打印机,打出来的字很模糊,网上有一些文章介绍应该使用"Arial,SimSun"(即:宋体),但实际测试的结果,宋体依然很模糊. 下面是各种字体的测试: ... 
- Python2.3-原理之语句和语法
			此节来自于<Python学习手册第四版>第三部分 一.python语句简介(第10章) 1.首先记得一个概念:a.程序由模块构成:b.模块包含语句:c.语句包含表达式:d.表达式建立并处理 ... 
- python强大的区间处理库interval用法介绍
			原文发表在我的博客主页,转载请注明出处 前言 这个库是在阅读别人的源码的时候看到的,觉得十分好用,然而在网上找到的相关资料甚少,所以阅读了源码来做一个简单的用法总结.在网络的路由表中,经常会通过掩码来 ... 
- MVVM小记
			这篇小记源自于codeproject上的一篇文章 http://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explai ... 
- c/s  自动升级(WebService)
			首先声明,本人文笔不好,大家见笑,欢迎高手吐槽. 做c/s开发肯定会遇到的就是自动升级功能,而这实现方式是非常多. 本文使用 webservice的方式来提供升级服务 首先准备服务 为了方便我们专门用 ... 
- word-wrap,word-break和white-space总结
			最近网页布局中遇到得比较多,所以打算总结总结. word-wrap: 1.normal(使用浏览器默认的换行规则) 2.break-word(内容将在边界内换行,但是英文换行会按词断句) word-b ... 
- SqlServer——批量插入数据
			像Major表里面批量插入数据演示: 代码如下: Declare @I int Set @I= Begin Tran InsertData: Insert into Major values(@I,' ... 
- IE6下margin时,float浮动产生双倍边距
			今天遇到了一个IE6下的兼容性问题,虽然IE6已经不被大众所期待了,用户也已基本上消失的所剩无几,但是,作为一个问题而存在,我们有必要尝试的去研究一下bug的改善方法 对元素float-left,然后 ... 
- Linux运维教程
			最近看马哥Linux运维,收益颇多.愿马哥,身体健康! 2013马哥全套 http://pan.baidu.com/s/1c0JQu9i 运维技术文档 http://pan.baidu.com/s/1 ... 
