分布式id php,分布式ID生成器PHP+Swoole实现(下) - 代码实现

上篇文章主要介绍《实现原理》,这篇看主要代码的编写。

实现IDGenerator类

64位ID由以下元素组成:固定位占2位,时间戳占41位,服务实例数字编号占4位,业务编号占10位,自增id占7位

const BITS_FULL = 64;

const BITS_PRE = 2; // 固定位01

const BITS_TIME = 41; // 可支持69年

const BITS_SERVER = 4; // 可支持16台集群服务

const BITS_WORKER = 10; // 可支持业务数1024个

const BITS_SEQUENCE = 7; // 一毫秒内支持生成128个id

定义好三个变量:

$sequence_id: 自增序列id,在同一毫秒内产生的ID由此变量进行递增区分

$last_timestamp: 最后一次产生ID时的毫秒级时间戳,与下一次生成ID时的时间进行比较,如果时间相同则进行$sequence_id++,如果不同$sequence_id置0从新开始计算。

$server_id: 服务器id编号,代表不同的分布式服务实例,服务启动时指定。

private $sequence_id = 0;

private $last_timestamp = 0;

private $server_id = 0;

EPOCH_TIME,由过去最近的一个时间值作为比较基数,如下值为2018-10-30 00:00:00

const EPOCH_TIME = 1540828800000; //时间基数

获取一个64位ID主要由以下位运算完成

/**

* 获取id

*/

function get($worker_id = 0)

{

//初始化id位

$id = pow(2, 62);

/* 1. 时间戳 41位 */

$time = $this->timeGen();

$diff_time = $time - self::EPOCH_TIME;

$shift = self::BITS_FULL - self::BITS_PRE - self::BITS_TIME;

$id |= $diff_time << $shift;

/* 2. 服务器id */

$shift -= self::BITS_SERVER;

$id |= ($this->server_id & (pow(2, self::BITS_SERVER) - 1)) << $shift;

/* 3. 业务id */

$shift -= self::BITS_WORKER;

$id |= ($worker_id & (pow(2, self::BITS_WORKER) - 1)) << $shift;

/* 4. 自增id */

$id |= ($this->sequence_id % (pow(2, self::BITS_SEQUENCE) - 1));

$this->sequence_id++;

return $id;

}

/**

* 获取当前时间

*/

function timeGen() {

$wait_next_ms = 0;

do {

if($wait_next_ms > 0) {

usleep(100); //等待下一毫秒,休眠0.1毫秒

}

$timestamp = microtime(true) * 1000;

$timestamp = (int) $timestamp;

if($this->last_timestamp < $timestamp) {

$this->sequence_id = 0;

}

$wait_next_ms++;

} while ($this->last_timestamp == $timestamp

&& $this->sequence_id >= (pow(2, self::BITS_SEQUENCE) - 1)

|| $this->last_timestamp > $timestamp);

$this->last_timestamp = $timestamp;

return $timestamp;

}

实现Swoole redis服务

$shortopts = 's:p'; // s服务ID编号, p绑定端口

$options = getopt($shortopts);

// 由swoole_table存储最后一次产生数据的相关值

$table = new swoole_table(2048);

$table->column('sequence_id', swoole_table::TYPE_INT);

$table->column('last_timestamp', swoole_table::TYPE_FLOAT);

$table->column('server_id', swoole_table::TYPE_INT);

$table->create();

// atomic分业务加锁

for ($i = 0; $i <= 1023; $i++) {

$atomics[$i] = new swoole_atomic(0);

}

$serv = new Server("0.0.0.0", $options['p']);

$serv->table = $table;

$serv->atomics = $atomics;

$IDGen_config = array(

'server_id' => $options['s'],

'last_timestamp' => 0,

'sequence_id' => 0,

);

$serv->table->set('key:idgen_config', $IDGen_config);

$serv->on('start', function ($serv) use($options) {

// 启动事件

});

//监听redis get指令

$serv->setHandler('GET', function ($fd, $data) use ($serv) {

$data = trim($data[0]);

$IDGen = new IDGen();

$id = $IDGen->get();

return Server::format(Server::STRING, $id);

});

$serv->start();

Redis-cli连接测试

redis-cli -h 172.19.19.21 -p 9500

172.19.19.21:9500> get 1

"4747443928557682816"

172.19.19.21:9500> get 2

"4747443933230137600"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值