2022. 8. 14. 16:26γBackend/πΏ Spring
λͺ©μ°¨
- μλ‘
- Shedlock μ΄λ?
- λ³Έλ‘
- Shedlock μ¬μ©μ μν νλ‘μ νΈ μ€μ
- Shedlock μ μ¬μ©νμ λ / μ¬μ©νμ§ μμ λ λΉκ΅
- κ²°λ‘
- μμ½
μλ‘
2λμ λμΌν μλ² μΈμ€ν΄μ€λ₯Ό λμ΄ (Scale-out) μν©μ κ°μ ν΄λ³΄μ. μλ²μ μΌμ μ£ΌκΈ°λ‘ λ©μΌμ λ°μ‘νλ μ€μΌμ₯΄λ¬κ° μλ€. 2λμ μΈμ€ν΄μ€μ μ€μΌμ₯΄λ¬κ° λμμ μλνλ€λ©΄, λκ°μ λ©μΌμ΄ 2λ²μ© λ°μ‘λλ μν©μ΄ λ°μνλ€.
λκ°μ λ©μΌ 2λ² λ°λκ² λμλκ³ ν μ μμ§λ§, μλ²κ° 2λλ³΄λ€ λ§λ€λ©΄? λκ°μ λ©μΌμ μ¬λ¬ λ² λ°λκ²μ μ°¨μΉνλλΌλ, μλ² μ μ₯μμλ μ€λ³΅λλ μμ μ μννλ κ²μ΄κΈ° λλ¬Έμ 리μμ€ λλΉλ₯Ό μ€μ¬μΌνλ€.
Shedlock μ΄λ?
shedlock λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ©΄, λμΌν μ€μΌμ₯΄λ¬κ° μ€λ³΅ λμνλ κ²μ λ°©μ§ν μ μλ€.
곡μλ¬Έμλ₯Ό μ°Έμ‘°νλ©΄, shedlock μ μ¬μ©νλ©΄ μ€μΌμ₯΄λ¬κ° λμμ μ΅λ νλ²λ§ μ€νλλλ‘ λ³΄μ₯(scheduled tasks are executed at most once at the same time) νλ€.
ShedLock makes sure that your scheduled tasks are executed at most once at the same time. If a task is being executed on one node, it acquires a lock which prevents execution of the same task from another node (or thread). Please note, that if one task is already being executed on one node, execution on other nodes does not wait, it is simply skipped.
λ³Έλ‘
Shedlock μ¬μ©μ μν νλ‘μ νΈ μ€μ
Requirements and dependencies : shedlock μ μ¬μ©νλ €λ©΄ μλμ λ κ°μ§κ° νμνλ€.
- Java 8
- slf4j-api
build.gradle
shedlock dependency λ₯Ό μΆκ°ν΄μ£Όμ.
// shed lock
implementation 'net.javacrumbs.shedlock:shedlock-spring:4.14.0'
implementation 'net.javacrumbs.shedlock:shedlock-provider-jdbc-template:4.14.0'
shedlock Table μμ±
μλμ sql λ¬Έμ μ¬μ©ν΄ shedlock ν μ΄λΈμ μμ±νμ. ν΄λΉ ν μ΄λΈμ μ΄λ¦μ κΌ shedlock μΌλ‘ μ§μ ν΄μΌνλ€. κ·Έλ μ§ μμΌλ©΄ μλ¬ λλ€. (μ κ° κ²ͺμ΄λ΄μ . . . )
CREATE TABLE shedlock
(
name VARCHAR(64) NOT NULL COMMENT 'μ΄λ¦',
locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'μ κΈ μΌμ',
lock_until TIMESTAMP(3) NOT NULL COMMENT 'μ κΈ κΈ°κ°',
locked_by VARCHAR(255) NOT NULL COMMENT 'μ κΈ μ€νμ',
PRIMARY KEY (name)
) COMMENT 'μ€μΌμ₯΄ λ½νΉ';
Scheduler Configuration
LockProvider ν΄λμ€λ₯Ό μμ±νλ€. LockProviderλ λ°μ΄ν° μ μ₯μ(μμμ μμ±ν shedlock ν μ΄λΈ)λ₯Ό μ¬μ©νμ¬ Lockμ 보λ₯Ό μ½μ /κ°±μ νλ€. μ£Όμν μ μ shedlock μ κΈ°λ‘λ λ°μ΄ν°λ₯Ό μλμΌλ‘ λ³κ²½/μμ νλ©΄ μλλ€.
@Configuration
public class SchedulerConfiguration{
@Bean
public LockProvider lockProvider(DataSource dataSource){
return new JdbcTemplateLockProvider(
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate((dataSource)))
.usingDbTime()
.build()
);
}
}
μ¬κΈ°κΉμ§ μ λ°λΌμλ€λ©΄, scheduler μ μ μμ μΌλ‘ lock μ κ±Έ μ μλ€.
μ체μ μΌλ‘ κ°λ¨ν scheduler ν΄λμ€λ₯Ό λ§λ€μ΄ shedlock μ΄ μ μ©λμ λμ, κ·Έλ μ§ μμ λμ μ°¨μ΄λ₯Ό λΉκ΅ν΄λ³΄μ.
Shedlock μ μ¬μ©νμ λ / μ¬μ©νμ§ μμ λ λΉκ΅
μ°μ κ°λ¨ν μ€μΌμ₯΄λ¬λ₯Ό λ§λ€μ΄λ³΄μ.
@EnableScheduling
μ΄λ
Έν
μ΄μ
μ μ¬μ©ν΄ ν΄λΉ ν΄λμ€κ° μ€μΌμ₯΄λ¬ μμ λͺ
μνκ³ , @Scheduled(cron = "0 0/1 * * * ?")
μ΄λ
Έν
μ΄μ
μΌλ‘ ν΄λΉ μ€μΌμ₯΄λ¬κ° μ΄λ μ£ΌκΈ°λ‘ λμνλμ§ λͺ
μνλ€.
@Component
@RequiredArgsConstructor
@Slf4j
@EnableScheduling
public class AlarmScheduler {
@Scheduled(cron = "0 0/1 * * * ?")
public void sendAlarm(){
log.info("------------- : HOO ");
}
}
ν΄λΉ μ€μΌμ₯΄λ¬λ 맀 1λΆλ§λ€ λ‘κ·Έλ₯Ό μ°λλ€. κ°λ Ή νμ¬ μκ°μ΄ μ€ν 14μ 52λΆ 30μ΄λΌλ©΄, ν΄λΉ μ€μΌμ₯΄λ¬λ 14μ 53λΆ 00μ΄ λΆν° 맀 1λΆλ§λ€ λ‘κ·Έλ₯Ό μ°λλ€. λ§μ½ λμΌν μλ²κ° nλ μ€νμ€μ΄λΌλ©΄, 맀 λΆλ§λ€ nκ°μ κ°μ λ‘κ·Έκ° μΆλ ₯λλ€.
μ°λ¦¬λ μ¬λ¬λμ μλ²κ° μ€ν μ€μΌ λ shedlock μ μ¬μ©νμ¬, ν λμ μλ²μμλ§ μ€μΌμ₯΄λ¬κ° λμνλλ‘ ν΄λ³΄μ.
μ°μ νμλ λμΌν μλ²λ₯Ό 2κ° μ€νμμΌ μ€νν΄λ³΄κ² λ€. μΈν 리μ μ΄μμ μ¬λ¬κ°μ μ€νλ§λΆνΈ μλ²λ₯Ό μ€νμν€λ λ°©λ²μ μλλ₯Ό νμΈν΄λ³΄μ.
* μ°Έκ³ ) μΈν 리μ μ΄μμ μ€νλ§λΆνΈ μλ² μ¬λ¬κ° μ€νμν€κΈ°
1. λ½(shedlock)μ κ±Έμ§ μμ λ
@Component
@RequiredArgsConstructor
@Slf4j
@EnableScheduling
//@EnableSchedulerLock(defaultLockAtMostFor = "10s") // shedlock μ£Όμ μ²λ¦¬ -> λ½ κ±Έμ§ μλλ€.
public class AlarmScheduler {
@Scheduled(cron = "0 0/1 * * * ?")
//@SchedulerLock(name = "AlarmScheduler_scheduledTask", lockAtLeastFor = "9s", lockAtMostFor = "9s")
public void sendAlarm(){
log.info("------------- : HOO ");
...
...
}
}
@EnableSchedulerLock
μ΄λ
Έν
μ΄μ
μ μ£Όμ μ²λ¦¬νμ¬, shedlock μ λΉνμ±ν νλ€.
μ΄ κ²½μ° 2κ°μ μ€μΌμ₯΄λ¬κ° λμμ μ€νλλ©°, κ°κ°μ ν°λ―Έλμμ λ‘κ·Έκ° μ°ν κ²μ νμΈν μ μλ€.
κ°κ°μ μλ²μμ κ±°μ λμΌν μκ°μ λ‘κ·Έκ° μ°νλ€. λ§μ½ μ€μΌμ₯΄λ¬μ λΉμ¦λμ€ λ‘μ§μ΄ λ©μΌμ λ°μ‘νλ κ²μ΄μλ€λ©΄, λμΌν λ©μΌ 2κ°κ° κ±°μ λμμ λ°μ‘λ κ²μ΄λ€.
2. λ½μ κ±Έ λ
@Component
@RequiredArgsConstructor
@Slf4j
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "10s") // μ£Όμ ν΄μ -> λ½ κ±΄λ€.
public class AlarmScheduler {
@Scheduled(cron = "0 0/1 * * * ?")
@SchedulerLock(name = "AlarmScheduler_scheduledTask", lockAtLeastFor = "9s", lockAtMostFor = "9s")
public void sendAlarm(){
log.info("------------- : HOO ");
...
...
}
}
@EnableSchedulerLock
, @SchedulerLock
μ΄λ
Έν
μ΄μ
μ μΆκ°ν΄μ£Όμ.
@SchedulerLock
μ΄λ
Έν
μ΄μ
μ name, lockAtLeastFor, LockAtMostFor
μ΄λ μμ±μ΄ μλ€.
name
μ unique ν κ°μ΄κΈ° λλ¬Έμ λ€λ₯Έ μ€μΌμ₯΄λ¬μ κ²ΉμΉμ§ μκ² μ€μ νλ κ²μ΄ μ€μνλ€.
lockAtLeastFor
: μ€μ§μ μΌλ‘ lock μ΄ κ±Έλ¦¬λ μ΅μ 보μ₯λ lock μκ°
lockAtMostFor
: ν΄λΉ μ€μΌμ€λ¬ λ
Έλκ° λ€μ΄λμ λ, lock μ μΈμ κΉμ§ 보μ₯ν΄μ£Όλμ§ μ΅λ μκ°μ μ€μ νλ€.
μ μ΄λ―Έμ§μ λ‘κ·Έλ₯Ό νμΈν΄λ³΄λ©΄, 2λμ μλ²μμ μλ‘ λ²κ°μκ°λ©° lock μ΄ κ±Έλ¦¬λ κ²μ νμΈν μ μλ€. μ¦ A μλ²μμ μ€μΌμ₯΄λ¬κ° λλ€λ©΄, B μλ²μ μ€μΌμ₯΄λ¬λ λ½μ΄ κ±Έλ¦¬κ³ , λ€μ μ£ΌκΈ°μμλ B μλ²μμ μ€μΌμ₯΄λ¬λ₯Ό λμμν€κ³ , A μ€μΌμ₯΄λ¬κ° λ½μ΄ 걸리λ κ²μ΄λ€. λΌμ΄λ λ‘λΉ λ°©μμΌλ‘ λ½μ΄ 걸리λ κ² κ°μλ°, μ΄κ±΄ 곡μλ¬Έμμμ λ μ°Ύμλ΄μΌκ² λ€.
κ²°λ‘ μ μΌλ‘ shedlock λΌμ΄λΈλ¬λ¦¬λ₯Ό μ μ©νλ©΄ μ¬λ¬κ°μ μ€μΌμ₯΄λ¬κ° μ‘΄μ¬νλλΌλ, λ¨ νλλ§μ μ€μΌμ₯΄λ¬λ§ μ€ννκ³ λλ¨Έμ§ μ€μΌμ₯΄λ¬μ λμμ μ μ΄ν μ μκ² λλ€.
κ²°λ‘
νμ¬ μ 무 μ€ μ€μΌμ₯΄λ¬μ λ½μ κ±Έμ΄μΌ ν΄μ μ‘°μ¬νκ² λλ€.
shedlock μ λμ ν μ΄μ λ₯Ό μ 무μ μ°κ΄μ§μ΄ μκ°ν΄λ³΄λ©΄,
-> μ΄μνκ²½μμ μλ² μΈμ€ν΄μ€ λ€μ μ‘΄μ¬ -> μΈμ€ν΄μ€ κ°μ λ§νΌ μ€μΌμ₯΄λ¬κ° λμνλ€λ©΄, μ€λ³΅ μμ μ΄ μ§νλ μ μλ€ -> λΉμ¦λμ€ μ€λ₯
-> μ€μΌμ₯΄λ¬μ μ€λ³΅ μ΄μμ λ°©μ§νκ³ μ shedlock μ΄λΌλ λΌμ΄λΈλ¬λ¦¬ λμ .
-> μ€μΌμ₯΄λ¬κ° νμ¬ μ μ©λ μμ (μΉ΄μΉ΄μ€ν‘ μλ¦Ό λ°μ‘, μ€λλ κ°μΈμ 보 μμ )μ μ€λ³΅ μ§νμ λ§λλ€.
μ λλ‘ μμ½ν μ μλ€.