共计 3012 个字符,预计需要花费 8 分钟才能阅读完成。
详细讨论了 ShedLock 的原理、配置步骤以及在实际项目中的应用场景,为处理复杂的分布式系统任务提供了有力支持。
在当今的分布式计算环境中,协调多个节点之间的任务执行,确保它们在没有冲突或重复的情况下执行,面临着重大挑战。无论是管理周期性任务、批处理过程还是关键系统任务,保持同步和一致性对于无缝运行至关重要。
问题
假设我们需要按计划运行某些任务,无论是数据库清理任务还是某些数据生成任务。如果直接解决这个问题,你可以使用 Spring Framework 中包含的 `@Schedules` 注解来解决这个问题。该注解允许您按固定间隔或按 cron 计划运行代码。但是,如果我们的服务实例数量超过一个怎么办?在这种情况下,任务将在我们的每个服务实例上执行。
ShedLock
ShedLock 确保您的定时任务在同一时间最多只执行一次。该库通过外部存储实现锁。如果一个任务在一个实例上执行,锁被设置,所有其他实例不等待,并跳过任务的执行。这实现了“最多执行一次”。外部存储可以是关系型数据库(PostgreSQL、MySQL、Oracle 等)通过 JDBC 工作,NoSQL(Mongo、Redis、DynamoDB)以及许多其他存储(完整列表可以在项目页面上找到)。
让我们以使用 PostgreSQL 为例。首先,让我们使用 Docker 启动数据库:
docker run -d -p 5432:5432 --name db
-e POSTGRES_USER=admin
-e POSTGRES_PASSWORD=password
-e POSTGRES_DB=demo
postgres:alpine
现在需要创建一个锁表。在项目页面上,我们需要找到针对 PostgreSQL 的 SQL 脚本:
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL,
lock_until TIMESTAMP NOT NULL,
locked_at TIMESTAMP NOT NULL,
locked_by VARCHAR(255) NOT NULL,
PRIMARY KEY (name)
);
这里:
-
`name` – 锁的唯一标识符,通常表示被锁定的任务或资源
-
`lock_until` – 指示持有锁的结束时间的时间戳
-
`locked_at` – 指示获取锁的时间戳
-
`locked_by` – 获取锁的实体的标识符(例如,应用程序实例)
接下来,创建一个 Spring Boot 项目并在 `build.gradle` 中添加必要的依赖项:
implementation 'net.javacrumbs.shedlock:shedlock-spring:5.10.2'
implementation 'net.javacrumbs.shedlock:shedlock-provider-jdbc-template:5.10.2'
现在描述配置:
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
public class ShedLockConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.usingDbTime()
.build());
}
}
让我们创建一个 `ExampleTask`,每分钟开始一次并执行一些耗时动作。为此,我们将使用 `@Scheduled` 注解:
@Service
public class ExampleTask {@Scheduled(cron = "0 * * ? * *")
@SchedulerLock(name = "exampleTask", lockAtMostFor = "50s", lockAtLeastFor = "20s")
public void scheduledTask() throws InterruptedException {System.out.println("task scheduled!");
Thread.sleep(15000);
System.out.println("task executed!");
}
}
在这里,我们使用 `Thread.sleep` 模拟任务的执行时间为 15 秒。一旦应用程序启动并任务执行开始,将在数据库中插入一条记录。
如果同时,另一个应用程序尝试运行任务,它将无法获取锁并跳过任务执行:
2024-02-18 08:08:50.057 DEBUG 45988 --- [scheduling-1] n.j.s.core.DefaultLockingTaskExecutor
: Not executing 'exampleTask'. It's locked.
在第一个应用程序获取锁时,会在数据库中创建一条记录,该记录的锁时间等于锁设置中的 `lockAtMostFor`。这个时间是必要的,以确保锁不会永远设置,以防应用程序崩溃或由于某种原因终止(例如,在 Kubernetes 中从一个节点驱逐 Pod 到另一个节点)。成功执行任务后,应用程序将更新数据库条目,并将锁定时间减少到当前时间,但如果任务执行时间非常短,则此值不能小于配置中的 `lockAtLeastFor`。此值有助于最大程度地减少实例之间的时钟不同步。它确保您的定时任务只被同时执行一次。
结论
ShedLock 是协调复杂 Spring 应用程序中任务的有用工具。它确保任务顺利运行且仅运行一次,即使跨多个实例也是如此。它易于设置,并为 Spring 应用程序提供了可靠的任务处理能力,使其成为处理分布式系统的任何人都很有价值的工具。 文章来源:https://www.toymoban.com/diary/apps/714.html
项目代码可在 GitHub 上找到。https://github.com/vshago/shedlock-demo 文章来源地址 https://www.toymoban.com/diary/apps/714.html
到此这篇关于分布式任务同步:在 Spring 中利用 ShedLock 的文章就介绍到这了, 更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持 TOY 模板网!
原文地址:https://www.toymoban.com/diary/apps/714.html
如若转载,请注明出处:如若内容造成侵权 / 违法违规 / 事实不符,请联系站长进行投诉反馈,一经查实,立即删除!