Alucns
V2EX  ›  PHP

求 16 位纯数字订单号产生算法

  •  
  •   Alucns · Dec 26, 2020 · 8065 views
    This topic created in 2138 days ago, the information mentioned may be changed or developed.
    最近业务方要求订单号不能大于 16 位,以前写的 18 位算法不能用了,改成 16 位重复的概率太高了,问问大家有什么好的算法分享!

    现在用的 18 位:

    <?php declare(strict_types=1);
    date_default_timezone_set('Etc/GMT-8');
    $time = microtime(true);
    function order()
    {
    $ids = 0;
    $aes = substr(microtime(), 2, 6);
    $pid = $aes . getmypid() . mt_rand(0, 999999);
    for($in = 0; $in < 18; $in++) {
    $ids += (int) (substr($pid, $in, 1));
    }
    return time() . $aes . str_pad(strval($ids), 2, '0', STR_PAD_LEFT);
    }

    $arr = array();
    for($i = 0; $i < 1000000; $i++) {
    $arr[] = order();
    }
    $arrs = array_count_values($arr);
    echo 'COUNT ' . count($arrs);
    echo '<br>';
    echo 'RAND ' . array_rand($arrs);
    echo '<br>';
    arsort($arrs);
    $as = [];
    foreach($arrs as $ids => $aos) {
    if ($aos > 1) {
    $as[] = $ids;
    echo $ids . ' - ' . $aos . '<br>';
    }
    }
    echo 'COUNT ' . count($as);
    echo '<br>';
    echo 'Time ' . number_format((microtime(true) - $time), 3);
    43 replies  •  2020-12-28 13:09:11 +08:00
    hbolive
    hbolive
    Dec 26, 2020
    1
    单纯依靠算法,16 还是 18 位,都没法保证吧重复吧。
    所以应该有其他机制校验下生成的 ID 是否重复。
    laminux29
    laminux29
    Dec 26, 2020
    2
    为啥订单号就不能老老实实从 1 开始自增?为啥订单号就不能常见的无符号 32 位整型?
    Alucns
    Alucns
    OP
    Dec 26, 2020
    3
    @hbolive 是有校验,产生的订单写入 Redis 了,产生的时候从 Redis 检查一次。
    pxw2002
    pxw2002
    Dec 26, 2020 via Android
    4
    有几位根据日期时间生成
    就不会重复了吧
    bleutee
    bleutee
    Dec 26, 2020 via iPhone
    5
    @laminux29 萬一人家想操數據呢?一五一十的順序排列,咋操
    Alucns
    Alucns
    OP
    Dec 26, 2020
    6
    @pxw2002 用毫秒加随机 2 位,每秒并发 1 万容易重复的。
    Alucns
    Alucns
    OP
    Dec 26, 2020
    7
    @laminux29 自增要先写数据库,很多多业务是先拿订单号请求接口成功后才写入数据库。
    还有就是自增从 1 开始,容易被人查数据。
    jimmyismagic
    jimmyismagic
    Dec 26, 2020
    8
    业务方的订单号和你内部的订单号完全可以分开啊,重复就重复呗
    Alucns
    Alucns
    OP
    Dec 26, 2020
    9
    @jimmyismagic 这个就是内部订单号,不能重复的。
    jimmyismagic
    jimmyismagic
    Dec 26, 2020
    10
    @Aluhao 所以他到底是甲方还是乙方?乙方糊弄过去就行了,甲方就怼回去,不懂瞎指导
    bsg1992
    bsg1992
    Dec 26, 2020
    11
    时间戳 不就解决了吗
    crclz
    crclz
    Dec 26, 2020❤️3
    12
    你说的 16 位是“个十百千万”的位吧,不是 bit 吧。

    如果是 16 个字符,那么约束我猜就是前端 js 的 number 超过 53~54bit 就会损失精度吧。

    一个解决方案是传字符串。

    如果非要数字,也不是不可以。你去看看 snowflake 算法。https://github.com/beyondfengyu/SnowFlake/blob/master/SnowFlake.java 把第 18 行里面的几个东西改一下,就可以应对不同的位数,本质是(使用年限,机器数量,数据中心数量,每秒并发数量)的权衡。当然首先得去看看 showflake 的结构再来改。
    Jooooooooo
    Jooooooooo
    Dec 26, 2020
    13
    用时间戳+机器码

    每个机器上维护一个当前时间戳可用的序号

    你并发不至于那么大
    Alucns
    Alucns
    OP
    Dec 26, 2020
    14
    @jimmyismagic 要拿内部唯一订单号去关联对方订单信息,要先请求传 16 位订单号过去。
    xuanbg
    xuanbg
    Dec 26, 2020❤️1
    15
    魔改雪花算法,41 位时间戳不要动,10 位设备去掉,差不多就是 16 位数字了。

    但是,我估计你要的是 yyyyMMdd+2 位业务代码+2 位 xx+4 位流水号,流水号还要加密的那种。在我的 github 里面有,请自取
    DarkCat123
    DarkCat123
    Dec 26, 2020
    16
    @laminux29 容易被人遍历数据,分析…… 而且不利于分布式数据库的 hash 分区。

    原来的 18 位用的是 snowflake?
    我建议要不要魔改下 snowflake, 牺牲一下时间来换位数降低(我记得原来的 snowflake 可以用 69 年)。
    要不然考虑找个 md5 sha1 之类的 hash 之后转 hex 看看能不能到 16 位吧。
    Alucns
    Alucns
    OP
    Dec 26, 2020
    17
    @Jooooooooo 主要是只限制 16 个数字,长一点都好解决。
    DarkCat123
    DarkCat123
    Dec 26, 2020
    18
    @xuanbg 老哥好巧,我们同时提到了魔改 snowlflake……
    jimmyismagic
    jimmyismagic
    Dec 26, 2020
    19
    @Aluhao 那你从 1 开始不就行了,对方唯一,需要你传的唯一,对方根本不关心你传的什么,楼上的 snowfake 一般用的很多,分布式 id 用的比较多,单机也没什么问题,16 位 50 多个比特完全够了
    dorothyREN
    dorothyREN
    Dec 26, 2020
    20
    13 位时间戳 加 3 位随机数或者 3 位自增数字
    lmmortal
    lmmortal
    Dec 26, 2020 via Android❤️1
    21
    可以借鉴一下身份证号最后一位的校验算法
    lin07hui
    lin07hui
    Dec 26, 2020
    22
    10 进制转 16 进制,不香吗
    lawler
    lawler
    Dec 26, 2020
    23
    @dorothyREN #20 就这个方案里的自增就可以了。
    @Aluhao #7 redis incr,mq


    要觉得不行,不妨把解决 10w/tps 的方案分享出来?
    要觉得可以遍历,不妨把不能遍历的纯数字索引方案分享出来?
    ytmsdy
    ytmsdy
    Dec 26, 2020 via iPhone
    24
    时间戳,加两个随机数,外加一个校验位。绰绰有余了!
    yuzo555
    yuzo555
    Dec 26, 2020
    25
    “容易被人遍历数据”这个不是自增的问题,是你们程序权限控制的问题
    Soar360
    Soar360
    Dec 26, 2020
    26
    20-1226-19-123456
    dorothyREN
    dorothyREN
    Dec 26, 2020
    27
    @lawler #23 13 位时间戳+3 位数字,1 毫秒 1000 个单号,肯定够用了
    jzmws
    jzmws
    Dec 26, 2020
    28
    @crclz 用雪花自己技术不过硬 然后 js 超出精度 坑死自己了 , 用这个算出来的是会操作 js 精度的
    jimmyismagic
    jimmyismagic
    Dec 26, 2020
    29
    @jzmws js 太傻了,前端技术不行让后端想办法
    dream7758522
    dream7758522
    Dec 26, 2020 via Android❤️1
    30
    很简单啊,时间戳→md5,16 位。→生成的 md5 中的 abcdef 用 123456 改写。
    举例:0123456789012345→md5,16 位→199aa7dcadfdb4e4→其中的字母字母用 123456 替换→1991174314642454 。
    觉得容易反算的话,可以加盐
    eyeix
    eyeix
    Dec 26, 2020
    31
    @laminux29 #2 自增订单号会被竞争对手分析流水
    Lemeng
    Lemeng
    Dec 27, 2020
    32
    重复 16 位 18 位都少。
    catror
    catror
    Dec 27, 2020 via Android
    33
    任何一个生成 int64 ID 的算法都行,int64 的 16 进制编码结果就是 16 位
    mxT52CRuqR6o5
    mxT52CRuqR6o5
    Dec 27, 2020 via Android
    34
    加密一个自增序列可以得到看上去随机的序列,不会重复,魔改加密算法让密文空间和明文空间在 16 位纯数字内
    mxT52CRuqR6o5
    mxT52CRuqR6o5
    Dec 27, 2020 via Android
    35
    要是没有随机性的要求的话直接魔改 snowflake 就是了
    hijoker
    hijoker
    Dec 27, 2020
    36
    13 位毫秒数+3 位随机数, 数据库这个字段设置类似唯一约束的东西, 如果真有重复,插入报错,根据报错信息重新生成随机数并重试插入
    itechify
    itechify
    Dec 27, 2020 via Android
    37
    @jzmws #28 我公司 long 类型都转字符串出去给前端了
    mostkia
    mostkia
    Dec 27, 2020
    38
    一般都时间戳+盐保证唯一性
    neptuno
    neptuno
    Dec 27, 2020
    39
    时间戳+(用户 id 转成 3 位数)?是不是最简单+重复率低
    ciddechan
    ciddechan
    Dec 28, 2020
    40
    @dream7758522 这种的会不会分不出是真的 123456 还是替换的 123456
    WaldenHorizon
    WaldenHorizon
    Dec 28, 2020
    41
    1.雪花算法:毫秒时间戳+集群号+机器号+进程号+自增序号
    这里最关键的是进程常驻,需要 swoole/workerman 插件
    2.额外写一个单实例部署的 id 生成器,加锁单线程运行,性能没有 1 好
    rSP0rcaA9K11Rjsz
    rSP0rcaA9K11Rjsz
    Dec 28, 2020
    42
    16 位 MD5 ?拿老 18 位订单号做一次转换
    afewok
    afewok
    Dec 28, 2020
    43
    但凡深入调研下业界和 github,都不会问出这个问题。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1321 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 110ms · UTC 21:49 · PVG 05:49 · LAX 13:49 · JFK 16:49
    ♥ Do have faith in what you're doing.