栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

结合Redis在Spring架构体系中使用雪花算法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

结合Redis在Spring架构体系中使用雪花算法


前言

分布式ID生成策略有多种,各有利弊。这里记录下在工作中我结合Redis在Spring架构体系中使用雪花算法生成分布式ID的方式。


一、代码部分
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;


@Slf4j
@Service
public class SnowflakeManager {

    
    private static final Long START_TIMESTAMP = 1577808000000L;
    
    private static final Long MAX_SEQ = ~(-1L << 12);
    
    private static final Long MAX_MACHINE = ~(-1L << 10);

    
    private Long machine;
    
    private Long lastSeq = 0L;
    
    private Long lastSqlTimestamp = 0L;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    
    private static final String RECORD_SNOWFLAKE_MACHINE_SEQ_REDIS_KEY = "RECORD_SNOWFLAKE_MACHINE_SEQ";
    private static final String RECORD_SNOWFLAKE_MACHINE_MAP_REDIS_KEY = "RECORD_SNOWFLAKE_MACHINE_MAP";

    @PostConstruct
    public void init() throws UnknownHostException {
        //获取当前机器的IP地址
        final String hostAddress = InetAddress.getLocalHost().getHostAddress();
        //初始化Redis缓存
        stringRedisTemplate.opsForValue().setIfAbsent(RECORD_SNOWFLAKE_MACHINE_SEQ_REDIS_KEY, "0");
        stringRedisTemplate.opsForHash().putIfAbsent(RECORD_SNOWFLAKE_MACHINE_MAP_REDIS_KEY, "default", "0");
        //不包含当前主机IP地址时,设置递增的值
        if (!stringRedisTemplate.opsForHash().keys(RECORD_SNOWFLAKE_MACHINE_MAP_REDIS_KEY).contains(hostAddress)) {
            stringRedisTemplate.opsForHash().put(RECORD_SNOWFLAKE_MACHINE_MAP_REDIS_KEY, hostAddress
                    , stringRedisTemplate.opsForValue().increment(RECORD_SNOWFLAKE_MACHINE_SEQ_REDIS_KEY, 1L).toString());
        }
        //获取当前主机对应的编码
        machine = Long.parseLong((String) stringRedisTemplate.opsForHash().get(RECORD_SNOWFLAKE_MACHINE_MAP_REDIS_KEY, hostAddress));
        log.info("主机:{},机器码:{}", hostAddress, machine);
        //做个校验
        if (machine > MAX_MACHINE) {
            throw new RuntimeException("机器码已达到最大值" + MAX_MACHINE + ", 请排查无效数据!");
        }
    }

    public synchronized Long nextId() {
        //获取当前时间
        Long now = System.currentTimeMillis();
        if (lastSqlTimestamp.equals(now) && ++lastSeq > MAX_SEQ) {
            throw new RuntimeException("同一毫秒内生成的序号达到" + MAX_SEQ + ", 请注意并发量!");
        }
        if (!lastSqlTimestamp.equals(now)) {
            lastSeq = 0L;
        }
        lastSqlTimestamp = now;
        
        return ((now - START_TIMESTAMP) << 22) | machine << 12 | lastSeq;
    }

}

说明:同一应用多个实例部署在不同宿主机上面,利用了宿主机的IP地址不重复的特性,结合Redis单线程的特点来给不同的应用实例生成不同的机器码。如果可以指定每个实例都机器码,则可以简化这一操作,直接通过application.yml配置给不同的应用实例指定机器码即可。


二、雪花算法

这里不讲雪花算法的原理了,相信大家随意百度一下就能知道原理、其核心算法是左移。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/446201.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号