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
bind 127.0.0.1 -::1
을 주석 처리하여 외부 접속 허용합니다.protected-mode
를 'yes'에서 'no'로 변경하여 보호 모드 비활성화합니다.sudo systemctl stop redis-server.service
sudo systemctl start redis-server.service
sudo systemctl status redis-server.service
# Redis
spring.redis.host = x.x.x.x
spring.redis.port = 6379
@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;
}
}
@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와 서버 간의 통신이 정상적으로 동작되는 것을 확인 할 수 있습니다!!
카프카를 활용하는 다수의 서버가 존재하는 환경
에서 데이터베이스 또는 애플리케이션 레벨의 락은 몇 가지 한계점을 드러냅니다.
카프카는 분산 스트리밍 플랫폼으로, 높은 처리량과 메시지 순서의 정확성을 목표로 설계되었습니다.
개별 파티션 내에서는 이러한 목표를 효과적으로 달성하지만, 다수의 파티션에 걸쳐 병렬로 처리될 때 전체 시스템의 일관성 유지는 쉽지 않은 과제가 됩니다.
데이터베이스 락
은 일관성을 위해 필수적이긴 하지만 병렬 처리 환경에서 성능 저하와 시스템 복잡도의 증가라는 대가를 치르게 됩니다.
애플리케이션 레벨의 락
도 코드 복잡도를 높이고, 데드락과 같은 부작용을 초래할 위험이 있습니다. 특히 분산 환경에서는 여러 인스턴스 간의 상태 동기화에 있어서 이러한 전통적인 락 방식이 한계를 보이는 경우가 많습니다.
이에 반해 레디스를 활용한 분산 락
은 분산 시스템 상에서의 서비스 인스턴스 간 동기화 문제에 효과적인 해결책을 제시합니다.
레디스는 인-메모리 데이터 스토어로서, 빠른 처리 속도와 함께 대규모 트래픽을 관리할 수 있는 안정적인 성능을 자랑합니다.
이를 통해 카프카의 병렬 처리 능력을 유지하면서도 레디스의 신속한 데이터 액세스 능력과 결합해, 동시성 문제를 효과적으로 해결하고 시스템의 전반적인 성능을 최적화
할 수 있는 방안을 제공합니다.