生产环境有多台服务器,注册中心使用eureka,springboot项目中使用@Scheduled注解实现定时,现在每一台都会跑一次定时,如何让多台服务器上的定时任务轮询执行
7条回答 默认 最新
关注
引自免费微信小程序:皆我百晓生
要解决在分布式环境中确保只有一个实例执行定时任务的问题,可以采用 leader election(领导选举)策略。在这种情况下,我们可以使用一个轻量级的分布式协调服务,例如 ZooKeeper 或者 Redis 的 String 事务操作。这里我将提供一个基于 Redis 的解决方案。
首先,你需要在应用启动时,通过 Redis 进行 leader election,确保只有一个节点成为 leader 并执行定时任务。以下是步骤:
- 引入 Redis 相关依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
- 配置 Redis 连接:
在
application.properties
文件中添加 Redis 配置:
spring.redis.host=your_redis_host spring.redis.port=your_redis_port
- 创建一个用于 leader election 的工具类
LeaderElectionService
:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service public class LeaderElectionService { private static final String LEADER_KEY = "distributed-task-leader"; @Autowired private RedisTemplate<String, String> redisTemplate; public boolean electLeader(String serverId) { try (RedisConnection connection = redisTemplate.getConnectionFactory().getConnection()) { // 使用 Redis 的 SETNX 命令设置键值对,只有当 key 不存在时,才会设置成功,并返回 true。 // 如果多个实例同时尝试获取锁,只会有一个返回 true,其他返回 false。 return connection.setnx(LEADER_KEY, serverId).booleanValue(); } } public void releaseLeadership() { redisTemplate.delete(LEADER_KEY); } }
- 在需要执行定时任务的服务类中注入
LeaderElectionService
,并在方法上添加@PostConstruct
注解确保在定时任务执行之前进行 leader election:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class DistributedTaskService { private static final long EXECUTION_INTERVAL_SECONDS = 60; // 定期执行间隔时间,单位:秒 @Autowired private LeaderElectionService leaderElectionService; @Scheduled(fixedRate = EXECUTION_INTERVAL_SECONDS * 1000) @PostConstruct public void executeDistributedTask() { String serverId = "server-" + UUID.randomUUID(); // 生成唯一标识符,可以用 IP 地址或其他方式替代 if (leaderElectionService.electLeader(serverId)) { System.out.println("Server " + serverId + " is the leader, executing task..."); // 执行你的定时任务逻辑 // ... leaderElectionService.releaseLeadership(); } else { System.out.println("Server " + serverId + " is not the leader, skipping task execution."); } } }
这样,在多台服务器上运行此应用时,只有被选为 leader 的服务器会执行定时任务。每次服务器重启时,都会重新竞争 leader 身份,从而确保任务始终由一台服务器执行。注意,这个方案依赖于 Redis 的可用性,如果 Redis 出现故障,可能会影响 leader election 的结果。
解决 无用评论 打赏 举报 编辑记录
悬赏问题
- ¥30 不会,学习,有偿解答
- ¥15 SQL查询语句报错(检查)
- ¥15 此表中公式应该怎么写
- ¥15 求HI-TECH PICC 9.50 PL3安装包
- ¥15 下载ctorch报错,求解
- ¥15 如何入门学习c语言,单片机
- ¥15 idea 编辑语言的选择
- ¥15 Windows下部署Asmjit
- ¥15 请问双层规划模型的上下层目标函数不一致,是如何保证迭代收敛性的
- ¥30 微信小程序 前端页面内容搜索