唯一ID生成原理与PHP实现-雪花算法

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 唯一ID生成原理与PHP实现-雪花算法

snowflake算法

虽然PHP提供了一个生成唯一ID的函数uniqid(),但这个函数真的可以生成唯一ID吗?我们来看看uniqid()的具体实现:

PHP_FUNCTION(uniqid)

{

   ...

   gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);

sec = (int) tv.tv_sec;

   usec = (int) (tv.tv_usec % 0x100000);

spprintf(&uniqid, 0, "%s%08x%05x", prefix, sec, usec);

RETURN_STRING(uniqid, 0);

}

从代码可以看出,uniqid()是通过微妙级时间戳来实现的,在分布式高并发的情况下,ID的重复率是很高的,所以我们不能使用uniqid()来生成唯一ID。

snowflake算法

既然不能单纯靠时间戳来保证唯一性,那么是不是可以增加以下特征值来保证呢?为此,Twitter公司发明了snowflake算法。snowflake算法的核心原理是把一个64位的整数分为3个部分,如下图:

image.png

如上图所示,高端的第一位不使用,接着的41位字节用于存储毫秒级的时间戳,紧跟着时间戳的10位作为机器ID,而最后12位为序列号。

  1. 对于不同的机器来说,可以为每一台机器分配一个唯一的机器ID,这样就可以保证每台机器锁生成的ID不会重复。
  2. 对于同一台机器,如果同一时刻多个客户端并发请求,那么可以通过增加序列号来保证ID唯一性。

默认情况下41位的时间戳可以支持该算法使用到2082年(需要通过减去一个起始时间戳),10位的工作机器ID可以支持1023台机器,12位的序列号支持1毫秒产生4095个自增序列ID。

也就是说1台机器1秒可以承受4095000个并发,可以胜任任何场景。snowflake算法的代码实现大概如下:

static uint64_t last_ts = 0;

static uint64_t sequence = 0;

static uint64_t datacenter_id = 0;

// 获取毫秒时间戳

uint64_t current_timestamp()

{

   struct timeval tv;

   uint64_t retval;

if (gettimeofday(&tv, NULL) == -1) {

       return 0ULL;

   }

retval = (u64_t)tv.tv_sec * 1000ULL +

            (u64_t)tv.tv_usec / 1000ULL;

return retval;

}

// 如果在同一毫秒内超过了并发现在, 那么等待下一毫秒

uint64_t skip_next_millis()

{

   uint64_t ts;

while (1) {

       ts = current_timestamp();

       if (ts > last_ts) {

           break;

       }

   }

return ts;

}

// 获取下一个ID

uint64_t get_next_id()

{

   uint64_t retval, ts;

ts = current_timestamp();

if (ts == last_ts) { // 同一毫秒内多个并发

       sequence = (sequence + 1) & 0xFFF;// 增加序列号计数器

       if (sequence == 0) {  // 计数器用完

           ts = skip_next_millis();// 等待下一毫秒

       }

   } else {

       sequence = 0;// 清空序列号计数器

   }

last_ts = ts;

retval = (ts << 22) | (datacenter_id << 12) | sequence;

return retval;

}

PHP实现唯一ID生成函数

严格来说使用PHP是不能实现snowflake算法的,这是因为PHP的运行机制导致的。一般一台机器会启动多个PHP进程,而且进程之间是不能共享内存的,就是说多个PHP进程之间不能使用同一个序列号,这样就会导致不同进程生成的ID可能会重复。而且每次请求完,PHP都会释放本次请求的所有资源,那么就不能记录最后一次时间戳和序列号计数器的值(虽然可以使用文件或者memcached之类实现,当这样性能就会降低很多)。所以说使用PHP是不能实现snowflake算法的。

不能使用PHP代码实现snowflake算法,但是可以通过PHP扩展和php-cli运行模式下来实现,下图是PHP-FPM的运行机制:

image.png

从上图可以看出,在创建worker进程之前先会调用每个扩展的init()函数(PHP_MINIT_FUNCTION函数),所以我们可以在init()函数创建一块共享内存,然后每个worker进程就可以共用这块内存(因为fork之前创建的共享内存可以在子进程中共用)。

因为不同的进程并发访问共享内存可能会导致数据不一致的问题,所以必须解决资源竞争的问题,解决资源竞争最常用的方法就是使用锁。

进程间一般使用的锁有:信号量和自旋锁。信号量与自旋锁的不同之处是,信号量会发生进程上下文切换,而自旋锁不会。

当然这两种锁都可以解决资源竞争问题,但是相对于生成唯一ID这种场景,使用自旋锁会有更好的性能,这是因为生成ID这个过程非常短,而自旋锁锁不需要切换上下文。

自旋锁

自旋锁的原理是不断测试锁是否能够被上锁,如果能够上锁就进行上锁操作,否则就不断重复上面的操作。下面代码是一个简单的实现:

void spin_lock(atomic_t *lock, int id)

{

   int i, n;

for ( ;; ) {

if (*lock == 0 &&

           __sync_bool_compare_and_swap(lock, 0, id)) {

           return;

       }

if (ncpu > 1) {

for (n = 1; n < 129; n << 1) {

for (i = 0; i < n; i++) {

                   __asm("pause");

               }

if (*lock == 0 &&

                   __sync_bool_compare_and_swap(lock, 0, id)) {

                   return;

               }

           }

       }

sched_yield();

   }

}

__sync_bool_compare_and_swap(var, old, new)函数是一个原子性操作,作用就是比较var与old的值,如果相等就把var的值改为new,如果不相等就继续进行这个操作直到成功为止。这里有个小技巧,就是当长时间获取不到锁的情况下,我们会调用sched_yield()系统调用让出CPU,从而避免过度使用CPU资源。

总结

snowflake算法可以有效的生成唯一ID,而且通过配置机器ID可以很好地支持分布式环境。本文介绍了怎么使用PHP扩展来实现snowflake算法,具体实现可以参考本人所写的Atom扩展: https://github.com/liexusong/atom

本文转自:https://mp.weixin.qq.com/s/bagOgzdwLyZv_ITNVnYfoQ

目录
相关文章
|
9月前
|
存储 算法 安全
控制局域网电脑上网的 PHP 哈希表 IP 黑名单过滤算法
本文设计基于哈希表的IP黑名单过滤算法,利用O(1)快速查找特性,实现局域网电脑上网的高效管控。通过PHP关联数组构建黑名单,支持实时拦截、动态增删与自动过期清理,适用于50-500台终端场景,显著降低网络延迟,提升管控灵活性与响应速度。
340 8
|
运维 监控 算法
局域网屏幕监控软件 PHP 图像块增量传输算法解析
本文探讨了一种基于PHP语言开发的图像块增量传输算法,适用于局域网屏幕监控场景。通过将屏幕图像分块处理、计算哈希值并对比变化区域,该算法显著降低了网络带宽占用,提升了监控效率。在企业管理和远程教育中,该技术可实现终端设备的实时监控与远程管控,同时支持与生物识别等技术融合,拓展应用范围。实验表明,该算法在常规办公场景下可减少90%以上的数据传输量,展现了良好的实时性和优化效果。
225 3
|
存储 监控 算法
公司员工电脑监控软件剖析:PHP 布隆过滤器算法的应用与效能探究
在数字化办公的浪潮下,公司员工电脑监控软件成为企业管理的重要工具,它能够帮助企业了解员工的工作状态、保障数据安全以及提升工作效率。然而,随着监控数据量的不断增长,如何高效地处理和查询这些数据成为了关键问题。布隆过滤器(Bloom Filter)作为一种高效的概率型数据结构,在公司员工电脑监控软件中展现出独特的优势,本文将深入探讨 PHP 语言实现的布隆过滤器算法在该软件中的应用。
227 1
|
存储 监控 算法
单位电脑监控软件中 PHP 哈希表算法的深度剖析与理论探究
数字化办公的时代背景下,单位电脑监控软件已成为企业维护信息安全、提升工作效率的关键工具。此类软件可全面监测员工的电脑操作行为,收集海量数据,故而高效管理和处理这些数据显得尤为重要。数据结构与算法在此过程中发挥着核心作用。本文将聚焦于哈希表这一在单位电脑监控软件中广泛应用的数据结构,并通过 PHP 语言实现相关功能,为优化单位电脑监控软件提供技术支持。
226 3
|
存储 监控 算法
论内网电脑监控软件中 PHP 哈希表算法的深度剖析与探究
当代企业网络管理体系中,内网电脑监控软件占据着关键地位。其功能涵盖对员工电脑操作行为的实时监测,以此维护企业信息安全,同时助力企业优化网络资源配置,提升整体工作效能。在构建内网电脑监控软件的诸多技术中,数据结构与算法构成了核心支撑体系。本文聚焦于哈希表这一重要数据结构,深入剖析其在 PHP 语言环境下,如何为内网电脑监控软件的高效运作提供助力,并通过详实的代码示例予以阐释。
229 3
|
存储 监控 算法
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
258 7
|
监控 算法 安全
关于公司电脑桌面监控中 PHP 二叉搜索树算法的深度剖析
在现代企业管理中,公司电脑桌面监控系统通过二叉搜索树(BST)算法保障信息安全和提高效率。本文探讨PHP中的BST在监控场景的应用,包括节点定义、插入与查找操作,并展示如何管理时间戳数据,以快速查询特定时间段内的操作记录。BST的高效性使其成为处理复杂监控数据的理想选择。
197 2
|
缓存 监控 算法
内网监控管理软件:PHP 语言队列算法揭秘
在数字化办公环境中,内网监控管理软件对企业的稳定运行和信息安全至关重要。本文深入介绍PHP中的队列算法及其在内网监控软件中的应用,包括监控数据收集、任务调度和日志记录等场景,通过代码示例展示其实现方法。队列算法可提高性能、保证数据顺序并实现异步处理,为企业提供高效的安全保障。
279 1
|
算法 关系型数据库 MySQL
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
在分布式系统中,确保每个节点生成的 ID 唯一且高效至关重要。Snowflake 算法由 Twitter 开发,通过 64 位 long 型数字生成全局唯一 ID,包括 1 位标识位、41 位时间戳、10 位机器 ID 和 12 位序列号。该算法具备全局唯一性、递增性、高可用性和高性能,适用于高并发场景,如电商促销时的大量订单生成。本文介绍了使用 Go 语言的 `bwmarrin/snowflake` 和 `sony/sonyflake` 库实现 Snowflake 算法的方法。
1120 1
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
|
存储 算法 安全
SnowflakeIdGenerator-雪花算法id生成方法
SnowflakeIdGenerator-雪花算法id生成方法
628 1

热门文章

最新文章