结合redis在spring架构体系中使用雪花算法(代码片段)

孙广明的博客 孙广明的博客     2023-01-28     201

关键词:


前言

分布式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;

/**
 * @author sungm
 * @since 2021-11-06 21:16
 */
@Slf4j
@Service
public class SnowflakeManager 

    /** 开始时间戳: 2020-01-01 00:00:00 */
    private static final Long START_TIMESTAMP = 1577808000000L;
    /** 12位最大序号: 2^12 - 1 */
    private static final Long MAX_SEQ = ~(-1L << 12);
    /** 10位最大机器码: 2^10 -1 */
    private static final Long MAX_MACHINE = ~(-1L << 10);

    /** 当前机器码 */
    private Long machine;
    /** 最后生成的序号 */
    private Long lastSeq = 0L;
    /** 最后一个序号生成的时间 */
    private Long lastSqlTimestamp = 0L;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /** 定义雪花算法的 Key,把机器码存到Redis中 */
    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;
        /* 0 - 41位时间戳 - 10位机器码 - 12位序列*/
        return ((now - START_TIMESTAMP) << 22) | machine << 12 | lastSeq;
    



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


二、雪花算法

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

为啥在将 Jedis 与 Spring Data 结合使用时,数据会以奇怪的键存储在 Redis 中?

】为啥在将Jedis与SpringData结合使用时,数据会以奇怪的键存储在Redis中?【英文标题】:WhyisdatagettingstoredwithweirdkeysinRediswhenusingJediswithSpringData?为什么在将Jedis与SpringData结合使用时,数据会以奇怪的键存储在Redis中?【发布时间】... 查看详情

雪花算法中机器id保证全局唯一(代码片段)

...否过期需要重新分配;另一种是不设置过期时间,只依靠在spring容器销毁的时候去删除记录(但是这种方式容易删除失败)实现方式一<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId>... 查看详情

springboot分布式全局唯一id的生成-雪花算法snowflake

...xff0c;怎么使用全局唯一id?在分布式是,微服务的架构中,或者大数据分库分表中,多个不同节点怎么保持每台机器生成的主键id不重复,具有唯一性?方案1:mysql的自增主键;设定一定的步长;... 查看详情

检查雪花中的表架构更改

】检查雪花中的表架构更改【英文标题】:Tochecktableschemachangeinsnowflake【发布时间】:2021-09-1816:38:48【问题描述】:我有一张雪花表,我正在从AWS作业中插入数据。在将数据插入雪花之前,我想检查插入值的列数和数据类型是否... 查看详情

springboot中使用雪花算法生成雪花id(代码片段)

...、什么是雪花算法2、雪花算法的优缺点3、springboot项目中使用雪花算法使用1、什么是雪花算法雪花算法(Snowflake)是一种生成全局唯一ID的算法,由Twitter公司开发。它可以在分布式系统中生成全局唯一的ID,解决... 查看详情

在雪花中结合 OBJECT_AGG 和 GROUP BY

】在雪花中结合OBJECT_AGG和GROUPBY【英文标题】:CombiningOBJECT_AGGandGROUPBYinSnowflake【发布时间】:2021-09-0716:46:59【问题描述】:有没有办法将雪花中的GROUPBY和OBJECT_AGG与两者之间的不同聚合级别结合起来?在以下示例中,对于每个城... 查看详情

在 Mongoose Schema 中使用雪花作为类型

...以及我的MongoDB数据库中的主键。问题:我想在我的Mongoose架构中使用Discord的Snowfla 查看详情

策略模式和spring的结合在项目中的应用

一、策略模式        策略模式的定义:策略模式是对算法的封装,把使用算法的责任和算法本身分隔开,委派给不同的对象管理。策略模式通常把一系列的算法包装到一系列的策略类里面,作为一个抽象策略... 查看详情

spring模块组成(框架组成整体架构体系架构体系结构)

Spring是一个轻量级Java开发框架,致力于简化Java开发。Spring总共大约有20个模块,由1300多个不同的文件构成。而这些组件被分别整合在核心容器(CoreContainer)?、?AOP(AspectOrientedProgramming)和设备支持(Instrmentation)?、数据访问与... 查看详情

缓存架构中分布式一致性hash应用解析(代码片段)

...应用中,并不是只应用redis等中间件去处理,也会结合本地缓存去处理实际的应用场景。一致性Hash算法在缓存架构中应用Hash 查看详情

监控雪花数据库架构更改的最佳方法?

】监控雪花数据库架构更改的最佳方法?【英文标题】:BestapproachtomonitorschemachangeonSnowflakedatabase?【发布时间】:2019-11-1419:42:18【问题描述】:谁能建议监控雪花数据库架构变化的最佳方法?我会在任何架构更改时触发我的应用... 查看详情

编程实践golang实现雪花算法

...时间顺序),订单编号等。自增ID:对于数据敏感场景不宜使用,且不适合于分布式场景。GUID:采用无意义字符串,数据量增大时造成访问过慢,且不宜排序。1.1.3.算法描述最高位是符号位,始终为0,不可用。41位的时间序列,... 查看详情

mybaits-plus使用雪花算法给字段赋值技巧

在mybatis-plus中,如果不给id属性赋值,将会使用雪花算法自动赋值!  注意事项:    1.目前仅知道为id的字段会自动赋值    2.类中对应的字段应该为Long    3.数据库中为id的字段可以设置为VARCHAR类型,(一开始也懵... 查看详情

雪花数据库中的公共模式

...7-2612:37:12【问题描述】:当我们创建数据库时会创建公共架构,如果我们不指定任何架构,则会在公共架构下创建表。您能否告诉我您是否看到或遇到从数据库中删除公共架构的任何问题,因为我不希望任何人在公共架构下创建... 查看详情

Auth Server 是不是应该在微服务架构中与 User Service 结合使用?

】AuthServer是不是应该在微服务架构中与UserService结合使用?【英文标题】:ShouldtheAuthServerbecombinedwiththeUserServiceinamicroservicesarchitecture?AuthServer是否应该在微服务架构中与UserService结合使用?【发布时间】:2017-12-0618:57:34【问题描... 查看详情

分布式架构体系知识(代码片段)

...法缓存击穿缓存雪崩分布式微服务单体应用微服务微服务架构分布式服务分布式锁实现方法两大类分布式锁第一类第二类分布式事务2PC协调者故障分析协调者故障,通过选举得到新协调者3PCTCC本地消息表消息事务最大努力通... 查看详情

分布式全局唯一id解决方案(雪花算法)(代码片段)

...分布式ID吗Redis集群实现分布式ID的利弊雪花算法(SonwFlake)使用糊涂工具包实现雪花算法优缺点:为什么需要分布式全局唯一ID以及分布式ID的业务需求在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识如在... 查看详情

springboot分布式全局唯一id的生成-雪花算法snowflake

...xff0c;怎么使用全局唯一id?在分布式是,微服务的架构中,或者大数据分库分表中,多个不同节点怎么保持每台机器生成的主键id不重复,具有唯一性?方案1:mysql的自增主键;设定一定的步长;... 查看详情