设计思路
- ID生成算法选择:
- 常用的分布式ID生成算法如雪花算法(Snowflake)。雪花算法生成的ID由时间戳、机器ID、序列号三部分组成。时间戳保证了ID的大致递增顺序,机器ID确保不同节点生成的ID不同,序列号用于在同一毫秒内不同请求生成不同ID。
- 处理网络延迟:
- 由于不同节点时钟可能存在偏差,为避免因时钟回退导致ID冲突,节点启动时获取NTP(网络时间协议)服务器时间进行时钟同步。
- 若检测到时钟回退,等待时钟追上前一个时间戳后再继续生成ID。
- 处理节点故障:
- 为了保证即使某个节点故障,整个系统仍能正常生成ID,每个节点生成的ID应尽量独立,不依赖其他节点。
- 可以设置备用节点,当主节点故障时,备用节点接管ID生成任务。同时,记录故障节点的ID生成状态(如时间戳、序列号),在故障节点恢复后,从记录的状态继续生成ID,避免重复。
核心代码示例(基于雪花算法)
package main
import (
"errors"
"fmt"
"sync"
"time"
)
// Snowflake结构体定义
type Snowflake struct {
machineID int64
datacenterID int64
sequence int64
lastStamp int64
mutex sync.Mutex
}
// NewSnowflake创建一个新的Snowflake实例
func NewSnowflake(machineID, datacenterID int64) (*Snowflake, error) {
if machineID < 0 || machineID > 1023 {
return nil, errors.New("machine ID can't be greater than 1023 or less than 0")
}
if datacenterID < 0 || datacenterID > 1023 {
return nil, errors.New("datacenter ID can't be greater than 1023 or less than 0")
}
return &Snowflake{
machineID: machineID,
datacenterID: datacenterID,
sequence: 0,
lastStamp: -1,
}, nil
}
// Generate生成唯一ID
func (s *Snowflake) Generate() int64 {
s.mutex.Lock()
defer s.mutex.Unlock()
now := time.Now().UnixNano() / 1000000
if now < s.lastStamp {
// 时钟回退处理
now = s.lastStamp
}
if now == s.lastStamp {
s.sequence = (s.sequence + 1) & 4095
if s.sequence == 0 {
// 等待下一毫秒
for now <= s.lastStamp {
now = time.Now().UnixNano() / 1000000
}
}
} else {
s.sequence = 0
}
s.lastStamp = now
return (now << 22) |
(s.datacenterID << 12) |
(s.machineID << 12) |
s.sequence
}
整体架构描述
- 节点层:每个分布式节点都运行一个雪花算法的实例,负责在本地生成唯一ID。每个节点通过配置获取自己的机器ID和数据中心ID。
- 时钟同步层:通过NTP协议与时间服务器同步时钟,确保各个节点的时间偏差在可接受范围内。
- 监控与故障处理层:有一个监控系统负责监测各个节点的运行状态。当某个节点故障时,监控系统将故障信息通知给备用节点,备用节点接管ID生成任务。同时,故障节点恢复后,监控系统协助其恢复到故障前的ID生成状态。