5.5 KiB
Snowflake
Algorithm Introduction
Snowflake
is a distributed global unique ID generation algorithm proposed by twitter. The result of the algorithm generating ID
is a long integer with the size of 64bit
. Under the standard algorithm, its structure is shown in the figure below:
-One bit
, unused.
-
The highest bit in the binary system is the sign bit. The
ID
generated by us is generally a positive integer, so the highest bit is fixed to 0. -
41 bits
to record the timestamp (MS).41 bits
can represent2^41 - 1
numbers.- In other words,
41 bits
can represent the value of2^41 - 1
milliseconds, and the unit year is(2^41 - 1) / (1000 * 60 * 60 * 24 * 365)
about69
years。
-
10 bits
, used to record theID
of the working machine.- It can be deployed in
2^10
nodes, including5
bitsDatacenterId
and5
bitsWorkerId
.
- It can be deployed in
-
12 bits
, serial number, used to record differentid
generated in the same millisecond.12 bits
can represent the maximum number of positive integers2^12 - 1
with a total of4095
numbers, which represent the4095
ID
serial numbers generated by the same machine in the same time interval (MS).
Snowflake
can guarantee that:
- All generated
ID
increase with time trend.- No duplicate
ID
will be generated in the whole distributed system (Because there is a distinction betweenDatacenterId (5 bits)
andWorkerId (5 bits)
.
- No duplicate
The hyperf/snowflake component provides good extensibility in design, allowing you to implement other variant algorithms based on snowflake with simple extension.
Install
composer require hyperf/snowflake
Use
The framework provides MetaGeneratorInterface
and IdGeneratorInterface
. MetaGeneratorInterface
generates Meta
files of ID
, and IdGeneratorInterface
generates distributed ID
based on the corresponding Meta
files.
The MetaGeneratorInterface
used by the framework by default is a millisecond level generator
based on Redis
.
The configuration file is located in config/autoload/snowflake.php
If the configuration file does not exist, you can execute php bin/hyperf.php vendor:publish hyperf/snowflake
command to create a default configuration. The contents of the configuration file are as follows:
<?php
declare(strict_types=1);
use Hyperf\Snowflake\MetaGenerator\RedisMilliSecondMetaGenerator;
use Hyperf\Snowflake\MetaGenerator\RedisSecondMetaGenerator;
use Hyperf\Snowflake\MetaGeneratorInterface;
return [
'begin_second' => MetaGeneratorInterface::DEFAULT_BEGIN_SECOND,
RedisMilliSecondMetaGenerator::class => [
// Redis Pool
'pool' => 'default',
// To calculate the Key of WorkerId
'key' => RedisMilliSecondMetaGenerator::DEFAULT_REDIS_KEY
],
RedisSecondMetaGenerator::class => [
// Redis Pool
'pool' => 'default',
// To calculate the Key of WorkerId
'key' => RedisMilliSecondMetaGenerator::DEFAULT_REDIS_KEY
],
];
Using Snowflake
in the framework is very simple. You just need to take out the IdGeneratorInterface
object from DI
.
<?php
use Hyperf\Snowflake\IdGeneratorInterface;
use Hyperf\Context\ApplicationContext;
$container = ApplicationContext::getContainer();
$generator = $container->get(IdGeneratorInterface::class);
$id = $generator->generate();
When you know that the ID
needs to reverse the corresponding Meta
, you just need to call generate
.
<?php
use Hyperf\Snowflake\IdGeneratorInterface;
use Hyperf\Context\ApplicationContext;
$container = ApplicationContext::getContainer();
$generator = $container->get(IdGeneratorInterface::class);
$meta = $generator->degenerate($id);
Override 'Meta' generator
There are many ways to implement the distributed global unique ID
, and there are also many variants based on the Snowflake
algorithm. Although they are all Snowflake
algorithms, they are not the same. For example, someone may generate a Meta
based on UserId
rather than WorkerId
. Next, let's implement a simple MetaGenerator
.
In short, the UserId
will definitely exceed '10 bits'. Therefore, the default DataCenterId
and WorkerId
cannot be installed. Therefore, the UserId
module needs to be taken.
<?php
declare(strict_types=1);
use Hyperf\Snowflake\IdGenerator;
class UserDefinedIdGenerator
{
/**
* @var IdGenerator\SnowflakeIdGenerator
*/
protected $idGenerator;
public function __construct(IdGenerator\SnowflakeIdGenerator $idGenerator)
{
$this->idGenerator = $idGenerator;
}
public function generate(int $userId)
{
$meta = $this->idGenerator->getMetaGenerator()->generate();
return $this->idGenerator->generate($meta->setWorkerId($userId % 31));
}
public function degenerate(int $id)
{
return $this->idGenerator->degenerate($id);
}
}
use Hyperf\Context\ApplicationContext;
$container = ApplicationContext::getContainer();
$generator = $container->get(UserDefinedIdGenerator::class);
$userId = 20190620;
$id = $generator->generate($userId);
Application in database modelon in database model
After configuring Snowflake
, we can make the database model directly use Snowflake
ID
as the primary key.
<?php
class User extends \Hyperf\Database\Model\Model {
use \Hyperf\Snowflake\Concern\Snowflake;
}
When the user model is created, the Snowflake
algorithm will be used to generate the primary key by default.