TCC

최기환·2020년 4월 23일
1

MSA

목록 보기
1/1

1. TCC?


TCC란 Try-Confirm/Cancel로, 분산된 REST 시스템들 간의 트랜잭션을 HTTP와 REST 원칙으로 접근하여 해결하는 방법이다.

2. Monolithic Architecture의 서비스


현재, 필자는 수강편람과 학생의 수강기록에 따른 시간표 생성 시스템을 구축하는 중이다. 이 시스템은 spring boot Rest api 서버를 메인으로 flask 바탕으로한 crawling서버가 있다.
(Crawling은 유저가 최초 회원가입을 할 때, 혹은 새로운 학기에 처음 로그인할 때만 진행한다.)

3. Microservice로 처리할 경우.(가정)


기존 서비스와 달리 이번에는 1인당 1번만 시간표를 생성할 수 있다고 하자.(추가로 할려면 돈을,,,,)
진행 순서는 이렇다.

  • 1단계 : 사용자가 시간표 생성을 요청한다.
  • 2단계 : 사용자에게 적용되는 수강편람(졸업요건) 데이터를 가져온다. 한 번 가져온 데이터에 대해서는 체크 한다.(체크는 데이터 삽입을 위해 + 캐싱)
  • 3단계 : 사용자의 학점 데이터를 가져온다. 한 번 가져온 데이터에 대해서는 체크 한다.
  • 4단계 : 사용자가 들었던 강의 데이터를 가져온다. 한 번 가져온 데이터에 대해서는 체크 한다.
  • 5단계 : 앞의 단계에서 호출한 데이터를 바탕으로 시간표를 생성한다.


시간표를 생성할 때, 2단계 혹은 3단계 중 하나라도 실패할 경우 의도한 데이터를 생성하여 TimeTableDB에 넣을 수 없다.
이때, 각 서비스 호출에 대해 실패할 경우, 롤백하지 않으면 일관성이 깨지고 만다. 즉, 시간표 생성 요청에 대해 트랜잭션 처리가 보장되어야 한다.

4. TCC로 처리하기


TCC는 트랜잭션 처리를 관계형데이터베이스와 비슷하게 처리한다.

RestApi 호출 한 번에 끝이 아니라, try로 위 단계를 한 번 돌고 5단계까지 진행한 후 2단계부터 confirm을 다시 요청한다.
Try 중 실패가 발생하면 Confirm 대신 cancel을 쏜다.

5. Transaction 포인트 코드로 보기


makeTimeTableService는 makeTable 메서드로 시간표를 생성한다. 이곳이 트랜잭션 포인트다.
TccRestAdapter는 TCC Rest 커뮤니케이션을 담당한다.

TccRestAdapter로 수강편람과 학생의 학점을 체크요청을 try하고 오류가 없으면 confirm을 요청한다.

@Service
public class MakeTimeTableServiceImpl implements TimeTableService {
    private TccRestAdapter tccRestAdapter;
    @Autowired
    public void setTccRestAdapter(TccRestAdapter tccRestAdapter) {
        this.tccRestAdapter = tccRestAdapter;
    }
    @Override
    public void makeTable(final Order order) {
        // 수강편람 체크(Try)
        ParticipantLink conditionParticipantLink = checkConditon(order);
        // 학생 학점 체크(Try)
        ParticipantLink creditParticipantLink = checkCredit(order);
        // ...
        // 확정(Confirm)
        tccRestAdapter.confirmAll(conditionParticipantLink.getUri(), creditParticipantLink.getUri());
    }
    private ParticipantLink checkConditon(final Order order) {
        final String requestURL = "http://localhost:8081/api/v1/condtion";
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("adjustmentType", "REDUCE");
        requestBody.put("userId", order.getUserId());
        requestBody.put("condition", order.getCondition());
        return tccRestAdapter.doTry(requestURL, requestBody);
    }
    private ParticipantLink checkCredit(final Order order) {
        final String requestURL = "http://localhost:8082/api/v1/credit";
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("userId", order.getUserId());
        requestBody.put("credit", order.getCredit());
        return tccRestAdapter.doTry(requestURL, requestBody);
    }
}
profile
개발자를 위한 개발자입니다.

0개의 댓글