一、介绍
Snowflake 是 Twitter 内部的一个 ID 生算法,可以通过一些简单的规则保证在大规模分布式情况下生成唯一的 ID 号码。其组成为:
- 第一个 bit 为未使用的符号位。
- 第二部分由 41 位的时间戳(毫秒)构成,他的取值是当前时间相对于某一时间的偏移量。
- 第三部分和第四部分的 5 个 bit 位表示数据中心和机器ID,其能表示的最大值为 2^5 -1 = 31。
- 最后部分由 12 个 bit 组成,其表示每个工作节点每毫秒生成的序列号 ID,同一毫秒内最多可生成 2^12 -1 即 4095 个 ID。
需要注意的是:
- 在分布式环境中,5 个 bit 位的 datacenter 和 worker 表示最多能部署 31 个数据中心,每个数据中心最多可部署 31 台节点
- 41 位的二进制长度最多能表示 2^41 -1 毫秒即 69 年,所以雪花算法最多能正常使用 69 年,为了能最大限度的使用该算法,你应该为其指定一个开始时间。
雪花算法生成的 ID 并不能保证唯一,如当两个不同请求同一时刻进入相同的数据中心的相同节点时,而此时该节点生成的 sequence 又是相同时,就会导致生成的 ID 重复。
二、安装和使用(php)
1.安装
composer require godruoyi/php-snowflake -vvv
2.使用
2.1 简单使用
$snowflake = new \Godruoyi\Snowflake\Snowflake; $snowflake->id();
//指定机器id(减小生成相同id的概率)
$snowflake = new \Godruoyi\Snowflake\Snowflake($datacenterId, $workerId); $snowflake->id();
//指定开始时间
$snowflake = new \Godruoyi\Snowflake\Snowflake; $snowflake->setStartTimeStamp(strtotime('2019-08-08')*1000); $snowflake->id();
2.2 高级使用(在laravel中使用)
①.服务提供者中进行注册
/App\Providers\AppServiceProvider
use Godruoyi\Snowflake\Snowflake;
use Godruoyi\Snowflake\LaravelSequenceResolver;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton('snowflake', function () {
return (new Snowflake())
->setStartTimeStamp(strtotime('2019-08-08')*1000)
->setSequenceResolver(
new LaravelSequenceResolver($this->app->get('cache')->store()
));
});
}
}
②.在model中使用
<?php
namespace App\Models;
use Aiadtech\Utils\Snowflake\Traits\LaravelModelTrait;
use Illuminate\Database\Eloquent\Model as BaseModel;
use DateTimeInterface;
use DateTime;
/**
* @mixin \Illuminate\Database\Eloquent\Builder
* @method static bool insert(array $values)
* @method static static where(string $column, $operator = null, $value = null, $boolean = 'and')
* @method static static whereIn($column, $values, $boolean = 'and', $not = false)
* @method static static whereDate(string $column, $operator, $value = null, $boolean = 'and')
* @method static static whereBetween(string $column, array $values, $boolean = 'and', $not = false)
*/
class Model extends BaseModel
{
use LaravelModelTrait;
const CREATED_AT = 'create_time';
const UPDATED_AT = 'update_time';
public $incrementing = false;
/**
* 为数组 / JSON 序列化准备日期。
*
* @param DateTimeInterface $date
* @return string
*/
protected function serializeDate(DateTimeInterface $date): string
{
return $date->format($this->dateFormat ?: 'Y-m-d H:i:s');
}
/**
* @param $raw_time
* @return string
* @throws \Exception
*/
public function getCreateTimeAttribute($raw_time): string
{
return $this->dateTimeFormat($raw_time);
}
/**
* 格式化更新时间
* @param $raw_time
* @return string
* @throws \Exception
*/
public function getUpdateTimeAttribute($raw_time): string
{
return $this->dateTimeFormat($raw_time);
}
/**
* 格式化时间
* @param $raw_time
* @param string $format
* @return string
* @throws \Exception
*/
public function dateTimeFormat($raw_time, string $format = 'Y-m-d H:i:s'): string
{
return (new DateTime($raw_time))->format($format);
}
}
③.注意事项
在保存数据的时候使用save()方法或者create()方法,会自动填充id,
数据表结构中,id字段要设置为biginteger 主键,非自增。