• aoe
    2019-10-10
    个人觉得“微信序列号生成器”的方法更简单,因为:
    Snowflake
    1. Snowflake算法是基于二进制的,对于像我这样基础不扎实的理解起来还是比较困难。
    2. Snowflake集群环境下需要保证时钟同步,对运维能力有一定要求;一旦时钟错乱,又刚好是高并发时,会导致大量异常序号。
    3. 如果公司运维能力有限,不适合用Snowflake。
    4. 百度开源的UidGenerator(仅支持单机部署)使用Snowflake算法,单机QPS可达600万。项目说明:https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md 。
    5. 美团Leaf(分布式ID生成系统),QPS近5万。项目地址:https://tech.meituan.com/2017/04/21/mt-leaf.html 。

    微信序列号生成器
    文档地址:https://www.infoq.cn/article/wechat-serial-number-generator-architecture
    1. 递增但不连续的数字序列解决方案。
    2. 设计目标QPS1000万以上。
    3. 通过在递增过程中使用“步长”将每秒磁盘写入由1000万级降至1万。
    4. 设计原理相对于Snowflake更通俗易懂。
    5. 可以使用hash的负载均衡策略组建集群。
    6. 缺点:需要自己实现集群中机器增减后更新负载均衡策略的逻辑。
    7. Java版最简单Demo():使用spring boot搭建一个web工程,使用Controller调用Service实现数字递增
    Service类
    import org.springframework.stereotype.Service;

    import javax.annotation.PostConstruct;
    import java.util.concurrent.atomic.AtomicLong;

    @Service
    public class GeneratorService {

        private AtomicLong id;

        @PostConstruct
        private void init(){
            id = new AtomicLong(0);
        }

        public long getId(){
            return id.incrementAndGet();
        }
    }
    单机测试QPS 3万(测试工程、测试脚本在同一机器运行。)
    硬件信息:CPU 2.7 GHz Intel Core i7 | 内存 16 GB 2133 MHz LPDDR3
    测试工具:JMeter
    展开
     5
     55
  • 程序水果宝
    2019-10-09
    老师说如果我们发现系统时钟不准,就可以让发号器暂时拒绝发号,直到时钟准确为止。我们的程序本身就是运行在系统中的,如何来判断系统中的时间是否准确呢?

    作者回复: 可以暂时记录上次发好的时间,然后和这次的时间比较

     3
     6
  • 小喵喵
    2019-10-09
    但是当数据库分库分表后,使用自增字段就无法保证 ID 的全局唯一性了?
    1.使用数据库的自增,设置起始值和步长不一样,不是一样可以实现吗?
    2.预估每天的数据量,预先生成ID存入缓存(比如Redis)里面,然后去取,这种方法也简单?

    作者回复: 其实很难预估数据量,某一天有活动咋办?不同的起始值也可,只是增加人工成本,增加了库表咋办?忘了设置咋办?

    
     4
  • gogo
    2019-10-10
    标准的snowflake算法最多支持69年,如果项目真的支撑到69年之后,应该怎么处理呢

    作者回复: 在没到69年的时候增加时间的位数……

     3
     2
  • stg609
    2019-10-09
    假设通过容器化来部署发号器,且同时会有多个发号器容器运行,那这个 worker Id 如何生成。容器自身的 id 是一串很长的16进制,无法转换为 worker id 吧?难道也需要引入 zookeeper 吗?有没有其他简单可行的方案?

    作者回复: 容器ID太长了。。。 其实引入zk也还好,对于zk是弱依赖,只是启动的时候拉一下机器ID

    
     2
  • jimmy
    2019-10-09
    snowflake方案中 现在一般公司都有容器虚拟化,所以每个实例都有自己的实例ID,以此作为唯一ID即可,另外保险起见在服务启动的时候可以向其他启动的服务发送check请求,确保ID全局唯一,这样可以不引入zk,让系统更简单些~

    作者回复: 容器ID太长了吧,比较占发号器的位数

    
     2
  • Lane
    2020-01-31
    老师我有疑问:中间的机器ID,同一毫秒内,3号机器先注册了一个用户,1号机器再注册一个用户。这样的话也不是顺序的了。

    作者回复: 是的,如果是独立部署的话就可以保证了

    
     1
  • 阿杜
    2019-12-20
    不仅仅是分库分表后的数据库,很多业务场景都需要分布式发号器,使用snowflake是个很好的选择,不过一般都是用的snowflake雪花算法,实现上会有所差异,比如机器位数和序号位数的选取就不同,1+41位时间戳+10机器区间位+12号递增或随机的数字,类似这种。uuid长度过长,也不递增,使用受限。不过snowflake算法有个问题就是服务器时间回拨的问题,就是时间可能不准,这个时候不能停止发号,我觉得可以采取的方式是:每个服务器存储最新的一个maxNewId,起个线程监控服务器时间是否正确,不正确就从maxNewId递增1获取,同事调准服务器时间,直到服务器时间正确。

    作者回复: 应该可行

    
     1
  • ET go home
    2019-10-09
    请问下同一时间位,同一机器,在生成序列号时,是要上锁的吧?

    作者回复: 是的 不过像redis那样单线程处理就好了

    
     1
  • 张珂
    2020-01-21
    老师好,想了解部署一套snowflake,性能怎么样?还有一个问题是,发号器虽然可以保证递增发号,但写入数据库时(假设有两个事务要写同一个表),那对于底层B+树也不一定顺序写入,无法利用磁盘顺序写的性能优化吧?

    作者回复: 性能在单实例单核可以达到2亿万次每秒

    发号器一般是改的redis

    
    
  • 五羊司机
    2019-12-25
    老师,不太明白,mycat也能生成唯一自增ID,为什么还要实现发号器,请问这俩有什么区别

    作者回复: mycat只能给数据库用,发号器更通用

    
    
  • 大鸡腿🍗
    2019-12-01
    感觉不引入zk也可以实现唯一,不同机器工作机器id不同,即使同一台机器同个时间后面12位序列号也不同呢
    
    
  • 疯狂咸鱼
    2019-11-22
    老师,序列号设置为10位每毫秒生成1024个序号,拿评论来说,也就是每秒支持1024*1000的并发评论么,另外,雪花算法生成的主键也会作为分库表的一列保存在数据库里么

    作者回复: 是的

    
    
  • yuan
    2019-11-13
    为什么snowflake的第一位一定是0?

    作者回复: 标准实现是的

     1
    
  • XD
    2019-11-03
    如果单纯为了保证分表之后自增主键唯一,在创建数据表的时候,配合auto_increment_offset和auto_increment_increment不就可以实现吗?(当然我不是说在微服务中不需要取号器)

    作者回复: 这样要对每一个库的offset都要维护,你要是分了1000张表,就要维护1000个offset

    
    
  • 吕宗霖
    2019-10-30
    老师好呀,发号器生成id当主键的话,由于位数较多,对数据库索引性能影响大么

    作者回复: 不会的

    
    
  • 长期规划
    2019-10-23
    老师,我理解发号器是单节点时,发出的号的单调递增的,但由于网络延时等,客户端收到的顺序并不一定严格单调递增,导致创建DB记录时,并不能保证按ID单调递增的顺序创建。不过,从秒级或更粗的粒度看,DB记录是按ID单调递增创建的
    
    
  • 长期规划
    2019-10-22
    老师,如果发号器部在一台机器上,使用多线程,那对于占12位的序号部分,在生成时,要用线程锁吧?

    作者回复: 可以单线程,比如类似redis的实现

    
    
  • 长期规划
    2019-10-22
    老师,序列号占12位,对应序列号最大值4096,如果一毫秒内请求生成唯一键的次数大于此值怎么办呢?我能想到的办法是当生成的序列号达到4096时,延时1毫秒,再生成。实际中,是这样处理吗?

    作者回复: 会发这么多号吗……

    
    
  • 长期规划
    2019-10-22
    学习了,之前面试时被问到如何设计ID生成器,没答好。
    
    
我们在线,来聊聊吧