真假唯一数

6分钟

速读仅需3分钟

在真实的业务中生成唯一数是常见的功能,也是面试必考题。今天说说在面试过程中面试官在问这个问题时最想得到怎样的答案。

大部分编程语言都提供了唯一数生成函数,可惜大部分并不好用,原因是使用条件不符合使用场景。比如你需要生成唯一的数字并且是按顺序增长的,但系统函数只能生成字符串,最后只能另辟蹊径。所以面试官会问通常都有哪些生成唯一数的方法?

一. 散列+时间+随机值

md5(time() . mt_rand(1,1000000));

如上 `time()` 函数获取当前时间戳,`mt_rand(1,1000000)` 函数获取一个1到1000000的随机值,看着好像生成的数是唯一的,但这行代码问题非常多。

在操作系统中时间是很不靠谱的参数,因为CPU计算太快,没有对应的时间单位。如果CPU 1秒内处理了2个请求,那么`time()`字段毫无意义。

在编程语言中随机数也并不随机,常见的随机数都需要有随机种子,而为了保证种子不被猜到,编程语言默认会使用当前系统时间作为种子。又变成了依赖时间的一个参数,所以这种方案不可取。

二. 微秒+进程编号

uniqid();

`uniqid()`函数可以得到一个基于微秒和进程编号的唯一ID。对于php-fpm来说,每个请求都独占一个进程,一个进程会串行的处理多个请求。所以通过进程编号+微秒看上去能生成唯一ID。但深究之后发现并不靠谱。

1秒等于100万微秒,现在问题会变成一个进程能在百万分之一秒内处理多个请求吗?答案是可以的,用当前最普通的CPU来说,单核心1秒就可以计算20亿次,1微秒可以计算2千次。从操作系统调度的角度来说,2千次同时处理到一个进程的两个请求是完全可能的。所以又变成了依赖时间的一个参数,这种方案也不可取。

你还能使用纳秒,皮秒等精度更高的时间参数,但以发展的远光看问题,未来CPU的算力会越来越快,依赖时间的唯一性会越来越差。无论怎么努力,只依靠编程语言自身得到唯一ID是非常困难的,也是我不推荐的。

三. 数据库

靠编程语言自己走不通,那就通过第三方工具,这种方案是比较靠谱的。实现起来也有很多种方法。

LOCK TABLES id_maker;
//拿到id
select id from id_maker; 
//加1更新
update id_maker set id=id+1;
UNLOCK id_maker;

这是我曾经见过的一种id_maker用法,每次调用得到的id都是唯一并且有序的。但问题是需要锁表,性能不高,在高并发下很容易发生资源抢占导致数据库崩溃。

//id_maker表有自增id和内容data两个字段
insert into id_maker(data) values('');
select last_insert_id();

这种方式性能就高很多,insert语句不会锁表,自增id百分百保证唯一性且有序。唯一的问题是需要定期删除历史数据,对于大部分项目我都建议使用这种方式生成唯一ID。

除了MySQL还有MongoDB,Redis等其他数据库方案,方法大同小异。但是这个方案有局限性,当我们的业务发展到成千上万台服务器时通过一个数据库的一张表去生成ID会导致性能下降拖垮其他服务,还会形成单点依赖。

四. 微秒+服务器编号+计数器

Twitter开源了他的唯一ID生成方案,名字叫SnowFlake,这种方案的原理非常简单,很容易基于SnowFlake算法做扩展。比如PHP并不会常驻内存,计数器的实现比较麻烦,但只要原理清楚了使用扩展或者数据库很容易实现。

这个方案的最大优点就是在庞大的集群中,每个服务靠自己就能算出全局的唯一ID。微秒能保证ID有序,服务器编号能确定到具体机器,计数器(可以理解为只为当前服务器提供的`id_maker`)能保证当前机器所有请求的唯一性,通过这些参数生成的唯一编号有序并且无懈可击。

如上四点写的其实是一种思路,处理问题都是由简单到复杂,由一到二。如果直接给面试官说终极方案,面试官会基于终极方案问更多复杂的问题,更多离业务非常贴近的问题,如果没接触过相关业务直接就pass了。所以由简单到复杂,讲清楚技术原理和思考过程,offer离你就不远了。

本文分享自微信公众号 - 城边编程(code-log),作者:phplog

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 5分钟了解并发编程中的『锁』

    计算机中有一门经典的课程叫『操作系统』,里面花很少的篇幅讲了『锁』,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。虽...

    sibenx
  • 面试必考题-数据库自增主键

    无论是做PHP开发还是做JAVA开发甚至前端开发,只要是开发,面试的时候都必考数据库。为什么前端也要考数据库?因为数据库课程是计算机的基础课程,同样的基础课程还...

    sibenx
  • 程序员每年都会买的东西是什么?

    在10年前能拥有一台自己的服务器是想都不敢想的事情,非常的昂贵。5年前能拥有一台VPS也是相当了不起的事,还是很贵。那时候大多站长(当时站长是一个非常庞大的群体...

    sibenx
  • 深入理解JavaScript系列(31):设计模式之代理模式

    代理模式使得代理对象控制具体对象的引用。代理几乎可以是任何对象:文件,资源,内存中的对象,或者是一些难以复制的东西。

    用户4962466
  • MySQL复制的奇怪问题跟进

    没想到今天在做压力测试的时候,又碰到了类似的问题,这个问题的紧要程度要排上了日程。

    jeanron100
  • SQL Server为啥使用了这么多内存?

    原文地址:http://support.microsoft.com/gp/anxin_techtip6/zh-cn

    Edison Zhou
  • Mybatis + Oracle CRUD

    Remember_Ray
  • Ubuntu系统,搭建mysql+sphinx环建

    本文介绍下如何在ubuntu系统中,利用apt工具,搭建mysql+sphinx的全文检索环境。

    王亚昌
  • DOM基础知识

    1.DOM介绍 DOM= Document Object Model,文档对象模型,DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。换句话...

    苦咖啡
  • mybatis获取update的id

    平常我门都是更新数据,用更新的条件再查询一次,得到更新的记录。这样我门就进行了两次数据库操作,链接了两次数据库。增加了接口的处理事件,因为链接数据库是很耗时的操...

    似水的流年

扫码关注云+社区

领取腾讯云代金券