AWS EC2 Redis 분산락 구현

song yuheon·2023년 11월 5일
0

Redis

목록 보기
1/1
post-thumbnail

Redis 분산락 구현 ( AWS Server )


설치 환경


  • AWS EC2 Ubuntu
  • c5.xlarge

Redis EC2에 설치


sudo apt install lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list

sudo apt-get update
sudo apt-get install redis

Redis 설정 파일 변경


  • bind 127.0.0.1 -::1을 주석 처리하여 외부 접속 허용합니다.
  • protected-mode를 'yes'에서 'no'로 변경하여 보호 모드 비활성화합니다.

Redis 서버 재시작


sudo systemctl stop redis-server.service
sudo systemctl start redis-server.service
  • 설정 변경 후 Redis 서버 재시작합니다.

Redis 서버 정상 작동 확인


sudo systemctl status redis-server.service
  • Redis 서버가 정상적으로 작동하는지 확인합니다.

Redis 분산락 구현 ( Client )


Client 설정 ( application.properties )


# Redis
spring.redis.host = x.x.x.x
spring.redis.port = 6379

Client 설정 ( RedissonConfig )



@Configuration
public class RedissonConfig {
    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;


    private static final String REDISSON_HOST_PREFIX = "redis://";

    @Bean
    public RedissonClient redissonClient() {
        RedissonClient redisson = null;
        Config config = new Config();
        config.useSingleServer().setAddress(REDISSON_HOST_PREFIX + redisHost + ":" + redisPort);
        redisson = Redisson.create(config);
        return redisson;
    }
}

Client 설정 ( KafkaConsumerService )



@Service
@RequiredArgsConstructor
@Slf4j
public class KafkaConsumerService {
    private final UserService userService;
    private final KafkaProducerService producer;
    private final BookApplyDonationService bookApplyDonationService;
    private final RedissonClient redissonClient;

    @KafkaListener(topics = "user-event-apply-input-topic", groupId = "user-event-apply-consumer-group${GROUP_ID}",
    containerFactory = "kafkaListenerContainerFactory2")
    public void AdminUserEventApplyConsume2(String message) throws JsonProcessingException {
//        System.out.println("Received Message in group 'test-consumer-group2': " + message);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        UserEventApplyKafkaDto kafkaDto = objectMapper.readValue(message, UserEventApplyKafkaDto.class);

        RLock lock = redissonClient.getLock(String.valueOf(kafkaDto.getBookApplyDonationRequestDto().getBookId()));

        MessageKafkaDto messageKafkaDto = new MessageKafkaDto();

        try {
            if (!lock.tryLock(3, 3, TimeUnit.SECONDS)) {
//                log.info("락 획득 실패");
                throw new IllegalArgumentException("락 획득 실패");
            }
//            log.info("락 획득 성공");

            messageKafkaDto =new MessageKafkaDto(bookApplyDonationService.createBookApplyDonationKafka(kafkaDto.getBookApplyDonationRequestDto(),
                    kafkaDto.getUserId()), kafkaDto.getCorrelationId());

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            e.printStackTrace();
        } finally {
//            log.info("finally문 실행");
            if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
//                log.info("언락 실행");
            }
        }
        String jsonString = objectMapper.writeValueAsString(messageKafkaDto);
        producer.sendMessage("user-event-apply-output-topic", jsonString);
    }
}

Redis 정상 동작 확인



Redis와 서버 간의 통신이 정상적으로 동작되는 것을 확인 할 수 있습니다!!


Redis 분산락을 선택한 이유


카프카를 활용하는 다수의 서버가 존재하는 환경에서 데이터베이스 또는 애플리케이션 레벨의 락은 몇 가지 한계점을 드러냅니다.
카프카는 분산 스트리밍 플랫폼으로, 높은 처리량과 메시지 순서의 정확성을 목표로 설계되었습니다.
개별 파티션 내에서는 이러한 목표를 효과적으로 달성하지만, 다수의 파티션에 걸쳐 병렬로 처리될 때 전체 시스템의 일관성 유지는 쉽지 않은 과제가 됩니다.

데이터베이스 락은 일관성을 위해 필수적이긴 하지만 병렬 처리 환경에서 성능 저하와 시스템 복잡도의 증가라는 대가를 치르게 됩니다.
애플리케이션 레벨의 락도 코드 복잡도를 높이고, 데드락과 같은 부작용을 초래할 위험이 있습니다. 특히 분산 환경에서는 여러 인스턴스 간의 상태 동기화에 있어서 이러한 전통적인 락 방식이 한계를 보이는 경우가 많습니다.

이에 반해 레디스를 활용한 분산 락은 분산 시스템 상에서의 서비스 인스턴스 간 동기화 문제에 효과적인 해결책을 제시합니다.
레디스는 인-메모리 데이터 스토어로서, 빠른 처리 속도와 함께 대규모 트래픽을 관리할 수 있는 안정적인 성능을 자랑합니다.
이를 통해 카프카의 병렬 처리 능력을 유지하면서도 레디스의 신속한 데이터 액세스 능력과 결합해, 동시성 문제를 효과적으로 해결하고 시스템의 전반적인 성능을 최적화할 수 있는 방안을 제공합니다.


profile
backend_Devloper

0개의 댓글