php与唯一ID生成的相关事宜
[原文地址:https://blog.ti-node.com/blog...]
唯一ID的生成并不是一件小事 , 想说爱它 , 也并不是像简单来一个uniqid()这样一件容易的事 .
为什么要唯一ID ?
1 . 数据库的自增ID在分库的时候 , 会是一场灾难 . 假设分两个库 , 因为每个库都会开始从1开始自增 , 届时 , 系统中将会出现两个id为1的用户 .
2 . 自增id会暴露用户量或者其他业务量 .
3 . 自增id会让有心者通过API得到任意用户的信息资料 .
解决方案呢 ?
1 . UUID , 全称Universally Unique Identifier , 中文通用唯一标识符 . 这个是开放软件基金会组织提出的一个标准 , 为的就是解决分布式环境下生成唯一标识符的问题 . UUID的长度是固定的32位 , 组织格式8-4-4-4-12 , 当然了在用的时候 , 中间的分隔符是要去掉的 . 这个货有几个问题不得不提 , 首先是字母数字混合 , 在一些传统数据库下 , 索引不太好做 , 不仅索引体积大 , 查询效率也差 . 其次是它本身也非常大 .
2 . MongoDB ObjectId , 格式模样都很类似于UUID , 是Mongodb内置的一种数据类型 , 如果你在插入数据的时候不指定_id , 那么Mongodb默认就会采用用这个货才填充_id , 在Mongodb这种类kv性质的数据库中 , 有着不错的查询效率 .
3 . 自建解决方案 , 为了能够解决业务问题 , 很多公司都自己提出一些解决方案 , 这些方案无疑都要做到如下几点 :
- 保证全局空间唯一性
- 保证尽量采取数字类型而非数字字母混合方式
- 保证一定的时序行和含义
- 保证一定的可反解性 , 通过反解的结果可以知道该ID的相关信息
市面上有的几种解决方案为Twitter的snowflake , Flikr的数据库自增方案 , Instagram的数据库存储过程方案 . 重点说下Twitter的snowflake解决方案原理 .
snowflask使用了64bit来表示一个id , Twitter的工程师们将它分成了4个段 , 每段表示不同的含义 . 如下图 :
前41bit段 , 是时间戳 , 单位会精确到毫秒级 . 所以该bit段可以容纳的时间容量为 2^41 = 2.199x10^12 毫秒 , 也就是 2.199x10^9 秒 . 换算成年 , 就是大概为69.7年 . 也就说 , 从1970年1月1日开始 , 可以使用69.7年 , id产生机器的上限就到了 .
中10bit段 , 是机器ID , 最大可以容纳2^10=1024台机器 . 你可以部署1一台以上的机器 , 给每个机器配置一个与众不同的独立的id号 , 比如从1号开始 , 最多可以部署到1024号机器 . 然后机器集群最前面挡一台nginx之类的服务器做代理 , 就可以完成一个不错的id发号集群了 .
后12bit段 , 是自增序列( 你可以等同为mysql的自增id ) , 它表示的1毫秒内的自增序列 . 也就是说从0毫秒开始一直到1毫秒结束这段时间内自增 . 也就说1毫秒内最多产生2^12=4096个序列 , 也就是说同一台机器上同一毫秒内最多产生4096个序列 , 如果超过了该数字 , 那就等待下一毫秒产生新的id .
TIPS : 顺带提一下 , php的uniqid()函数存在很大的风险 , 它生成的id并不能像它的名字那样做到uniqid , 重复概率略高 . 详情查看该函数的手册页评论 . 点击这里
TIPS : 推荐一个基于snowflake的php id产生器 : donkeyid生成器