在待过的公司里,若需要生成分布式id的时候,譬如,商品id,订单id,流水号,评论id时候,都会选择使用Twiteer的snowflake分布式id 生成算法,关于这个算法本身(如下图),网上资料充栋,就不多说了,下面主要说下,这个算法在实际使用中的一些改进点。
平常我们用到分布式id地方,最终都会伴随着分库分表情况,而分库分表时大多都会根据id来取模,这时候最终各数据分表中的数据是否分的均匀,就 取决于分布式id得后几位值,也就是上图序列号几位的值。但,很多时候我们使用分布式id在夸过一个毫秒后,起始的第一个值都是从0开始的,更可怕的是 大多数业务上80%时间(猜测)一个毫秒也就生成一二个id,根本达不到1毫米内生成几百个的持续不断的场景。
这时候在数据积累到一定量,需要分表情况下,就会出现数据不均匀的情况,也间接就会导致各分表sql查询不均匀,分表效果大打折扣。
所以,在每个毫秒开始生存的第一个id时,我们需要在序列号位置上随机生成一个数字,这样就不会出现以该id做分表key,进行取模分表时候数据不均匀情况。
| product_id | user_id |
|---|---|
| 87654321 | 12345678 |
在C2C业务场景中,例如二手闲置买卖,用户会把自己不用的商品发布到平台上来卖,这时候商品product表的结构就会上图,一个商品id(product_id,主键) 就会对应着一个用户id(user_id)。
分表时候我们很方便的根据product_id做key来取模分表,查询商品时候也很方便的先根据product_id,计算出所在的分表,然后去对应表查询。 但,业务上我们常常有根据user_id来查询商品情况,例如用户个人中心中我在卖的商品,就是一个根据user_id,查询多个商品的情况。 这时候怎么办,我们只能去所有分表,根据这个用户id查询,然后合并到一起得出结果。
这时候就有产生一系列问题,因为大多数用户发布商品都非常少,例如你分了256个表(16库16表),结果90%用户发布商品都在30个以内,会导致你 每次多查询200多个表,这无论从性能上还是资源上都是大大浪费。
那么对于这种非分表字段该若何优化查询呢,我们只需要在分布式id中,预留几个二进制位(如上图中的把机器位,序列号为都匀出几位来)作为业务位, 什么意思呢,
就是我生成product_id时候,嵌入user_id在其中,这样当我分表时候,用这着预留的业务位来取模,就会出现 同一个用户发布的商品都落在同一张表中的神奇情况。 这样对于非partion key的查询,也只需要一步就会到位,性能,资源上都会大大优化。
java demo示例 demo生成自定义规则:

