首页 体育世界正文

今日头条新闻,分布式ID生成计划:雪花算法(源自Twitter),降头

雪花(snowflake)在自然界中,是极具共同美丽,又变化多端的东西:

  1. 雪花归于六方晶系,它具有四个结晶轴,其间三个辅南略中文网轴在一个基面上,相互以60度的视点相交,第四轴(主晶轴)与三个辅轴所构成的基面笔直;
  2. 雪花的根本形状是六角形,可是大自然中却简直找不出两朵彻底相同的雪花,每一个雪花都具有自己的独有今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头图画,就象地球上找不出两个彻底相同的人相同。许多学者用显微镜观测过不计其数朵雪花,这些研讨最终标明,形状、巨细彻底相同和各部分彻底对称的雪花,在自然界中是无法构成的。

雪花算法:

雪花算法的原始版别是scala版,用于生成分布式ID(纯数字,时刻次序),订单编号等。

自增ID:关于数据灵敏场景不宜运用,且不适合于分布式场景。

GUID:选用无意义字兰菊花符串,数据量增大时形成拜访过慢,且不宜排序。

算法描绘:

  • 最高位是符号位,一直为0,不可用。
  • 41位的时刻序列,准确到毫秒级,41禛心真意长相守位的长度能够运用69年。时刻位还有一个很优女重要的作用是能够今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头依据时刻进行排序。
  • 10位的机器标识,10位的长度最多支撑布置1024个节点。
  • 12位的计数序列号,序列号即一系列的自增id,能够支撑同一节点同一毫秒生成多个ID序号,12位的计数序列号支撑每个节点每毫秒发生4096个ID序号。

Donet版别

using System;
namespace System
{
///
/// 分布式ID算法(雪花算法)
///

public class Snowflake
{
private static long machi哈尔滨师范大学阿城学院neId;//机器ID
private static long datacenterId = 0L;//数据ID
private static long sequence = 0L;//计数从零开始

private static long twepoch = 687888001020L; //仅有时刻随机量

private static long machineIdBits = 5L; //机器码字节数
private static long datacenterIdBits = 5L;//数据字节数
public static long maxMachineId = -1L ^ -1L << (int)machineIdBits; //最大机器ID
private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits);//最大数据ID

private static long sequenceBits = 12L; //计数器字节数,12个字节用来保存计数码
private static long machineIdShift = sequenceBits; //机器码数据左移位数,便是后边计数器占用的位数
private static long datacenterIdS霍雨浩之冰雪操纵hift = sequenceBits + machineIdBits;
private static long timestampLeftShift = sequenceBits + machineIdBits + datacenterIdBits; //时刻戳左移动位数便是机器码+计数器总字节数+数据字节数
public民间忌讳1000例 static long sequenceMask = -1L ^ -1L << (int)sequenceBits; //一微秒内能够发生计数,假如抵达该值则比及下一奇妙在进行生成
private static long lastTimestamp = -1L;//最终时刻戳

private static o摩登情书在线阅览全文bject syncRoot = new object();//加锁目标
static S登乘绳梯nowflake snowflake;
public static Snowflake Instance()
{
if (snowflake == null)
snowflake = new S张文朝nowflake();
return snowflake;
}

public S米露老公nowflake()
{
Snowflakes(0L, -1);
}
public Snowflake(long machineId)
{
Snowflakes(machineId, -1);
}

public Snowflake(long machineId, long datacenterId)
{
Snowflakes(machineId, datacenterId);
}

private void Snowflakes(long machineId, long datacenterId)
{
if (machineId >= 0)
{
if (machineId > maxMachineId)
{
throw new Exception("机器码ID不合法");
}
Snowflake.machineId = machineId;
}
if (datacenterId >= 0)
{
if (datacenterId > maxDatacenterId箱鼓九种根底节奏)
{
throw new Exception("数据中心ID不合法");
}
Snowflake.datacenterId = datacenterId;
}
}
///
/// 生成当时时刻戳
///

/// 毫秒
private static long GetTimestamp()
{
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKi逐鼎大明nd.Utc)).TotalMilliseconds;
}
///
/// 获取下一微秒时刻戳
///

///


///
private static long GetNextTimestamp(long lastTimestamp)
{
long timestamp = GetTimestamp();
if (timestamp <= lastTimestamp)
{
timestamp = GetTimestamp();
}
return timestamp;
}

///


/// 获取长整型的ID
///

///
public long GetId()
{
lock (syncRoot)
{
long timestamp = GetTimestamp();
if (Snowflake.lastTimestamp == timestamp)
{ //同一奇妙中生成ID
sequence = (sequence + 1) & sequenceMask; //用&运算核算该微秒内发生的计数是否现已抵达上限
if (sequence == 0)
{
//一奇妙内发生的ID计数已达上限,等候下一奇妙
timestamp = GetNextTimestamp(lastTimestamp);
}
}
else
{
//不同微秒生成ID
sequence = 0L;
}
if (timestamp < lastTimestamp)
{
throw new Exception("时刻戳比上一次生成ID时时刻戳还小,故反常");
}
Snowflake.lastTimestamp = timestamp; //把当时时刻戳保存为最终生成ID的时刻戳
long Id = ((timestamp - twepoch) << (int)timestampLeftShift)
| (datacenterId << (int)datacenterIdShift)
| (machineId << (int)machineIdShift)
| sequence;
return Id;
}
}
}
}

Golang版

snowflake.go

package snowflake
// twitt今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头er 雪花算法
// 把时刻戳,作业机器ID, 序列号组合成一个 64位 int
// 榜首方位零, [2,42]这41位寄存时刻戳,[43,52]这10位寄存机器id,[53,64]最终12位寄存序列号
import "time"
var (
m潘娇阳achineID int64 // 机器 id 占10位, 十进制规模是 [ 0, 1023 ]
sn int64 // 序列号占 12 位,十进制规模是 [ 0, 4095 ]
lastTimeStamp int64 // 前次的时刻戳(毫秒级), 1秒=1000毫秒, 1毫秒=1000微秒,1微秒=1000纳秒
)

func init() {
lastTimeStamp = time.Now().UnixNano() / 1000000
}

func SetMachineId(mid int64) {
// 把机器 id 左移 12 位,让出 12 位空间给序列号运用
machineID = mid << 12
}

func GetSnowflakeId() int64 {
curTimeStamp := time.Now().UnixNano() / 1000000
// 同一毫秒
if curTimeStamp == lastTimeStamp {
sn++
// 序列号占 12 位,十进制规模是 [ 0, 4095 ]
if sn > 4095 {
time.Sleep(time.Millisecond)
curTimeStamp = time.Now().UnixNano() / 1000000
lastTimeStamp 胶州李克光= curTimeStamp
sn = 0
}
// 取 64 位的二进制数 0000000000 0000000000 0000000000 0001111111111 1111111111 1111111111 1 ( 这儿共 41 个 1 )和时刻戳进行并操作
// 并成果( 右数 )第 42 位必定是 0, 低 41 位也便是时刻戳的低 41 位
rightBinValue := curpervertedTimeStamp & 0x1FFFFFFFFFF
// 机器 id 占用10位空间,序列号占用12位空间,所以左今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头移 22 位; 通过上面的并操作,左移后的第 1 位,必定是 0
rightBinValue <<= 22
i魏京生d := rightBi墨尘视界nValue | machineID | sn
return id
}
if curTimeStamp > lastTimeStamp {
sn = 0
lastTimeStamp = curTimeStamp
// 取 64 位的二进制数 0000000000 0000000000 0000000000 0001111111111 1111111111 1111111111 1 ( 这儿共 41 个 1 )和时刻戳进行并操作
// 并成果( 右数 )第 42 位必定是 0, 低 41 位也便是时刻戳的低 41 位
rightBinValue := curTimeStamp & 0x1FFFFFFFFFF
// 机器 id 占用10位空间,序列号占用12位空间,所以左移 22 位; 通过上面的并操作,左移后的第 1 位,必定是 0
rightBinValue <<= 22
id := rightBinValue | machineID | sn
return id
}
if curTimeStamp < lastTimeStamp {
return 0
}
return 0
}

main.go

package main
import (
"fmt"
"reflect"
"snowflake"
"time"
)
func main() {
//var ids = []int64{}
var ids = make([]int64, 0)
//设置一个机器标识,如IP编码,避免分布式机器生成重复码
snowflake.SetMachineId(192168100101)

fmt.Println("start", time.Now().Format("13:04:05"))
for i := 0; i < 10000000; i++ {
i多美娅d := snowflake.GetSnowflakeId()
ids = append(ids, id)
}
fmt.Println("end ", time.Now().Format("13:04:05"))

result := Duplicate(ids)
fmt.Println("去重后数量:", len(result))
fmt.Println(result[10], result[11], result[12], result[13], result[14])
fmt.Println(result[9990], result[9991], result[9992], result[9993], result[9994今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头])
}
//去重
func Duplicate(a interface{}) (ret []interface{}) {
va := reflect.ValueOf(a)
for i := 0; i < va.Len(); i++ {
if i > 0 && reflect.DeepEqual(va.Index(i-1).Interface(), va.Index(i).Interf今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头ace()) {
continue
今天头条新闻,分布式ID生成方案:雪花算法(源自Twitter),降头}
ret = append(ret, va.Index(i).Interface())
}
return ret
}

留意:在分布式体系中给每台机器设置一个int64的机器码,能够是IP编号+随机数,如192168011234(192.168.0.1+1234)

测验成果:

定论:

理论上生成速率为kw/秒,所以彻底满意一般企业级使用, 算法牢靠(去重处理在此也是多此一举);

功能:100W+/秒;

本文来自于博客园史布斯的博客

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。