分布式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 ...
随机推荐
- 【java】企业级分布式搜索平台Solr视频教程
课程背景为了满足高可用.可扩展并容错的分布式搜索引擎.Solr是一个高性能,采用Java5开发, 基于Lucene的全文搜索服务器.同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现 ...
- 从.NET的宠物商店到Android MVC MVP
1 一些闲话 记得刚进公司的时候,我们除了做常规的Training Project外,每天还要上课,接受各种技术培训和公司业务介绍.当时第一次知道QA和SQA的区别.Training Project时 ...
- BPR: Bayesian Personalized Ranking from Implicit Feedback-CoRR 2012——20160421
1.Information publication:CoRR 2012 2.What 商品推荐中常用的方法矩阵因子分解(MF),协同过滤(KNN)只考虑了用户购买的商品,文章提出利用购买与未购买的偏序 ...
- C++命名规范
1.1 类型名 首字母大写,末尾加_T.如: class TnppCoverageArea_T{…}; 1.2 1.2 变量和函数名 变量和函数名中首字母小写,其后每个英文单词的第一个字母 ...
- 探索 SharePoint 2013 Search功能
转载: http://www.cnblogs.com/OceanEyes/p/SharePont-2013-Search-Develop.html SharePoint 2013的搜索功能很强大,特别 ...
- Question2Answer安装
Question2Answer安装 Question2Answer的安装过程很简单,只需要几分钟的时间你就可以有一个强大的问答系统. 安装要求 Web服务器(比如Apache) PHP 4.3 或更高 ...
- [转]java反射机制
原文地址:http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html 一.什么是反射机制 简单的来说,反射机制指的是程序在运 ...
- iOS开发遇到的错误 -- Label显示多行文字导致宽度和高度的问题
Label的宽度问题 注意:UILabel下面需要设置preferredMaxLayoutWidth ,设置了autolayout和numberofline的UIlabel才显示多行 label宽度的 ...
- iPad开发--QQ空间,处理横竖屏布局,实现子控件中的代理
一.主界面横竖屏效果图 二.主界面加载, 初始化Dock(红色框的控件),判断程序启动时的屏幕方向.调用自己- (void)transitionToLandScape:(BOOL)isLandScap ...
- 【POJ 3415】Common Substrings 长度不小于k的公共子串的个数
长度不小于k的公共子串的个数,论文里有题解,卡了一上午,因为sum没开long long!!! 没开long long毁一生again--- 以后应该早看POJ里的Discuss啊QAQ #inclu ...