本文目录导读:

我来为您提供一个PHP实现的雪花算法(Snowflake ID)生成器,这是一个分布式ID生成方案,能够生成全局唯一的64位整数ID。
基础版雪花算法实现
<?php
class Snowflake
{
// 各个部分的位数
const EPOCH_BITS = 41; // 时间戳位数
const MACHINE_BITS = 10; // 机器ID位数
const SEQUENCE_BITS = 12; // 序列号位数
// 最大支持的值
const MAX_MACHINE_ID = -1 ^ (-1 << self::MACHINE_BITS); // 1023
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS); // 4095
// 偏移量
const MACHINE_SHIFT = self::SEQUENCE_BITS; // 12
const TIMESTAMP_SHIFT = self::SEQUENCE_BITS + self::MACHINE_BITS; // 22
// 起始时间戳(2020-01-01)
private const EPOCH = 1577808000000;
private $machineId; // 机器ID
private $sequence = 0; // 序列号
private $lastTimestamp = -1; // 上次生成ID的时间戳
/**
* 构造函数
* @param int $machineId 机器ID (0-1023)
* @throws Exception
*/
public function __construct($machineId = 0)
{
if ($machineId < 0 || $machineId > self::MAX_MACHINE_ID) {
throw new Exception("Machine ID must be between 0 and " . self::MAX_MACHINE_ID);
}
$this->machineId = $machineId;
}
/**
* 生成新的ID
* @return int 64位雪花算法ID
* @throws Exception
*/
public function nextId()
{
$timestamp = $this->getCurrentTimestamp();
// 处理时钟回拨
if ($timestamp < $this->lastTimestamp) {
throw new Exception("Clock moved backwards. Refusing to generate id for " .
($this->lastTimestamp - $timestamp) . " milliseconds");
}
// 同一毫秒内生成ID
if ($timestamp === $this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
// 序列号用尽,等待下一毫秒
if ($this->sequence === 0) {
$timestamp = $this->waitNextMillis($this->lastTimestamp);
}
} else {
// 新的毫秒,序列号从0开始
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
// 组合生成ID
return (($timestamp - self::EPOCH) << self::TIMESTAMP_SHIFT) |
($this->machineId << self::MACHINE_SHIFT) |
$this->sequence;
}
/**
* 等待到下一毫秒
*/
private function waitNextMillis($lastTimestamp)
{
$timestamp = $this->getCurrentTimestamp();
while ($timestamp <= $lastTimestamp) {
usleep(100); // 等待100微秒
$timestamp = $this->getCurrentTimestamp();
}
return $timestamp;
}
/**
* 获取当前毫秒时间戳
*/
private function getCurrentTimestamp()
{
return (int)(microtime(true) * 1000);
}
/**
* 解析ID,获取其组成部分(用于调试)
*/
public function parseId($id)
{
$timestamp = ($id >> self::TIMESTAMP_SHIFT) + self::EPOCH;
$machineId = ($id >> self::MACHINE_SHIFT) & self::MAX_MACHINE_ID;
$sequence = $id & self::MAX_SEQUENCE;
return [
'timestamp' => $timestamp,
'datetime' => date('Y-m-d H:i:s', $timestamp / 1000),
'machine_id' => $machineId,
'sequence' => $sequence
];
}
}
// 使用示例
try {
$snowflake = new Snowflake(1); // 机器ID为1
// 生成多个ID
$ids = [];
for ($i = 0; $i < 10; $i++) {
$ids[] = $snowflake->nextId();
}
print_r($ids);
// 解析第一个ID
print_r($snowflake->parseId($ids[0]));
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
改进版:支持更灵活的配置
<?php
class FlexibleSnowflake
{
// 默认配置(Twitter Snowflake标准)
private $config = [
'epoch' => 1577808000000, // 起始时间
'timestamp_bits' => 41, // 时间戳位数
'machine_bits' => 10, // 机器ID位数
'sequence_bits' => 12, // 序列号位数
];
private $machineId;
private $sequence = 0;
private $lastTimestamp = -1;
// 计算后的值
private $maxMachineId;
private $maxSequence;
private $machineShift;
private $timestampShift;
public function __construct($machineId = 0, $config = [])
{
// 合并配置
$this->config = array_merge($this->config, $config);
// 计算位偏移
$this->machineShift = $this->config['sequence_bits'];
$this->timestampShift = $this->config['sequence_bits'] + $this->config['machine_bits'];
// 计算最大值
$this->maxMachineId = -1 ^ (-1 << $this->config['machine_bits']);
$this->maxSequence = -1 ^ (-1 << $this->config['sequence_bits']);
// 验证机器ID
if ($machineId < 0 || $machineId > $this->maxMachineId) {
throw new Exception("Machine ID must be between 0 and " . $this->maxMachineId);
}
$this->machineId = $machineId;
}
public function nextId()
{
$timestamp = $this->getTimestamp();
if ($timestamp < $this->lastTimestamp) {
throw new Exception("Clock moved backwards");
}
if ($timestamp === $this->lastTimestamp) {
$this->sequence = ($this->sequence + 1) & $this->maxSequence;
if ($this->sequence === 0) {
$timestamp = $this->waitNextMillis();
}
} else {
$this->sequence = 0;
}
$this->lastTimestamp = $timestamp;
return (($timestamp - $this->config['epoch']) << $this->timestampShift) |
($this->machineId << $this->machineShift) |
$this->sequence;
}
private function getTimestamp()
{
return (int)(microtime(true) * 1000);
}
private function waitNextMillis()
{
$timestamp = $this->getTimestamp();
while ($timestamp <= $this->lastTimestamp) {
usleep(100);
$timestamp = $this->getTimestamp();
}
return $timestamp;
}
}
带缓存和锁的线程安全版本
<?php
class ThreadSafeSnowflake extends Snowflake
{
private $lockFile;
private $fp;
public function __construct($machineId = 0, $lockPath = '/tmp/')
{
parent::__construct($machineId);
// 创建锁文件(用于多进程/多线程场景)
$this->lockFile = $lockPath . 'snowflake_' . $machineId . '.lock';
$this->fp = fopen($this->lockFile, 'c');
if (!$this->fp) {
throw new Exception("Cannot open lock file");
}
}
public function nextId()
{
// 文件锁确保并发安全
if (!flock($this->fp, LOCK_EX)) {
throw new Exception("Cannot acquire lock");
}
try {
return parent::nextId();
} finally {
flock($this->fp, LOCK_UN);
}
}
public function __destruct()
{
if ($this->fp) {
fclose($this->fp);
}
}
}
批量生成ID(性能优化)
<?php
class BatchSnowflake extends Snowflake
{
/**
* 批量生成ID
* @param int $batchSize 批量大小
* @return array
*/
public function nextBatchId($batchSize = 100)
{
$ids = [];
for ($i = 0; $i < $batchSize; $i++) {
$ids[] = $this->nextId();
}
return $ids;
}
/**
* 预生成一批ID并缓存
*/
private $idCache = [];
public function getCachedId()
{
if (empty($this->idCache)) {
$this->idCache = $this->nextBatchId(100);
}
return array_shift($this->idCache);
}
}
使用建议
- 机器ID分配:在多服务器环境中,每个节点使用不同的machineId
- 时钟同步:确保服务器时钟差异小于10ms
- 并发控制:高并发场景使用锁或Redis原子操作
- ID格式:返回的ID可以作为字符串处理,避免PHP整数溢出
测试示例
// 测试代码
$snowflake = new Snowflake(1);
$startTime = microtime(true);
$testCount = 10000;
for ($i = 0; $i < $testCount; $i++) {
$id = $snowflake->nextId();
if ($i < 5) {
echo "ID: " . $id . "\n";
}
}
$endTime = microtime(true);
$timeUsed = $endTime - $startTime;
echo "生成 " . $testCount . " 个ID耗时: " . $timeUsed . " 秒\n";
echo "平均速度: " . ($testCount / $timeUsed) . " IDs/秒\n";
echo "内存占用: " . memory_get_peak_usage(true) / 1024 . " KB\n";
这个实现包含了完整的雪花算法核心功能,你可以根据实际需求选择使用基础版或功能增强版,记得根据你的PHP环境(32位还是64位)进行相应调整。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播