当前位置: 首页 > 后端技术 > Java

面试官居然问我订单ID是怎么生成的?不就是MySQL的自增主键吗?

时间:2023-04-02 01:37:03 Java

一位漂亮的面试官坐在我对面,闪闪发光的MacBook标志挡不住她圆润可爱的脸蛋。节目妹子少之又少,美女面试官更难找。它是什么样子的?喜欢下面的:这么温柔可爱的面试官,应该不会让我为难吧。嗯,应该是吧,毕竟我这么帅,面试可能只是走个形式吧。美女面试官是单身吗?毕竟程序员不善于交际,因为我也是单身,所以我的婚姻在这里就注定了。我已经想好孩子的名字了。一冰!好名字。采访者:年轻人,你为什么低着头笑。面试开始了,你知道orderID是怎么生成的吗?什么?订单ID是如何生成的?美女怎么不按套路出牌呢!HashMap的实现原理我已经背下来了,你别问了。一味的问什么orderID。我:它还能如何生成?使用数据库主键自增。面试官:那可不行。数据库主键顺序自增,日订单量竞争对手一目了然,商业机密暴露。而且单机的MySQL只能支持几百量级的并发,而我们公司每天有几千万的订单,是hold不住的。我:嗯,那就用数据库集群吧。自增ID的初始值以机器号为准,步长等于机器数。比如有两台机器,第一台机器生成的ID是1,3,5,7,第二台机器生成的ID是2,4,6,8,如果性能不好,加一个机器,并发会立即增加。采访者:年轻人,你的想法很好。你有没有想过需要2000台机器来实现百万级并发,而你只是用来生成订单ID。公司再有钱,也负担不起这个。我:既然MySQL的并发不够,能不能先从MySQL中获取一批自增ID,加载到本地内存中,然后从内存中并发取出。这并发性能是不是很牛逼?面试官:你说得很好,这个叫号段模式。并发增加了,但是自增ID仍然不能作为订单ID。我:使用带有自己的UUID的Java怎么样?importjava.util.UUID;/***@authoryideng*@apiNoteUUIDexample*/publicclassUUIDTest{publicstaticvoidmain(String[]args){StringorderId=UUID.randomUUID().toString().replace("-","");System.out.println(orderId);}}输出结果:58e93ecab9c64295b15f7f4661edcbc1面试官:也不行。32位的字符串会占用更多的空间,无序的字符串作为数据库的主键。MySQL每次插入数据库时??,为了维护B+树结构,MySQL需要频繁调整节点顺序,影响性能。而且字符串太长,没有业务意义,pass。小伙子,你可能没有接触过电商系统,我先告诉你,生成一个订单ID需要满足什么条件:全局唯一:如果订单ID重复,则必须完成。高性能:实现高并发和低延迟。生成订单ID成了瓶颈,所以还好。高可用:至少要做到四个9,任何时候都不会宕机。易用性:如果为了满足上述要求部署上百台服务器,复杂且难以维护,是行不通的。数值有序递增:数值占用空间小,有序递增保证插入MySQL时性能更高。嵌入业务含义:如果可以在订单ID中嵌入业务含义,就可以通过订单ID知道是哪个业务线产生的,方便排查问题。我擦,生成一个小订单ID,搞出这么多规则,还能玩吗?今天面试可以跪吗?一直在订阅一灯的文章,这对我来说还是很少见的,认真的玩美女程序员。我:听说圈内流传很久的分布式、高性能、高可用的订单ID生成算法——雪花算法,完全可以满足您的上述需求。雪花算法生成的ID为Long类型,长度为64位。Bit1:符号位,暂时不用。第2~42位:共41位,毫秒时间戳,可支持约69年第43~52位:共10位,机器ID,最多可容纳1024台机器第53~64位:共12位,序列号,是一个自增值,表示同一毫秒内生成的ID,单机每毫秒最多可以生成4096个订单ID码:/***@authorOneLightArchitecture*@apiNoteSnowflakeAlgorithm**/publicclassSnowFlake{/***起始时间戳,从2021-12-01生成*/privatefinalstaticlongSTART_STAMP=1638288000000L;/***序号占用的位数为12*/privatefinalstaticlongSEQUENCE_BIT=12;/***机器ID占用的位数*/privatefinalstaticlongMACHINE_BIT=10;/***最大机器数*/privatefinalstaticlongMAX_MACHINE_NUM=~(-1L<MAX_MACHINE_NUM||machineId<0){thrownewRuntimeException("机器超过最大数量");}this.machineId=machineId;}/***生成下一个ID*/publicsynchronizedlongnextId(){longcurrStamp=getNewStamp();if(currStamp