모놀리식 구조에서 점점 서비스가 커지고 트래픽이 많아지게 되면 이 강결합된 구조가 문제를 일으키는 경우가 발생한다.
이벤트 기반 구조로 코드를 구성 하기 전에 트랜잭션 강결합과 약결합에 대해서 알아보자
트랜잭션 강결합(Strong Coupling)과 약결합(Loose Coupling)은 시스템이나 서비스의 의존성 수준을 나타낸다. 이 개념은 MSA, 분산 시스템, 또는 데이터베이스 트랜잭션에서 트랜잭션 경계와 서비스 간의 상호작용 방식에 따라 차이점이 있다.
우선 강결합 트랜잭션에 대해서 알아보자
📍 강결합 트랜잭션 (Strong Coupling Transaction)
강결합 트랜잭션은 두 개 이상의 컴포넌트나 서비스가 밀접하게 연결되어 있어서 한 컴포넌트, 서비스의 변경이 다른 컴포넌트, 서비스에 영향을 미치는 경우를 의미한다. 이 경우 트랜잭션 일관성을 보장하기 위해 각 컴포넌트가 같은 트랜잭션 경계 내에서 실행된다.
강결합 트랜잭션 (Strong Coupling Transaction)은 일반적으로 분산 트랜잭션(Distributed Transaction)이나 2PC (Two-Phase Commit)와 같이 동기적 트랜잭션처리 방식에서 발생한다.
강결합 트랜잭션(Strong Coupling Transaction) 의 특징으로는 일관성 보장이 쉽고 ACID 속성을 유지하기가 쉽다. 그리고 동기적으로 수행되기 때문에 하나의 트랜잭션이 완료될 때까지 모든 참여 트랜잭션이 block 상태가 된다.
일관성 보장이 쉬운 이유는 Transation 경계가 서로 공유되기 때문이다. 그리고 ACID 속성이 유지가 쉬운 이유는 하나의 트랜잭션 단위 내에서 처리가 되기 때문에 속성 자체를 유지하기가 수월하다.
우선 강결합 트랜잭션(Strong Coupling Transaction)의 장점을 보자
우선 가장 큰 장점은 데이터의 일관성이 보장된다. 그리고 모든 작업이 하나의 Transaction 내에서 이루어지기 때문에 데이터 손실이나 충돌이 방지된다. 예외 상황 발생 시 롤백이 가능해서 위에서 말한 특징 ACID 유지 중 하나인 원자성을 유지할 수 있다.
하지만 단점도 꽤 있는편이다.
Transaction 간의 변경이 발생하면 다른 Transaction들도 영향을 받고 시스템이 커지면 커질수록 이 문제가 크게 작용한다. 이러한 문제 때문에 확장성이 용이하지 못하다. 그리고 이 외에도 하나의 트랜잭션이 많은 작업을 하게 되면 네트워크 지연이나 lock이 발생하면서 퍼포먼스가 떨어지는 건 시간문제이다.
하지만 이런 강결합 트랜잭션(Strong Coupling Transaction)을 사용하는 이유는 ACID를 보장하고 데이터 일관성이 매우 중요한 서비스는 어쩔 수 없이 이러한 방식을 채택해야 한다.
대표적으로 은행에서 이체서비스를 예시로 들 수 있다. 예를 들어 하나의 계좌에서 이체하면 잔액을 감소시키는 Transaction이 있고 이체가 완료했다면 수취 계좌의 잔액을 증가시키는 Transaction이 있다고 가정을 해보자
1. A 계좌에서 100만 원이 차감되는 트랜잭션이 먼저 실행되고 성공.
2. B 계좌에 100만 원을 추가하는 트랜잭션이 실행 중 네트워크 오류 또는 데이터베이스 충돌로 인해 실패.
이 경우, A 계좌의 금액은 차감되었지만, B 계좌에는 금액이 추가되지 않아서 두 계좌 간의 데이터 불일치(Inconsistent State)가 발생한다. 결과적으로 A 계좌의 고객은 돈이 사라졌다고 생각할 수 있고, B 계좌의 고객은 돈이 들어오지 않았다고 주장할 수 있다. 그러므로 이런 동작들은 오히려 강결합으로 묶는 것이 더 안전하지 않을까?
그 외에도 모놀리틱 시스템에서 하나의 DB를 여러 서비스가 직접 연결되어 작업을 수행할 때는 이런 강결합 구조가 조금 더 적합하다.
이제 강결합 트랜잭션(Strong Coupling Transaction)을 어느 정도 알아봤으니 약결합 트랜잭션 (Loose Coupling Transaction)에 대해서 한번 알아보자
📍약결합 트랜잭션 (Loose Coupling Transaction)
약결합 트랜잭션 (Loose Coupling Transaction)은 서로 다른 서비스나 트랜잭션이 독립적으로 동작하며, 직접적인 의존성이 낮은 경우를 의미한다. 약결합은 서비스 간의 독립성을 보장하기 위해 대표적으로 비동기 방식이나 이벤트 기반 통신을 사용한다. 약결합 트랜잭션에서는 트랜잭션 일관성을 전체 시스템 수준에서 보장하지 않고, 서비스 간의 이벤트 전파를 통해 궁극적인 일관성(Eventual Consistency)을 달성한다
약결합 트랜잭션 (Loose Coupling Transaction)은 각 서비스나 트랜잭션은 독립적으로 동작하고, 트랜잭션 경계를 공유하지 않는다.
하지만 전체 시스템의 일관성은 즉시 보장 되지 않지만 점진적으로 일관성을 보장한다. 그리고 주로 비동기적 시스템 또는 이벤트 기반 통신 방식을 사용하여 결합도를 낮춘다.
약결합 트랜잭션 (Loose Coupling Transaction)은 확장성이 뛰어나고 서비스 간의 의존성이 낮은 게 장점이다. 그리고 비동기 방식으로 구현 가능 하기 때문에 시스템 성능을 높일 수 있다.
하지만 데이터 일관성이 보장이 어렵고 데이터 정합성을 맞추는 것이 어렵다. 위에서 말한 것처럼 일관성이 즉시 보장은 되지 않지만 점진적으로 보장한다. 이게 무슨 말이냐 하면 상태 추적과 보상 트랜잭션이 필요하다는 말이다. 이러한 동작이 구현되어 있어야 문제가 발생했을 때도 추적, 해결이 가능하다.
그리고 이러한 동작들이 실행되기 위해서는 복잡한 상태관리와 예외처리가 필요하다. 상태관리와 예외처리가 제대로 되어있지 않다면 오류를 역추적하기가 매우 어려워진다.
약결합 트랜잭션 (Loose CouplingTransaction)을 사용하는 환경으로는 MSA 나 Saga Pattern 환경이 있다.
최근 IT 회사들이 많이 채택하는 MSA 가 대표적인 예시이다. MSA는 서비스 간 의존성을 줄이기 위해 각 서비스가 독립적인 Transaction을 가지며, Kafka, RabbitMQ, AWS SNS/SQS 등을 통해 서비스 간의 이벤트를 비동기적으로 주고받아 트랜잭션을 처리한다.
그리고 Saga Pattern은 분산 환경에서 서비스 간 트랜잭션을 관리하기 위해 보상 트랜잭션을 사용하여 일관성을 달성하고 한 서비스의 상태가 변경되면 다른 서비스에 이벤트를 전파하여 연쇄적으로 상태를 변경하고, 예외가 발생했을 경우 보상 트랜잭션을 통해 롤백하는 방식이다.
마무리하며
다들 요즘 이벤트 기반에 대해서 관심이 많은 것 같아서 한번 정리를 해봤다. 나도 MSA 환경에서 개발을 하지만 이런 건 본인이 정리하지 않으면 누가 구축해 둔 구조를 사용만 할 줄 아는 사람이 되고 활용을 잘하지 못하게 된다. 어떤 사람은 이런 원초적인 개념을 굳이 이렇게 정리할 필요 있냐고 하지만 난 이렇게 밑바닥부터 다져가는 게 뭔가 심적으로도 편하고 개발했을 때 퀄리티도 잘 나오는 것 같다. 만약에 이런 개념이 얕은 상태로 개발을 하게 된다면 MSA로 구축해 두고 모놀리식처럼 사용하는 끔찍한 상황이 발생할 수도 있고 MSA로 전환한 의미가 없어지는 순간이 올 것이다.
그런 순간이 오지 않으려면 화려하게 개발을 하기보단 밑바닥을 점진적으로 다져가면서 성장하는 게 좋다고 생각한다.
'Dev' 카테고리의 다른 글
Apache Kafka 중복 메시지를 어떻게 방지할 것 인가 (0) | 2024.12.03 |
---|---|
Apache Kafka에 대하여 (0) | 2024.12.03 |
인증(Authentication)과 인가(Authorization) (4) | 2024.10.06 |
Hexagonal Architecture (헥사고날 아키텍쳐) (1) | 2024.09.14 |
[InteliJ] 인텔리제이 미사용 import 자동 삭제 (0) | 2022.05.28 |