优化队列
This commit is contained in:
@@ -5,121 +5,471 @@ namespace app\common\library;
|
|||||||
|
|
||||||
class Snowflake
|
class Snowflake
|
||||||
{
|
{
|
||||||
// 起始时间戳(2023-01-01)
|
// 起始时间戳(2023-01-01 00:00:00)
|
||||||
const EPOCH = 1672502400000;
|
const EPOCH = 1672502400000;
|
||||||
|
|
||||||
// 机器ID位数
|
// 位数分配
|
||||||
const WORKER_ID_BITS = 5;
|
const WORKER_ID_BITS = 5; // 5位工作机器ID
|
||||||
const DATACENTER_ID_BITS = 5;
|
const DATACENTER_ID_BITS = 5; // 5位数据中心ID
|
||||||
const SEQUENCE_BITS = 12;
|
const SEQUENCE_BITS = 12; // 12位序列号
|
||||||
|
|
||||||
// 最大值
|
// 最大值计算
|
||||||
const MAX_WORKER_ID = -1 ^ (-1 << self::WORKER_ID_BITS);
|
const MAX_WORKER_ID = -1 ^ (-1 << self::WORKER_ID_BITS);
|
||||||
const MAX_DATACENTER_ID = -1 ^ (-1 << self::DATACENTER_ID_BITS);
|
const MAX_DATACENTER_ID = -1 ^ (-1 << self::DATACENTER_ID_BITS);
|
||||||
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS);
|
const MAX_SEQUENCE = -1 ^ (-1 << self::SEQUENCE_BITS);
|
||||||
|
|
||||||
// 移位
|
// 移位偏移量
|
||||||
const WORKER_ID_SHIFT = self::SEQUENCE_BITS;
|
const WORKER_ID_SHIFT = self::SEQUENCE_BITS;
|
||||||
const DATACENTER_ID_SHIFT = self::SEQUENCE_BITS + self::WORKER_ID_BITS;
|
const DATACENTER_ID_SHIFT = self::SEQUENCE_BITS + self::WORKER_ID_BITS;
|
||||||
const TIMESTAMP_LEFT_SHIFT = self::SEQUENCE_BITS + self::WORKER_ID_BITS + self::DATACENTER_ID_BITS;
|
const TIMESTAMP_LEFT_SHIFT = self::SEQUENCE_BITS + self::WORKER_ID_BITS + self::DATACENTER_ID_BITS;
|
||||||
|
|
||||||
|
// 序列号掩码
|
||||||
|
const SEQUENCE_MASK = -1 ^ (-1 << self::SEQUENCE_BITS);
|
||||||
|
|
||||||
|
// 实例存储
|
||||||
|
protected static $instances = [];
|
||||||
|
|
||||||
protected $workerId;
|
protected $workerId;
|
||||||
protected $datacenterId;
|
protected $datacenterId;
|
||||||
protected $sequence = 0;
|
protected $sequence = 0;
|
||||||
protected $lastTimestamp = -1;
|
protected $lastTimestamp = -1;
|
||||||
|
protected $lastGenerateTime = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* @param int $workerId 工作机器ID (0-31)
|
||||||
|
* @param int $datacenterId 数据中心ID (0-31)
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
public function __construct($workerId = 1, $datacenterId = 1)
|
public function __construct($workerId = 1, $datacenterId = 1)
|
||||||
{
|
{
|
||||||
|
// 验证 workerId
|
||||||
if ($workerId > self::MAX_WORKER_ID || $workerId < 0) {
|
if ($workerId > self::MAX_WORKER_ID || $workerId < 0) {
|
||||||
throw new \Exception("worker Id can't be greater than " . self::MAX_WORKER_ID . " or less than 0");
|
throw new \Exception(sprintf(
|
||||||
|
"Worker ID 必须在 0 到 %d 之间,当前值:%d",
|
||||||
|
self::MAX_WORKER_ID,
|
||||||
|
$workerId
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证 datacenterId
|
||||||
if ($datacenterId > self::MAX_DATACENTER_ID || $datacenterId < 0) {
|
if ($datacenterId > self::MAX_DATACENTER_ID || $datacenterId < 0) {
|
||||||
throw new \Exception("datacenter Id can't be greater than " . self::MAX_DATACENTER_ID . " or less than 0");
|
throw new \Exception(sprintf(
|
||||||
|
"Datacenter ID 必须在 0 到 %d 之间,当前值:%d",
|
||||||
|
self::MAX_DATACENTER_ID,
|
||||||
|
$datacenterId
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->workerId = $workerId;
|
$this->workerId = $workerId;
|
||||||
$this->datacenterId = $datacenterId;
|
$this->datacenterId = $datacenterId;
|
||||||
|
|
||||||
|
// 记录日志
|
||||||
|
\think\Log::info(sprintf(
|
||||||
|
"Snowflake 实例初始化完成,WorkerId: %d, DatacenterId: %d",
|
||||||
|
$workerId,
|
||||||
|
$datacenterId
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成下一个ID
|
||||||
|
* @return int
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
public function nextId()
|
public function nextId()
|
||||||
{
|
{
|
||||||
$timestamp = $this->timeGen();
|
$timestamp = $this->timeGen();
|
||||||
|
|
||||||
|
// 检查时钟回拨
|
||||||
if ($timestamp < $this->lastTimestamp) {
|
if ($timestamp < $this->lastTimestamp) {
|
||||||
$diff = $this->lastTimestamp - $timestamp;
|
$diff = $this->lastTimestamp - $timestamp;
|
||||||
throw new \Exception("Clock moved backwards. Refusing to generate id for {$diff} milliseconds");
|
|
||||||
|
// 轻微时钟回拨,等待时钟追上
|
||||||
|
if ($diff < 100) { // 100毫秒内的回拨
|
||||||
|
usleep($diff * 1000); // 微秒休眠
|
||||||
|
$timestamp = $this->timeGen();
|
||||||
|
} else {
|
||||||
|
throw new \Exception(sprintf(
|
||||||
|
"时钟回拨过大,拒绝生成ID。回拨时间:%d 毫秒",
|
||||||
|
$diff
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 同一毫秒内生成多个ID
|
||||||
if ($this->lastTimestamp == $timestamp) {
|
if ($this->lastTimestamp == $timestamp) {
|
||||||
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
|
$this->sequence = ($this->sequence + 1) & self::MAX_SEQUENCE;
|
||||||
|
|
||||||
|
// 序列号溢出,等待下一毫秒
|
||||||
if ($this->sequence == 0) {
|
if ($this->sequence == 0) {
|
||||||
$timestamp = $this->tilNextMillis($this->lastTimestamp);
|
$timestamp = $this->tilNextMillis($this->lastTimestamp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->sequence = 0;
|
// 新的毫秒,重置序列号,使用随机初始值避免重复
|
||||||
|
$this->sequence = mt_rand(0, 10) & self::MAX_SEQUENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->lastTimestamp = $timestamp;
|
$this->lastTimestamp = $timestamp;
|
||||||
|
|
||||||
return (($timestamp - self::EPOCH) << self::TIMESTAMP_LEFT_SHIFT) |
|
// 计算并返回ID
|
||||||
($this->datacenterId << self::DATACENTER_ID_SHIFT) |
|
$id = ((($timestamp - self::EPOCH) << self::TIMESTAMP_LEFT_SHIFT)
|
||||||
($this->workerId << self::WORKER_ID_SHIFT) |
|
| ($this->datacenterId << self::DATACENTER_ID_SHIFT)
|
||||||
$this->sequence;
|
| ($this->workerId << self::WORKER_ID_SHIFT)
|
||||||
}
|
| $this->sequence);
|
||||||
|
|
||||||
protected function tilNextMillis($lastTimestamp)
|
// 记录生成时间(用于调试)
|
||||||
{
|
$this->lastGenerateTime = microtime(true);
|
||||||
$timestamp = $this->timeGen();
|
|
||||||
while ($timestamp <= $lastTimestamp) {
|
|
||||||
$timestamp = $this->timeGen();
|
|
||||||
}
|
|
||||||
return $timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function timeGen()
|
return $id;
|
||||||
{
|
|
||||||
return floor(microtime(true) * 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析雪花ID
|
* 等待到下一毫秒
|
||||||
* @param int $id
|
* @param int $lastTimestamp 最后时间戳
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function tilNextMillis($lastTimestamp)
|
||||||
|
{
|
||||||
|
$timestamp = $this->timeGen();
|
||||||
|
$waitCount = 0;
|
||||||
|
|
||||||
|
while ($timestamp <= $lastTimestamp) {
|
||||||
|
// 等待时间过长记录警告
|
||||||
|
if ($waitCount++ > 100) {
|
||||||
|
\think\Log::warning("Snowflake 等待下一毫秒时间过长,已等待 {$waitCount} 次循环");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 微秒级休眠,避免CPU占用过高
|
||||||
|
usleep(100); // 休眠100微秒
|
||||||
|
$timestamp = $this->timeGen();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前时间戳(毫秒)
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function timeGen()
|
||||||
|
{
|
||||||
|
// 使用微秒时间,提高精度
|
||||||
|
return (int)(microtime(true) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析雪花ID为各个组成部分
|
||||||
|
* @param int $id 雪花ID
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function parseId($id)
|
public static function parseId($id)
|
||||||
{
|
{
|
||||||
|
// 转换为64位二进制字符串
|
||||||
$binary = decbin($id);
|
$binary = decbin($id);
|
||||||
$binary = str_pad($binary, 64, '0', STR_PAD_LEFT);
|
$binary = str_pad($binary, 64, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
$timestamp = bindec(substr($binary, 0, 42));
|
// 提取各组成部分
|
||||||
$timestamp = $timestamp + self::EPOCH;
|
$timestampBin = substr($binary, 0, 42);
|
||||||
|
$datacenterIdBin = substr($binary, 42, 5);
|
||||||
|
$workerIdBin = substr($binary, 47, 5);
|
||||||
|
$sequenceBin = substr($binary, 52, 12);
|
||||||
|
|
||||||
$datacenterId = bindec(substr($binary, 42, 5));
|
// 转换为十进制
|
||||||
$workerId = bindec(substr($binary, 47, 5));
|
$timestamp = bindec($timestampBin) + self::EPOCH;
|
||||||
$sequence = bindec(substr($binary, 52, 12));
|
$datacenterId = bindec($datacenterIdBin);
|
||||||
|
$workerId = bindec($workerIdBin);
|
||||||
|
$sequence = bindec($sequenceBin);
|
||||||
|
|
||||||
|
// 转换为可读时间
|
||||||
|
$dateTime = date('Y-m-d H:i:s', (int)($timestamp / 1000));
|
||||||
|
$millisecond = $timestamp % 1000;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'id' => $id,
|
||||||
'timestamp' => $timestamp,
|
'timestamp' => $timestamp,
|
||||||
'datacenterId' => $datacenterId,
|
'datetime' => $dateTime,
|
||||||
'workerId' => $workerId,
|
'millisecond' => $millisecond,
|
||||||
'sequence' => $sequence
|
'datacenter_id' => $datacenterId,
|
||||||
|
'worker_id' => $workerId,
|
||||||
|
'sequence' => $sequence,
|
||||||
|
'binary' => $binary,
|
||||||
|
'parts' => [
|
||||||
|
'timestamp' => $timestampBin,
|
||||||
|
'datacenter_id' => $datacenterIdBin,
|
||||||
|
'worker_id' => $workerIdBin,
|
||||||
|
'sequence' => $sequenceBin
|
||||||
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成ID(单例模式)
|
* 生成ID(主调用方法)
|
||||||
|
* @param int|null $workerId 工作机器ID
|
||||||
|
* @param int|null $datacenterId 数据中心ID
|
||||||
|
* @return int
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function generate($workerId = null, $datacenterId = null)
|
||||||
|
{
|
||||||
|
// 获取配置
|
||||||
|
if ($workerId === null) {
|
||||||
|
$workerId = self::getWorkerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($datacenterId === null) {
|
||||||
|
$datacenterId = self::getDatacenterId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建实例键
|
||||||
|
$instanceKey = "{$workerId}_{$datacenterId}";
|
||||||
|
|
||||||
|
// 检查是否已有实例
|
||||||
|
if (!isset(self::$instances[$instanceKey])) {
|
||||||
|
self::$instances[$instanceKey] = new self($workerId, $datacenterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成ID
|
||||||
|
return self::$instances[$instanceKey]->nextId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作机器ID
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public static function generate()
|
protected static function getWorkerId()
|
||||||
{
|
{
|
||||||
static $instance = null;
|
// 1. 从配置文件获取(FastAdmin 使用 application/extra/ 目录)
|
||||||
if (!$instance) {
|
$config = config('snowflake');
|
||||||
// 从配置获取workerId和datacenterId
|
if ($config && isset($config['worker_id'])) {
|
||||||
$workerId = config('snowflake.worker_id') ?: 1;
|
$workerId = (int)$config['worker_id'];
|
||||||
$datacenterId = config('snowflake.datacenter_id') ?: 1;
|
if ($workerId >= 0 && $workerId <= self::MAX_WORKER_ID) {
|
||||||
$instance = new self($workerId, $datacenterId);
|
return $workerId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $instance->nextId();
|
|
||||||
|
// 2. 从环境变量获取(FastAdmin 使用 .env 文件)
|
||||||
|
if (function_exists('env')) {
|
||||||
|
$envWorkerId = env('SNOWFLAKE_WORKER_ID');
|
||||||
|
if ($envWorkerId !== null && $envWorkerId !== false) {
|
||||||
|
$workerId = (int)$envWorkerId;
|
||||||
|
if ($workerId >= 0 && $workerId <= self::MAX_WORKER_ID) {
|
||||||
|
return $workerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 自动生成(基于服务器信息和进程ID)
|
||||||
|
// 使用服务器IP的最后一段 + 进程ID
|
||||||
|
$serverIp = self::getServerIp();
|
||||||
|
$ipParts = explode('.', $serverIp);
|
||||||
|
$ipLastPart = end($ipParts);
|
||||||
|
$processId = getmypid() ?: 1;
|
||||||
|
|
||||||
|
// 计算唯一的工作ID
|
||||||
|
$workerId = (($ipLastPart * 1000) + $processId) % (self::MAX_WORKER_ID + 1);
|
||||||
|
|
||||||
|
// 确保在有效范围内
|
||||||
|
$workerId = max(0, min($workerId, self::MAX_WORKER_ID));
|
||||||
|
|
||||||
|
return (int)$workerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据中心ID
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected static function getDatacenterId()
|
||||||
|
{
|
||||||
|
// 1. 从配置文件获取
|
||||||
|
$config = config('snowflake');
|
||||||
|
if ($config && isset($config['datacenter_id'])) {
|
||||||
|
$datacenterId = (int)$config['datacenter_id'];
|
||||||
|
if ($datacenterId >= 0 && $datacenterId <= self::MAX_DATACENTER_ID) {
|
||||||
|
return $datacenterId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 从环境变量获取
|
||||||
|
if (function_exists('env')) {
|
||||||
|
$envDatacenterId = env('SNOWFLAKE_DATACENTER_ID');
|
||||||
|
if ($envDatacenterId !== null && $envDatacenterId !== false) {
|
||||||
|
$datacenterId = (int)$envDatacenterId;
|
||||||
|
if ($datacenterId >= 0 && $datacenterId <= self::MAX_DATACENTER_ID) {
|
||||||
|
return $datacenterId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 自动生成(基于服务器IP)
|
||||||
|
$serverIp = self::getServerIp();
|
||||||
|
$ipParts = explode('.', $serverIp);
|
||||||
|
|
||||||
|
// 使用IP前两段计算数据中心ID
|
||||||
|
$part1 = isset($ipParts[0]) ? (int)$ipParts[0] : 0;
|
||||||
|
$part2 = isset($ipParts[1]) ? (int)$ipParts[1] : 0;
|
||||||
|
$datacenterId = (($part1 * 10) + $part2) % (self::MAX_DATACENTER_ID + 1);
|
||||||
|
|
||||||
|
// 确保在有效范围内
|
||||||
|
$datacenterId = max(0, min($datacenterId, self::MAX_DATACENTER_ID));
|
||||||
|
|
||||||
|
return (int)$datacenterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器IP
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function getServerIp()
|
||||||
|
{
|
||||||
|
// 多种方式获取服务器IP
|
||||||
|
if (isset($_SERVER['SERVER_ADDR'])) {
|
||||||
|
return $_SERVER['SERVER_ADDR'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('gethostname')) {
|
||||||
|
$hostname = gethostname();
|
||||||
|
if ($hostname) {
|
||||||
|
$ip = gethostbyname($hostname);
|
||||||
|
if ($ip !== $hostname) {
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试获取本机IP
|
||||||
|
if (function_exists('shell_exec') && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
||||||
|
$ip = shell_exec("hostname -I | awk '{print $1}'");
|
||||||
|
if ($ip) {
|
||||||
|
return trim($ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认返回127.0.0.1
|
||||||
|
return '127.0.0.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量生成ID
|
||||||
|
* @param int $count 生成数量
|
||||||
|
* @param int|null $workerId 工作机器ID
|
||||||
|
* @param int|null $datacenterId 数据中心ID
|
||||||
|
* @return array
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function batchGenerate($count = 10, $workerId = null, $datacenterId = null)
|
||||||
|
{
|
||||||
|
if ($count <= 0 || $count > 10000) {
|
||||||
|
throw new \Exception("生成数量必须在 1-10000 之间");
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = [];
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
$ids[] = self::generate($workerId, $datacenterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证ID是否有效
|
||||||
|
* @param int $id 雪花ID
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function validate($id)
|
||||||
|
{
|
||||||
|
if (!is_numeric($id) || $id <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$parsed = self::parseId($id);
|
||||||
|
|
||||||
|
// 检查时间戳是否合理(不能超过当前时间+10年)
|
||||||
|
$currentTime = (int)(microtime(true) * 1000);
|
||||||
|
$maxTime = $currentTime + (10 * 365 * 24 * 60 * 60 * 1000); // 10年后
|
||||||
|
|
||||||
|
if ($parsed['timestamp'] > $maxTime || $parsed['timestamp'] < self::EPOCH) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查ID组成部分是否在有效范围内
|
||||||
|
if ($parsed['datacenter_id'] > self::MAX_DATACENTER_ID ||
|
||||||
|
$parsed['worker_id'] > self::MAX_WORKER_ID ||
|
||||||
|
$parsed['sequence'] > self::MAX_SEQUENCE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ID生成统计信息
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getStats()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'worker_id' => $this->workerId,
|
||||||
|
'datacenter_id' => $this->datacenterId,
|
||||||
|
'last_timestamp' => $this->lastTimestamp,
|
||||||
|
'last_generate_time' => $this->lastGenerateTime,
|
||||||
|
'max_worker_id' => self::MAX_WORKER_ID,
|
||||||
|
'max_datacenter_id' => self::MAX_DATACENTER_ID,
|
||||||
|
'max_sequence' => self::MAX_SEQUENCE,
|
||||||
|
'epoch' => self::EPOCH,
|
||||||
|
'epoch_datetime' => date('Y-m-d H:i:s', self::EPOCH / 1000)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ID的详细信息(调试用)
|
||||||
|
* @param int $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getDetail($id)
|
||||||
|
{
|
||||||
|
if (!self::validate($id)) {
|
||||||
|
return ['error' => '无效的雪花ID'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsed = self::parseId($id);
|
||||||
|
|
||||||
|
// 添加生成时间估算
|
||||||
|
$generateTime = date('Y-m-d H:i:s', $parsed['timestamp'] / 1000);
|
||||||
|
$now = time();
|
||||||
|
$generateTimestamp = $parsed['timestamp'] / 1000;
|
||||||
|
$timeDiff = $now - $generateTimestamp;
|
||||||
|
|
||||||
|
if ($timeDiff < 60) {
|
||||||
|
$timeAgo = "刚刚";
|
||||||
|
} elseif ($timeDiff < 3600) {
|
||||||
|
$timeAgo = floor($timeDiff / 60) . "分钟前";
|
||||||
|
} elseif ($timeDiff < 86400) {
|
||||||
|
$timeAgo = floor($timeDiff / 3600) . "小时前";
|
||||||
|
} else {
|
||||||
|
$timeAgo = floor($timeDiff / 86400) . "天前";
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => $parsed['id'],
|
||||||
|
'timestamp' => $parsed['timestamp'],
|
||||||
|
'datetime' => $parsed['datetime'],
|
||||||
|
'datetime_full' => $generateTime . '.' . str_pad($parsed['millisecond'], 3, '0', STR_PAD_LEFT),
|
||||||
|
'time_ago' => $timeAgo,
|
||||||
|
'datacenter_id' => $parsed['datacenter_id'],
|
||||||
|
'worker_id' => $parsed['worker_id'],
|
||||||
|
'sequence' => $parsed['sequence'],
|
||||||
|
'binary' => chunk_split($parsed['binary'], 8, ' '),
|
||||||
|
'binary_parts' => [
|
||||||
|
'timestamp' => $parsed['parts']['timestamp'],
|
||||||
|
'datacenter' => $parsed['parts']['datacenter_id'],
|
||||||
|
'worker' => $parsed['parts']['worker_id'],
|
||||||
|
'sequence' => $parsed['parts']['sequence']
|
||||||
|
]
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// application/extra/snowflake.php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'worker_id' => 1, // 工作ID(1-31)
|
// 工作机器ID (0-31)
|
||||||
'datacenter_id' => 1, // 数据中心ID(1-31)
|
// -1 表示自动生成
|
||||||
|
'worker_id' => -1,
|
||||||
|
|
||||||
|
// 数据中心ID (0-31)
|
||||||
|
// -1 表示自动生成
|
||||||
|
'datacenter_id' => -1,
|
||||||
|
|
||||||
|
// 是否启用日志记录
|
||||||
|
'log_enabled' => false,
|
||||||
|
|
||||||
|
// 时钟回拨处理策略
|
||||||
|
'clock_backwards_strategy' => 'wait',
|
||||||
|
|
||||||
|
// 最大等待时间(毫秒)
|
||||||
|
'max_wait_time' => 100,
|
||||||
|
|
||||||
|
// ID生成模式
|
||||||
|
'mode' => 'auto',
|
||||||
|
|
||||||
|
// 服务器标识
|
||||||
|
'server_identifier' => '',
|
||||||
];
|
];
|
||||||
Reference in New Issue
Block a user