Snowflake is an ID generation algorithm within Twitter that uses a few simple rules to ensure that unique ID numbers are generated in large-scale distributed situations.

Its composition is:

  • The first bit is the unused sign bit.
  • The second part consists of a 41-bit timestamp (in milliseconds) that is the offset of the current time relative to a certain time.
  • The five bits in the third and fourth parts represent the data center and machine ID, and the maximum value they can represent is 2^ 5-1 = 31;
  • The last part is composed of 12 bits, which represents the serial number ID generated by each working node every millisecond. In the same millisecond, a maximum of 2^ 12-1, i.e. 4095 ids can be generated.

Note that:

  • In a distributed environment, a datacenter and worker with five bits means that a maximum of 31 data centers can be deployed, and a maximum of 31 nodes can be deployed in each datacenter.
  • The 41-bit binary length represents a maximum of 2^ 41-1 milliseconds or 69 years, so the Snowflake algorithm will last for a maximum of 69 years. To maximize the use of the algorithm, you should specify a start time for it.

It can be seen from the above that the ID generated by the snowflake algorithm cannot be guaranteed to be unique. For example, when two different requests enter the same node in the same data center at the same time and the sequence generated by the node is the same, the generated ID will be repeated.

Therefore, in order to use the snowflake algorithm to generate a unique ID, it is necessary to ensure that the serial number generated by the same node within the same millisecond is unique. Based on this, we have integrated multiple serial number providers into the SDK:

  • RandomSequenceResolver
  • RedisSequenceResolver (based on Redis PSEtex and Incrby)
  • LaravelSequenceResolver (based on Redis PSEtex and Incrby)
  • SwooleSequenceResolver (based on the Swoole_lock lock)

Different providers just need to ensure that the serial numbers generated in the same millisecond are different to get a unique ID.

requirements

  1. PHP > = 7.0
  2. Composer

The installation

$ composer require godruoyi/php-snowflake -vvv
Copy the code

use

  1. Easy to use.
$snowflake = new \Godruoyi\Snowflake\Snowflake;

$snowflake->id();
/ / 1537200202186752
Copy the code
  1. Specify the data center ID and machine ID.
$snowflake = new \Godruoyi\Snowflake\Snowflake($datacenterId, $workerId);

$snowflake->id();
Copy the code
  1. Specify the start time.
$snowflake = new \Godruoyi\Snowflake\Snowflake;
$snowflake->setStartTimeStamp(strtotime('2019-09-09') *1000);

$snowflake->id();
Copy the code

senior

  1. Used in Laravel

Since the SDK is relatively simple, we didn’t provide an extension pack for Laravel. You can quickly integrate into Laravel in the following ways.

// App\Providers\AppServiceProvider

use Godruoyi\Snowflake\Snowflake;
use Godruoyi\Snowflake\LaravelSequenceResolver;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register(a)
    {
        $this->app->singleton('snowflake'.function (a) {
            return (new Snowflake())
                ->setStartTimeStamp(strtotime('2019-10-10') *1000)
                ->setSequenceResolver(new LaravelSequenceResolver($this->app->get('cache')->store())); }); }}Copy the code
  1. Custom serial number solver

You can customize the serial number solver by implementing the Godruoyi\Snowflake\SequenceResolver interface.

class YourSequence implements SequenceResolver
{
    / * * * {@inheritdoc} * /
    public function sequence(int $currentTime)
    {
          // Just test.
        return mt_rand(0.1); }}// usage

$snowflake->setSequenceResolver(new YourSequence);
$snowflake->id();
Copy the code

You can also use closures directly:

$snowflake = new \Godruoyi\Snowflake\Snowflake;
$snowflake->setSequenceResolver(function ($currentTime) {
    static $lastTime;
    static $sequence;

    if ($lastTime == $currentTime) {
        ++$sequence;
    } else {
        $sequence = 0;
    }

    $lastTime = $currentTime;

    return $sequence;
})->id();
Copy the code

If you encounter any problems during use, please submit “PR”.