# 雪花算法改进 **Repository Path**: Ray3390/SnowFlake ## Basic Information - **Project Name**: 雪花算法改进 - **Description**: 雪花算法一个小改进 - **Primary Language**: C# - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-12-19 - **Last Updated**: 2023-12-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 雪花算法改进 #### 介绍 雪花算法的一个小改进,改进问题,当时间发生NTP回拨,会抛出异常。目前自己测试的没有问题,不保证所有场景能测试到。 如改进方法有误,希望及时留言,我会关闭该仓库,以免误人子弟。 如改进方法有误,希望及时留言,我会关闭该仓库,以免误人子弟。 如改进方法有误,希望及时留言,我会关闭该仓库,以免误人子弟。 #### 改进思想 利用未来时间弥补NTP回拨时间。 代码内记录了lastTimestamp(最后的时间戳),改进方法就是,如果发生NTP回拨,直接使用lastTimestamp产生id,如果1个毫秒内的id使用完了,直接lastTimestamp自动加1个毫秒,再继续生产,直至抵消回拨时间 #### 改进代码 ``` /// /// 获取id /// /// public long NextId() { lock (_lock) { var timestamp = TimeGen(); if (timestamp < lastTimestamp) { //修改此处,不再抛出异常 return NextNtpId(); //throw new Exception($"时间戳必须大于上一次生成ID的时间戳. 拒绝为{lastTimestamp - timestamp}毫秒生成id"); } ...... } } /// /// 产生NTP回拨id /// /// protected virtual long NextNtpId() { //sequence自增,和sequenceMask相与一下,去掉高位 sequence = (sequence + 1) & MaxSequenceNum; //判断是否溢出,也就是每毫秒内超过4095,当为4095时,与MaxSequenceNum相与,sequence就等于0 if (sequence == 0L) { //自动+1毫秒,用未来时间做弥补,直至补齐 lastTimestamp = lastTimestamp + 1; } return ((lastTimestamp - StartStmp) << TimestampLeftShift) | (DatacenterId << DatacenterIdShift) | (MachineId << MachineShift) | sequence; } ``` #### 未解决问题 和原始算法一样,当程序关闭后发生NTP回拨,仍然会产生重复id。目前我能想到的解决思想是:把lastTimestamp持久化,可以每个1秒持久化1次,当程序启动时直接赋值为持久化数据,这样可以更近一步减少重复id的发生几率。目前代码中没有实现。 #### 生产系统中需要注意的问题 雪花算法产生的id为long类型,返回给web前端时,如果数值过大,会造成js number类型精度丢失,一定要注意!!!