zoukankan      html  css  js  c++  java
  • 基于雪花算法的单机版

    雪花算法是基于时间戳的一种生成随机数的算法。网上的改变版也很多,当前基于我们的业务场景,改变了使用于我们业务场景的算法。

    1、生成的Id长度不能超过17,,最大值为:160111892926110,即前端支持的最大数字类型长度

    2、没有统一的服务来产生ID,需要将Id在各自服务中自主实现

    3、一台服务器可能部署多台实例

    4、实例随时会根据业务量的扩展,进行扩容。

    基于上述方式改变的算法如下:

    基于Mysql将服务所在机器的IP和PORT作为唯一标识存储在数据库中,这样就会在库中形成唯一的ID。之后根据升序即可获取当前IP和PORT所在列表中的位置,这样就可以固有一套IP对应表,同时,机器标识信息占用位数较少,目前定在了127位,仅需要7个BIT位。序列值为单秒最多支持创建31个,也就是需要5个BIT位。这样就有了12个BIT位,其余位数均为时间戳所在位数。剩余的41位可以支持69年,对于一个普通产品来说,足够了。下图为具体展示

    11111111111111111111111111111111111111111 1111111  11111

    时间戳                                                             机器        序列号

    具体代码实现:

    /**
     * <p>
     *    基于雪花算法改造的ID生成器
     * <p>
     *
     * @author woniu
     * @date 2020年01月14日
     * @version 1.0
     */
    public class IdUtils {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(IdUtils.class);
    
        private static IdUtils idUtils;
    
        /**
         * 上次更新时间
         */
        private static Long lastStamp = -1L;
    
        private static Long sqlNUm = 0L;
    
        private static Integer hostId = -1;
    
        private IpListService ipListService = AppContext.getAppObject(IpListService.class);
    
        /**
         * 基于2020年1月1日开始计算
         */
        private static final Long BEGIN_TIME = 1577808000000L;
    
        private static final Integer SEQ_NUM_LEN = 5;
    
        /**
         * 机器占位符,当前最大支持127个实例
         */
        private static final Integer HOST_LEN = 7;
    
        /**
         * 序列号的最大值,2的SEQ_NUM_LEN(5)次方减1 : 2^5 -1 = 31
         */
        private static final Integer MAX_SEQ_NUM = 31;
    
        /**
         * 时间戳的偏移位
         * 前端支持最大值为:9007199254740991,去除后11位,还有41位,支持69年
         */
        private static final Integer TIME_STAMP_SHIFT = HOST_LEN + SEQ_NUM_LEN;
    
        /**
         * 初始化实例
         * @return
         */
        private static IdUtils getInstance() {
            if (idUtils == null) {
                idUtils = new IdUtils();
            }
            return idUtils;
        }
    
        /**
         * 生成Id的入库
         */
        public static synchronized Long genId() {
            if (hostId == -1L) {
                initIp();
            }
            Long currentTime = System.currentTimeMillis();
            if (sqlNUm > MAX_SEQ_NUM) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                currentTime = System.currentTimeMillis();
                sqlNUm = 0L;
            }
            if (currentTime.longValue() == lastStamp.longValue()) {
                return ((currentTime - BEGIN_TIME) << 11) | (hostId << 6) | (sqlNUm ++);
            } else {
                sqlNUm = 0L;
                lastStamp = currentTime;
                return ((currentTime - BEGIN_TIME) << 11) | (hostId << 6) | (sqlNUm ++);
            }
        }
    
        /**
         * 初始化IP信息
         */
        private static void initIp() {
            try {
                String localIp = IpPortUtils.getLocalIp();
                String port = String.valueOf(IpPortUtils.getHttpPort());
                if (!getHostId(localIp, port)) {
                    IpList localIpList = new IpList();
                    localIpList.setIp(localIp);
                    localIpList.setPort(port);
                    localIpList.setCreateTime(new Date());
                    localIpList.setUpdateTime(new Date());
                    getInstance().ipListService.saveOrUpdate(localIpList);
                    getHostId(localIp, port);
                }
            } catch (Exception e) {
                LOGGER.error("init ip error", e);
                throw new RuntimeException();
            }
        }
    
        /**
         * 获取hostId信息,如果获取则返回true,反之false
         * @param localIp
         * @param port
         * @return
         */
        private static boolean getHostId(String localIp, String port) {
            List<IpList> ipList = getInstance().ipListService.findAllByAsc();
            for (int i = 0; i < ipList.size(); i++) {
                IpList ip = ipList.get(i);
                if (ip.getIp().equals(localIp) && ip.getPort().equals(port)) {
                    hostId = i;
                    return true;
                }
            }
            return false;
        }
    
    }
  • 相关阅读:
    Functional Programming Contest
    CodeChef--SEPT14小结
    Weekly 10 小结
    CSS中的 REM PX EM
    phoenegap3.5 采坑
    PPT插件 用js制作PPT
    js 代码命名规范系列
    文档列表
    mockjax MOCK.js的拦截ajax请求
    css Tab选项卡
  • 原文地址:https://www.cnblogs.com/woniu4/p/12194627.html
Copyright © 2011-2022 走看看