glhd/bits

0.5.0 2024-07-10 19:39 UTC

README

Build Status Coverage Status Latest Stable Release MIT Licensed Follow @inxilpro on Twitter Follow @chris@any.dev on Mastodon

Bits

Bits是一个用于在分布式计算中生成唯一64位标识符的PHP库。您可以使用Bits创建Twitter Snowflake IDsSonyflake IDs或任何其他使用位序列的唯一ID。

安装

composer require glhd/bits

配置

警告

如果您没有配置工作ID和数据中心ID,您可能会在多个应用服务器上使用Bits时遇到并发问题。

您需要配置以下两项以确保您的ID有效且唯一。

设置BITS_WORKER_IDBITS_DATACENTER_ID

由于每个工作都有自己的ID,雪花ID非常紧凑。如果您在多个数据中心运行多个服务器,您需要为每个数据中心分配一个唯一的值。您需要为应用程序使用的每个数据中心设置唯一的BITS_DATACENTER_ID(0-31),同一数据中心中的每个工作应具有唯一的BITS_WORKER_ID(0-31)。这意味着您最多可以有1024个不同的工作在同一时间生成雪花。

注意

如果您使用Lambda,这可能会成为一个问题。我们最终希望为Bits提供一个无服务器解决方案,但目前如果您在Laravel Vapor之类的环境中生成雪花,您需要自行管理锁定/释放ID。

设置BITS_EPOCH

雪花ID紧凑的另一个原因是它们使用自定义的“epoch”值(而不是1970年1月1日的Unix纪元)。这是可以生成雪花的最早时间,也设置了雪花可以生成的未来时间的限制。默认值为2023-01-01,对于大多数系统来说应该是足够的。但如果您在测试中要使用时间旅行回到2023年1月之前,这可能会引起问题(在这种情况下,您应该将epoch设置在您将时间旅行到的时间之前)。

使用方法

要获取新的雪花ID,只需调用Snowflake::make()。这将返回一个新的Snowflake对象

class Snowflake
{
    public readonly int $timestamp;
    public readonly int $datacenter_id;
    public readonly int $worker_id;
    public readonly int $sequence;
    
    public function id(): int;
    public function is(Snowflake $other): bool;
}

如果您更喜欢,也可以使用全局辅助函数snowflake()sonyflake()

所有Bits ID都实现了__toString()和Laravel Query\Expression接口,这样您就可以轻松地传递它们而不用担心类型。

与JavaScript一起使用

请注意,JavaScript只支持~52位整数,因此如果您将雪花传递到JavaScript中,请确保将它们转换为字符串。

所有Bits ID都实现了JsonableJsonSerializable,因此如果您将Bits实例传递给json_encode,它将自动为您处理。但如果您使用由Bits生成的整数ID,您将必须自己转换它们。

与Eloquent模型一起使用

Bits提供了Eloquent的HasUuidsHasUlids特性相同行为的HasSnowflakes特性。只需将HasSnowflakes添加到您的模型中,当它们被插入或更新时,就会为您生成一个新的雪花。

您还可以在Eloquent的$casts数组中使用SnowflakeSonyflake,以使该属性自动转换为Bits实例。

use Glhd\Bits\Database\HasSnowflakes;
use Glhd\Bits\Snowflake;
use Illuminate\Database\Eloquent\Model;

class Example extends Model
{
    // Auto-generate Snowflake for new models
    use HasSnowflakes;
    
    // Any attribute can be cast to a `Snowflake` (or `Sonyflake`)
    protected $casts = [
        'id' => Snowflake::class,
    ];
}

$example = Example::create();

$example->id instanceof Snowflake; // true

echo $example->id; // 65898467809951744

使用ID作为时间戳

雪花和Sonyflake的一个优点是它们可以根据时间排序,并且可以从ID中提取时间戳供以后使用。这意味着如果您愿意,可以使用这些ID代替created_at时间戳。

// Instead of:
User::where('created_at', '>', now());

// You can do (assuming users.id is a snowflake)
User::where('id', '>', app(MakesSnowflakes::class)->firstForTimestamp(now()));
// Instead of:
$created_at = $user->created_at;

// You can do (assuming User::id is cast to a Snowflake object)
$created_at = $user->id->toCarbon();

与Livewire一起使用

如果您使用Livewire,可以使用SnowflakeSynth合成器使雪花在您的组件中可用。

您只需要在AppServiceProvider中注册合成器。

use Glhd\Bits\Support\Livewire\SnowflakeSynth;
use Glhd\Bits\Support\Livewire\BitsSynth;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // If only using Snowflakes:
        Livewire::propertySynthesizer(SnowflakeSynth::class);
        
        // If using Sonyflakes or a custom Bits variant:
        Livewire::propertySynthesizer(BitsSynth::class);
    }
}

如果您使用非Snowflake版本的Bits,可以使用BitsSynth,它支持Bits的任何版本,但代价是存储更多的数据。

关于64位唯一ID

雪花格式

0 0000001100100101110101100110111100101011 01011 01111 000000011101
┳ ━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━ ━━━┳━ ━┳━━━ ━┳━━━━━━━━━━
┗━ unused bit     ┗━ timestamp (41)           ┃   ┃     ┗━ sequence (12)
                              datacenter (5) ━┛   ┗━ worker (5)

Sonyflake格式

0 000000011001001011101011001101111001010 11010110 1111000000011101
┳ ━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━┳━ ━┳━━━━━━━━━━━━━━
┗━ sign   ┗ timestamp (39)         sequence (8) ┛   ┗ machine (16)

这两个ID都由相同的64位整数56705782302306333表示,但传达了不同的元数据。根据您的规模和分布需求,您可能发现其中一个或另一个格式更合适,或者选择实现您自己的自定义格式。

Bits可以生成您想要的任何类型的64位唯一ID,以最适合您用例的方式。