Skip to end of metadata
Go to start of metadata

You are viewing an old version of this content. View the current version.

Compare with Current View Version History

Version 1 Next »

Microservices Architecture(MSA)에서 Feature 간 의존성은 독립성 원칙을 위반할 위험이 있습니다. 이 문서에서는 Notification Feature가 User Feature에 의존하는 문제를 예시로 들어, 의존성 문제와 이를 해결하기 위한 방법들을 설명합니다.


의존성 문제의 정의

Notification Feature → User Feature 의존성

com.example.notification.service.NotificationService
    ↓
com.example.notification.port.UserClientPort (Outbound Port)
    ↓
com.example.notification.adapter.UserClientAdapter (Outbound Adapter)
    ↓
com.example.user.port.UserServicePort (Inbound Port)
    ↓
com.example.user.service.UserServiceImpl (Business Logic)
    ↓
com.example.user.repository.UserRepository (JPA Repository)

문제점:

  1. 강한 결합:

    • Notification Feature가 User Feature에 강하게 결합되어, User Feature 변경 시 Notification Feature도 영향을 받습니다.

  2. MSA 독립성 원칙 위반:

    • 각 Feature는 독립적으로 배포 및 유지보수가 가능해야 하지만, 위와 같은 구조에서는 두 Feature가 독립적으로 동작하기 어렵습니다.

  3. 테스트 어려움:

    • Notification Feature를 테스트하려면 User Feature의 전체 구현이 필요할 수 있습니다.


해결 방안

1. REST API를 사용한 간접 호출

User Feature가 REST API를 제공하고, Notification Feature는 이를 호출하여 필요한 데이터를 가져옵니다. 이 접근법은 코드 의존성을 HTTP 통신으로 대체합니다.

구현 예시:

User Feature (REST API 제공):

@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping("/{userId}")
    public UserResponse getUser(@PathVariable String userId) {
        return userService.getUserById(userId);
    }
}

Notification Feature (REST Client 사용):

@Component
public class UserClientAdapter implements UserClientPort {
    private final RestTemplate restTemplate;

    public UserClientAdapter(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public UserResponse getUser(String userId) {
        return restTemplate.getForObject("http://user-service/users/" + userId, UserResponse.class);
    }
}

장점:

  • Feature 간 코드 의존성 제거.

  • 각 Feature의 독립적 배포 및 유지보수 가능.

단점:

  • REST 호출 시 네트워크 오버헤드 발생.

  • 호출 실패 시 복구 로직 필요.


2. 이벤트 기반 통신

User Feature가 사용자 데이터 변경 이벤트를 발행하고, Notification Feature가 이를 구독하여 처리합니다. 이는 비동기적으로 동작하며, 두 Feature 간 결합도를 낮춥니다.

구현 예시:

User Feature (이벤트 발행):

@Component
public class UserEventPublisher {
    private final ApplicationEventPublisher eventPublisher;

    public void publishUserEvent(UserEvent event) {
        eventPublisher.publishEvent(event);
    }
}

Notification Feature (이벤트 구독):

@Component
public class UserEventListener {
    @EventListener
    public void handleUserEvent(UserEvent event) {
        // 이벤트 데이터 처리
    }
}

장점:

  • 비동기적으로 동작하여 성능 개선 가능.

  • 두 Feature 간 직접적인 의존성 제거.

단점:

  • 이벤트 전송 지연 또는 손실 가능성.

  • 추가적인 메시징 시스템(Kafka, RabbitMQ 등) 도입 필요.

Kafka를 활용한 이벤트 기반 통신 구현 예시:

User Feature (이벤트 발행):

@Service
public class UserEventPublisher {
    private final KafkaTemplate<String, UserEvent> kafkaTemplate;

    public UserEventPublisher(KafkaTemplate<String, UserEvent> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void publishUserEvent(UserEvent event) {
        kafkaTemplate.send("user-events", event);
    }
}

Notification Feature (이벤트 구독):

@Service
@KafkaListener(topics = "user-events", groupId = "notification-group")
public class UserEventListener {

    public void handleUserEvent(UserEvent event) {
        // 이벤트 데이터 처리
        System.out.println("Received event: " + event);
    }
}

RabbitMQ를 활용한 이벤트 기반 통신 구현 예시:

User Feature (이벤트 발행):

@Service
public class UserEventPublisher {
    private final RabbitTemplate rabbitTemplate;

    public UserEventPublisher(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    public void publishUserEvent(UserEvent event) {
        rabbitTemplate.convertAndSend("userExchange", "userRoutingKey", event);
    }
}

Notification Feature (이벤트 구독):

@Service
@RabbitListener(queues = "userQueue")
public class UserEventListener {

    public void handleUserEvent(UserEvent event) {
        // 이벤트 데이터 처리
        System.out.println("Received event: " + event);
    }
}

각 해결 방안의 비교

항목

REST API 호출

이벤트 기반 통신

결합도

낮음

매우 낮음

성능

동기적 호출로 인해 네트워크 오버헤드 존재

비동기적 호출로 높은 성능 가능

복구 로직 필요성

있음

메시징 시스템 설정에 따라 다름

구현 복잡도

낮음

높음 (메시징 시스템 필요)


결론

Notification Feature와 User Feature 간 의존성 문제를 해결하기 위해 REST API 호출과 이벤트 기반 통신 두 가지 방법을 고려할 수 있습니다.

  • REST API 호출은 구현이 간단하고 동기적 처리가 필요한 경우 적합합니다.

  • 이벤트 기반 통신은 성능이 중요한 비동기 환경에 적합하며, 결합도를 최소화할 수 있습니다.

프로젝트 요구사항에 맞는 방식을 선택하거나, 상황에 따라 두 방법을 조합하여 사용할 수도 있습니다.

  • No labels