sonyflake源码解读

本文主要从源码角度深入解析Sonyflake,一个受Twitter Snowflake启发的分布式唯一ID生成算法。通过分析`sonyflake.go`和`sonyflake_test.go`文件,理解算法原理和实现细节,并强调测试用例在学习过程中的重要性。此外,提到了Sonyflake在AWS环境中的应用以及借鉴他人经验的重要性。
摘要由CSDN通过智能技术生成

网上大多数文章都只是说了snowflake或sonyflake的原理,但好像都没有多少是对源码的解读,对于初学者来说还需要多一些从别的角度去学习这个算法的思想,所以写了这篇文章,尝试从源码的角度去理解这个算法



sonyflake官方说了是受Twitter的Snowflake启发而衍生的分布式唯一ID生成算法。



目录结构

既然我们是从源码的角度去学习,那么就要先了解清楚这个包的目录结构是如何的。

能看得出来,整个包的文件数都是非常少的,非常精简

├── awsutil								
│   └── awsutil.go
├── example
│   ├── Dockerfile
│   ├── Dockerrun.aws.json
│   ├── linux64_build.sh
│   ├── README.md
│   └── sonyflake_server.go
├── go.mod
├── go.sum
├── LICENSE
├── README.md
├── sonyflake.go
└── sonyflake_test.go
  • awsutil:
    awsutil包提供了AmazonEC2MachineID函数,它返回AmazonEC2实例的低16位私有IP地址。它还可以通过检索实例元数据在Docker上正确工作。
    AWS VPC分配一个CIDR,子网掩码在/28 ~ /16之间。因此,如果每个EC2实例在AWS VPC中都有一个唯一的私有IP地址,那么地址的低16位也是唯一的。在这种情况下,您可以使用AmazonEC2MachineID作为Settings.MachineID。

  • example:在AWS Elastic Beanstalk上运行Sonyflake的示例

  • sonyflake.go:算法主体

  • sonyflake_test.go:测试用例



介绍

官方README上也说了ID的组成,ID是一个64位的数字

+-----------------------------------------------------------------------------+
|     标识位    |   39位保存时间戳   |       8位序列号      |     16位保存机器号    |
+-----------------------------------------------------------------------------+
| 1 Bit Unused | 39 Bit Timestamp |  8 Bit Sequence ID  |   16 Bit Machine ID |
+-----------------------------------------------------------------------------+



sonyflake.go

整个算法不足200行,不会很长,所以只要肯付出一些时间,基本上都能看懂,不会出现因代码太多,太枯燥而出现中途放弃的情况

package sonyflake

import (
	"errors"
	"net"
	"sync"
	"time"
)

// 这些常量是Sonyflake ID组成部分的位长度
const (
	BitLenTime      = 39                               // 时间戳的位长度
	BitLenSequence  = 8                                // 序列号的位长度
	BitLenMachineID = 63 - BitLenTime - BitLenSequence // 机器号的位长度
)

// Sonyflake的配置组成:
//
// StartTime 是Sonyflake ID进行生成的起始时间。
// 如果 StartTime 没有被配置或配置为0的话, 那么StartTime就会被设置为"2014-09-01 00:00:00 +0000 UTC".
// 如果配置的 StartTime 是超过当前的真实时间, Sonyflake对象是不会被创建的,那么就意味着会返回nil,所以上层不判断的话,直接调用 NextID() 就会发生panic,这个在golang里是一定要注意的.
//
// MachineID 返回实例机器的id.
// 如果 MachineID 返回的是error, Sonyflake对象是不会被创建的.
// 如果 MachineID 被配置为nil的话, 将使用默认的 MachineID.
// 默认的 MachineID 返回私有IP地址的低16位.
//
// CheckMachineID 校验实例机器id是否唯一.
// 如果 CheckMachineID 返回的是false, Sonyflake对象是不会被创建的.
// 如果 CheckMachineID 被配置为nil的话, 那么就不会去校验实例机器id是否唯一.
type Settings struct {
   
	StartTime      time.Time
	MachineID      func() (uint16, error)
	CheckMachineID func(uint16) bool
}

// Sonyflake 类.
type Sonyflake struct {
   
	mutex       *sync.Mutex		// 线程安全,主要是在多协程的时候通过锁去保证id唯一性
	startTime   int64			// 算法起始时间的时间戳,以10ms为单位时间
	elapsedTime int64			// 自设置的startTime以来,总共经过了多少个单位时间
	sequence    uint16			// 单位时间内的序列号
	machineID   uint16			// 实例机器id号
}

// NewSonyflake 创建对象.
// NewSonyflake 在以下情况将会返回nil:
// - Settings.StartTime 超过当前的真实时间.
// - Settings.MachineID() 返回error.
// - Settings.CheckMachineID() 返回false.
func NewSonyflake(st Settings) *Sonyflake {
   
	sf := new(Sonyflake)
	sf.mutex = new(sync.Mutex)																
	sf.sequence = uint16(1<<BitLenSequence - 1)

	if st.StartTime.After(time.Now()) {
   												// 如果配置的StartTime超过了当前真实时间
		return nil
	}
	if st.StartTime.IsZero() {
   														// 如果 StartTime 没有被配置或配置为0的话, 那么StartTime就会被设置为"2014-09-01 00:00:00 +0000 UTC"
		sf.startTime = toSonyflakeTime(time.Date(2014, 9, 1, 0, 0, 0, 0, time.UTC))	
	} else {
   																		// 如果配置的StartTime不为零且小于等于当前真实时间的话,StartTime就会以10ms为单位时间去转换
		sf.startTime = toSonyflakeTime(st.StartTime)
	}

	var err error
	if st.MachineID == nil {
   														// 如果不使用自定义的获取实例机器id号的函数的话,那么默认machineID就是私有IP地址的低16位
		sf.machineID, err = lower16BitPrivateIP()
	} else {
   
		sf.machineID, err = st.MachineID()
	}
	if err != nil || (st.CheckMachineID != nil && !st.CheckMachineID(sf.machineID)) {
   
		return nil
	}

	return sf
}

// NextID() 生成ID.
// 如果超过了能保存的时间戳上限, NextID() 将会返回error.
func (sf *Sonyflake) NextID() (uint64, error) {
   
	const maskSequence = uint16
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值