시간은 종종 잘못 이해되는 이슈다. 두대의 컴퓨터가 통신하고 메세지를 교환할 때, 네트워크를 자연스럽게 신뢰하고 문제 없다고 가정한다. 그런데 만약 통신이 실패하다면? 실패를 전파(propagate)하거나 재시도(retry) 하도록 준비가 되어 있어야한다.
일반적으로 MSA 기반에서 서버 간 통신은 동기식(synchronous) HTTP 를 사용한다. 요청을 보내고 응답을 기다린 후 다음 실행을 계속한다. 동기식 호출은 추론하기 쉽다. 코드를 순차적으로 만들고 하나씩 실행시킨다. 하지만 동기식은 덜 고려되고 자주 오해를 불러일으키는 coupling 형태중 하나인 time-coupling 으로 이어진다. 여기서 파생되는 불확실성과 coupling 에 대해서 알아보자.
동기식으로 요청을 보낼 때 아래 3가지 실패가 가능하다.
1. INBOUND_REQUEST_LOSS : 호출자(caller)와 서버 사이에서 요청이 실패한다. 서버는 아무런 호출이 되지 않는다. 결국 호출자는 timeout 될 때까지 기다린다.
2. SERVICE_FAILURE: 서버는 요청을 받았지만 정확하게 처리하지 못한다. 잘못된 응답이 리턴되거나 응답 자체가 없을 수 있다. 호출자가 실패를 응답 받는게 베스트 케이스이고 그렇지 않으면 timeout 될 때까지 기다린다.
3. OUTBOUND_RESPONSE_LOSS : 서버는 요청을 받고 제대로 처리하고 응답을 보내지만 응답 도중에 실패 하거나 커넥션이 닫힌다(호출자에게 응답이 다 가기전에). INBOUND_REQUEST_LOSS 에서와 같이 일시적인 네트워크 문제이지만 서버 호출 후에 발생했다는 차이가 있다.
동기식 호출은 단순함(simplicity) 때문에 자주 사용되지만 상호작용의 분산된 특성을 숨긴다.
cf) 그런데 이 말이 잘 이해가 안간다. 원래 문장은 'This type of communication, often used because of simplicity, hides the distributed nature of the interaction.' 이렇다. distributed nature of the interaction 를 숨긴다는게 무슨뜻인지 잘 모르겠다.
동기식 호출은 서버와 네트워크 포함 모든것이 정상 작동한다는 것을 가정한다.
cf) 이 말도 공감이 안된다. 원래 문장은 'However, it makes the assumption that everything (including the services and the network) is operational. But that’s not always the case. As a caller using synchronous communication, you must gracefully handle faulty responses and the absence of response.' 이렇다. 동기 호출이든 비동기 호출이든 실패 가능성을 다 염두해두고 만들어야 하지않나?
외부 api를 호출했지만 실패했을 때 그에 대한 방어로 timeout 과 retry 를 먼저 생각할 수 있다. timeout 을 얼마로 설정할건지는 서버, 네트워크 등 다양한 요소에 따라 달라진다. retry 는 좀 더 신경쓸게 많다(원문에서는 sneaky하다고 표현). 최초 요청이 제대로 전달됐는지를 확실하게 알 수 없으므로 idempotent 할 경우만 안전하게 retry 할 수 있다. 동일한 이벤트를 여러번 처리해도 해당 이벤트를 한번만 처리하는 것과 동일한 상태와 결과가 나오는게 idempotent 한 서비스다.
스토리지를 셋팅하기 위해 고려해야될게 많다. 스토리지가 CAP theorem 에 의해 결정되기 때문이다. 필요한 특성을 이해하고 올바른 인프라를 골라야 한다. Infinispan, Hazelcast와 같은 인메모리 데이터 그리고 Apache ZooKeeper 또는 etcd와 같은 인벤토리 서비스 또 Redis와 같은 전용 데이터베이스가 있다. 그러나 모든 솔루션에는 trade-off 가 존재한다.
결국 MSA 기반에서 다양한 외부 api들을 호출할 때 시간의 영향을 이해하는게 중요하다(It’s essential to understand the impact of the time and decouple our communication). 오래걸리는 api 들을 계속 기다리지 않고 decuoupling 하는게 중요하다. 여러 서비스를 포함하는 복잡한 api 호출들은 모든 서버들과 네트워크가 계속 정상적으로 작동할거라 기대할 수 없다.
원문 : https://learning.oreilly.com/library/view/reactive-systems-in/9781492091714/
'Java' 카테고리의 다른 글
Commands and Events(Design Principles of Reactive Systems) (0) | 2021.12.22 |
---|---|
slf4j error log 포맷 (0) | 2021.11.17 |
Mono.defer (0) | 2021.11.11 |
The dark side of distributed systems (0) | 2021.11.04 |
리스트 객체를 특정 key 기준으로 grouping 그리고 merge (0) | 2021.09.20 |