EC2 2대(이상) 중에 리더를 선출하는 방법은 다음과 같다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.time.Instant;
import java.util.Optional;
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public String instanceId(RestTemplate restTemplate) {
String instanceId = restTemplate.getForObject("http://169.254.169.254/latest/meta-data/instance-id", String.class);
System.out.println("Instance ID: " + instanceId);
return instanceId;
}
}
@Service
public class LeaderElectionService {
private static final String LEADER_ID = "current_leader";
@Autowired
private LeaderRepository leaderRepository;
@Autowired
private String instanceId;
@Scheduled(fixedRate = 30000) // 30초마다 실행
public void electLeader() {
Instant now = Instant.now();
Optional<Leader> leader = leaderRepository.findById(LEADER_ID);
if (leader.isEmpty() || leader.get().getTimestamp().isBefore(now.minusSeconds(60))) {
Leader newLeader = new Leader();
newLeader.setId(LEADER_ID);
newLeader.setInstanceId(instanceId);
newLeader.setTimestamp(now);
leaderRepository.save(newLeader);
System.out.println("Instance " + instanceId + " is the leader.");
} else if (leader.get().getInstanceId().equals(instanceId)) {
// 자신이 리더인 경우 주기적으로 timestamp 갱신
leader.get().setTimestamp(now);
leaderRepository.save(leader.get());
System.out.println("Instance " + instanceId + " is still the leader.");
} else {
System.out.println("Instance " + instanceId + " is not the leader.");
}
}
}
리더를 저장하는 mongoDB 컬렉션은 아래와 같이 정의한다.
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import java.time.Instant;
@Document(collection = "leaderElection")
public class Leader {
@Id
private String id;
private String instanceId;
@Indexed(expireAfterSeconds = 60)
private Instant timestamp;
// getters and setters
}
그리고 main에 @EnableScheduling 이 필요하다.
@SpringBootApplication
@EnableScheduling
public class YourApplication {
public static void main(String[] args) {
SpringApplication.run(YourApplication.class, args);
}
}