Redis | 基于 Redis 实现机器列表 Token 缓存的 Java 实现

news2025/3/31 12:11:25

关注:CodingTechWork

引言

  在分布式系统中,Token 缓存是一种常见的需求。它可以帮助我们快速验证用户身份,减少对数据库的频繁访问,提高系统的性能和响应速度。本文将介绍如何使用 Redis 来实现机器列表的 Token 缓存,在 Kubernetes Pod 部署的环境中,为了避免多个 Pod 同时执行相同的定时任务(如刷新缓存 Token),我们需要引入分布式锁机制。以下是基于RedisTemplate分布式锁实现的分布式刷新缓存 Token 的完整 Java 示例代码。

为什么选择 Redis

  Redis 是一个高性能的键值存储数据库,它提供了丰富的数据结构和极高的读写速度。以下是选择 Redis 实现 Token 缓存的原因:

  • 高性能:Redis 的读写速度非常快,能够轻松应对高并发场景下的 Token 验证请求。
  • 持久化支持:虽然 Redis 是内存数据库,但它支持多种持久化方式,可以保证数据在机器故障时不会丢失。
  • 易于使用:Redis 提供了丰富的客户端库,方便在各种编程语言中使用。

设计思路

  1. Token 的生成与存储:使用 UUID 生成唯一的 Token,并通过 RedisTemplate 存储到 Redis 中,同时设置过期时间
  2. Token 的验证:通过 RedisTemplate 从 Redis 中获取 Token,并检查其是否存在和是否过期。
  3. 分布式锁:使用 Redis 实现分布式锁,确保在分布式环境中只有一个 Pod 能够执行 Token 刷新任务。
  4. 定时刷新 Token:使用 Spring 的 @Scheduled注解实现定时任务,结合分布式锁确保同一时间只有一个 Pod 执行 Token 刷新操作。(当然,我们也可以引入xxl-job组件来实现定时任务)

Java 实现

引入依赖

在 Maven 项目中,需要引入 Spring Boot Starter Data Redis`` 和 Spring Boot Starter Scheduling 的依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-scheduling</artifactId>
</dependency>

Redis 配置类

创建一个 Redis 配置类,用于配置 RedisTemplate。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 设置键的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // 设置值的序列化方式
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;
    }
}

分布式锁工具类

创建一个分布式锁工具类,用于获取和释放锁。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLock {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String LOCK_PREFIX = "scheduled_task_lock:";
    // 锁过期时间(秒)
    private static final int LOCK_EXPIRE_TIME = 30; 

    /**
     * 尝试获取分布式锁
     * @param taskName 任务名称
     * @param nodeIdentifier 节点标识
     * @return 是否获取到锁
     */
    public boolean tryAcquireLock(String taskName, String nodeIdentifier) {
        String lockKey = LOCK_PREFIX + taskName;
        String lockValue = String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE_TIME * 1000);
        if (Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, LOCK_EXPIRE_TIME, TimeUnit.SECONDS))) {
            return true;
        } else {
            String currentValue = redisTemplate.opsForValue().get(lockKey);
            if (currentValue != null && Long.parseLong(currentValue) < System.currentTimeMillis()) {
                String oldValue = redisTemplate.opsForValue().getAndSet(lockKey, lockValue);
                if (oldValue != null && oldValue.equals(currentValue)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 释放分布式锁
     * @param taskName 任务名称
     * @param nodeIdentifier 节点标识
     */
    public void releaseLock(String taskName, String nodeIdentifier) {
        String lockKey = LOCK_PREFIX + taskName;
        redisTemplate.delete(lockKey);
    }
}

Token 缓存类

创建一个 Token 缓存类,用于生成、存储和验证 Token,同时提供刷新 Token 的方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class TokenCache {
    private static final String TOKEN_PREFIX = "token:";
    // Token 过期时间(秒)可以配置化
    private static final long EXPIRE_TIME = 60 * 60; 
    // 提前 5 分钟刷新 Token可以配置化
    private static final long REFRESH_THRESHOLD = 60 * 5; 

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 生成 Token
     */
    public String generateToken() {
        return java.util.UUID.randomUUID().toString();
    }

    /**
     * 存储 Token
     * @param token Token
     * @param machineId 机器 ID
     */
    public void storeToken(String token, String machineId) {
        redisTemplate.opsForValue().set(TOKEN_PREFIX + token, machineId, EXPIRE_TIME, TimeUnit.SECONDS);
    }

    /**
     * 验证 Token
     * @param token Token
     * @return 验证结果(true 表示有效,false 表示无效)
     */
    public boolean verifyToken(String token) {
        Object machineId = redisTemplate.opsForValue().get(TOKEN_PREFIX + token);
        return machineId != null;
    }

    /**
     * 刷新 Token
     * @param token Token
     */
    public void refreshToken(String token) {
        redisTemplate.expire(TOKEN_PREFIX + token, EXPIRE_TIME, TimeUnit.SECONDS);
    }
}

定时任务类

创建一个定时任务类,用于定期检查并刷新即将过期的 Token。使用分布式锁确保同一时间只有一个 Pod 执行该任务。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Set;

@Component
public class TokenRefreshTask {
    private static final String TASK_NAME = "refreshTokenTask";
    // 节点标识,可以根据实际情况动态生成
    private static final String NODE_IDENTIFIER = "node-1"; 

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private TokenCache tokenCache;
    @Autowired
    private RedisDistributedLock redisDistributedLock;

    /**
     * 定时任务:刷新即将过期的 Token
     */
    @Scheduled(fixedRate = 60 * 1000) // 每分钟执行一次
    public void refreshTokenTask() {
        if (redisDistributedLock.tryAcquireLock(TASK_NAME, NODE_IDENTIFIER)) {
            try {
                Set<String> keys = redisTemplate.keys(TokenCache.TOKEN_PREFIX + "*");
                if (keys != null) {
                    for (String key : keys) {
                        Long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
                        if (ttl != null && ttl <= TokenCache.REFRESH_THRESHOLD) {
                            tokenCache.refreshToken(key.replace(TokenCache.TOKEN_PREFIX, ""));
                            System.out.println("Token 刷新成功: " + key);
                        }
                    }
                }
            } finally {
                redisDistributedLock.releaseLock(TASK_NAME, NODE_IDENTIFIER);
            }
        } else {
            System.out.println("Token 刷新任务已被其他节点执行");
        }
    }
}

启动类

确保启动类中启用了定时任务。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class TokenCacheApplication {
    public static void main(String[] args) {
        SpringApplication.run(TokenCacheApplication.class, args);
    }
}

运行结果

在 Kubernetes 环境中部署多个 Pod 后,运行程序,观察输出结果:

Token 刷新成功: token:0f5d3f6e-7f8b-4d9b-8a1b-4d8c7f6e8d9b
Token 刷新任务已被其他节点执行

从结果可以看出,只有获取到分布式锁的 Pod 会执行 Token 刷新任务,其他 Pod 会跳过该任务。

总结

  通过引入分布式锁机制,我们成功解决了在 Kubernetes Pod 部署环境下分布式刷新缓存 Token 的问题。使用 Redis 实现的分布式锁确保了同一时间只有一个 Pod 能够执行 Token 刷新任务,避免了重复执行的问题。这种机制不仅适用于 Token 刷新,还可以扩展到其他需要分布式定时任务的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2323693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序语音识别功能 wx.createInnerAudioContext

页面样式htmlcss <view class"recorder_content"><view class"result_content"><view class"r_title">语音识别结果显示:</view><view class"r_h_input"><text wx:if"{{resultDetails.result}…

Web网页内嵌福昕OFD版式办公套件实现在线预览编辑PDF、OFD文档

PDF&#xff0c;即Portable Document Format&#xff0c;用于以一种独立于应用程序、硬件、操作系统的方式共享和查看文档&#xff1b;OFD&#xff0c;即Office Open Document Format for Document&#xff0c;是一种在政府公文和法律文件等领域广泛应用的电子文件格式&#xf…

ADZS-ICE-2000和AD-ICE2000仿真器在线升级固件

作者的话 近期发现有些兄弟的ICE-2000仿真器链接DSP报错&#xff0c;然后test第四步不通过&#xff0c;我就拿我的仿真器也试了一下&#xff0c;发现ADI悄咪咪的在线升级仿真器固件&#xff0c;有些兄弟不会操作&#xff0c;就会导致仿真器升级失败&#xff0c;连不上目标板&a…

第十一章:Python PIL库-图像处理

一、PIL库简介 PIL&#xff08;Python Imaging Library&#xff09;是一个功能强大的图像处理库&#xff0c;它提供了丰富的图像处理功能&#xff0c;包括图像的打开、处理和保存等操作。PIL支持多种图像文件格式&#xff0c;如JPEG、PNG、BMP等&#xff0c;并且可以完成对图像…

python项目整体文件和依赖打包

python项目整体文件和依赖打包 python项目整体文件和依赖打包 python项目整体文件和依赖打包 准备工作&#xff1a;扫描项目中必要的依赖包 pip install pipreqs pipreqs . 会有一些警告包&#xff0c;需要pip list进行版本修正,这里是三个包第一步&#xff1a;在虚拟环境中安…

logstash收集数据

防止ES的的I/O的压力过大&#xff0c;使用redis/kafka进行缓冲。 对redis的要求 Redis input plugin | Logstash Reference [8.17] | Elastic 一般企业要求的架构 我实现的架构 filebeat把数据传给logstash 配置好filebeat把收集到的数据输入到redis 然后执行命令&#xff0…

智能运维时代的网络拓扑管理:乐维监控的架构可视化实践

在数字化转型的浪潮中&#xff0c;企业IT基础设施正经历着前所未有的复杂化进程。当数以千计的网络设备、服务器、存储系统构成庞大网络体系时&#xff0c;如何实现全局可视化管理已成为企业数字化转型的关键命题。乐维监控网络拓扑系统作为新一代智能运维平台的核心组件&#…

CentOS 7 安装 EMQX (MQTT)

CentOS 7 安装 EMQX 通过 Yum 源安装 EMQX 支持通过 Yum 源安装&#xff0c;您可通过以下 Yum 命令从中自动下载和安装 EMQX。 通过以下命令配置 EMQX Yum 源&#xff1a; curl -s https://assets.emqx.com/scripts/install-emqx-rpm.sh | sudo bash安装以下依赖项&#xff…

人工智能:officeAI软件,如何调整AI对话界面的字体?

1、首先&#xff0c;随便打开一个excel&#xff08;使用wps&#xff09; 依次点击上方的【OfficeAI】—【右侧面板】 2、在弹出的面板中&#xff0c;输入&#xff1a;助手设置 &#xff0c; 然后按【回车】发送出去 3、之后会弹出界面&#xff0c;在【样式设定】中&#xff…

Qt之共享内存类QSharedMemory的使用及实现原理(全)

目录 1.简介 2.使用 3.实现原理 3.1.Windows内存映射 3.2.POSIX 共享内存 3.3.System V 共享内存 3.4.QSharedMemory的实现原理 4.总结 1.简介 QSharedMemory 是 Qt 框架提供的一个类&#xff0c;用于在不同进程或线程之间实现共享内存的管理。借助共享内存&#xff0c…

Problem A: 接口使用

1.题目问题 2.样例 3.代码实现 补充&#xff1a;注意空格 // 定义Vehicle接口 interface Vehicle {void start();void stop(); }// 实现Vehicle接口的Bike类 class Bike implements Vehicle {Overridepublic void start() {System.out.println("i am bike,i am running&…

用Python插入Excel表格到Word文档

在日常办公场景中&#xff0c;通过Python脚本自动化整合Excel数据与Word文档&#xff0c;能够实现表格的智能迁移&#xff0c;满足不同场景下数据呈现的专业性要求。直接提取表格内容插入Word适用于需要快速传递核心数据的场景&#xff0c;确保信息精准直达&#xff1b;完整复制…

合合信息TextIn大模型加速器 2.0来了:智能文档解析和图表解析能力全面升级

合合信息“TextIn大模型加速器 2.0”版本来了&#xff1a;文档解析和图表解析能力全面升级 背景 在日常工作中&#xff0c;我们常常遇到无法直接复制的文档内容或图片内容&#xff0c;这些内容通常需要进行识别和解析。一个典型的例子是&#xff0c;当我们需要将折线图转化为…

消息队列Message Queue

前面&#xff0c;我们在黑点点评中秒杀场景中&#xff0c;首次了解到消息队列MQ&#xff0c;它主要解决了秒杀场景中异步场景&#xff0c;提升了并发性&#xff0c;吞吐量。可是还是对消息队列又很多的疑惑&#xff1f; 消息队列是什么 消息队列是一种通信协议或中间件&#…

如何利用AI智能生成PPT提升工作效率

如何利用AI智能生成PPT提升工作效率&#xff1f;PPT制作曾经是每个人办公生活中的一大痛点。你有多久没有在制作PPT时感到焦头烂额&#xff0c;选模板、调整格式、插入图片&#xff0c;每一项都得花费大量的时间和精力&#xff0c;最后还未必能做出一份令人满意的效果。随着人工…

WIN11 企业版 部署Dify+Docker

Dify&#xff08;Do it for you&#xff09;是一款开源的大语言模型应用开发平台&#xff0c;旨在简化AI应用的创建、部署和管理过程&#xff0c;使开发者能够更快速、更轻松地构建和运营基于GPT等模型的AI应用。 Dify平台创建和运营一个AI chatbot应用&#xff0c;涉及到登录…

1.25-20GHz/500ns超快跳频!盛铂SWFA300国产捷变频频率综合器模块赋能雷达/5G/电子战高频精密控制 本振/频综模块

盛铂SWFA300捷变频频率综合器模块简述&#xff1a; 盛铂科技国产SWFA300捷变频频率综合器是一款在频率范围内任意两点频率的跳频时间在500nS以内的高速跳频源&#xff0c;其输出频率范围为1.25GHz至20GHz&#xff0c;频率的最小步进为10kHz。同时它拥有优秀的相位噪声特性&…

代理IP协议详解HTTP、HTTPS、SOCKS5分别适用于哪些场景

“代理IP协议在现代网络通信中扮演着至关重要的角色。它们通过提供中间层服务&#xff0c;帮助用户匿名访问网络、绕过地理限制、提高安全性和加速数据传输。HTTP、HTTPS和SOCKS5是三种最常见的代理IP协议&#xff0c;每种协议都有其特定的用途和适用场景。” HTTP代理及其适用…

AIGC工具平台-通用抠图换背景

本模块采用先进的大模型智能算法&#xff0c;精准识别并分割图像中的人物或物品主体&#xff0c;实现高效、精准、智能化的抠图处理。无论是人物肖像、产品展示&#xff0c;还是复杂场景&#xff0c;该工具均能准确提取主体&#xff0c;并自动适配至背景图像&#xff0c;实现自…

word快速创建虚拟文字

创建虚拟文字的作用&#xff1a;如培训新员工使用 Word&#xff0c;用虚拟文字演示如何设置段落格式。不需要你随便乱敲文字或者去复制一段文字过来。帮你节约了时间&#xff01; 两个函数的使用必须在段落的开头&#xff01;&#xff01;&#xff01; rand函数 在 Word 中…