[question] 동시성 이슈를 어떤 식으로 관리하고 있나요?
Closed this issue · 2 comments
질문
p.73의 시퀀스 다이어그램을 보면서, 동시성 관리 키워드가 떠올랐는데요.
여러분의 팀이나 개인 프로젝트에서 동시성 이슈를 해결했던 방식이 있으면 같이 공유해보면 좋을 것 같습니다.
연관 챕터
없음
경험이 비교적 적지만 경험해봤던 방식을 적어볼게요
-
낙관적 락을 이용한 동시성 이슈 해결 (https://kth990303.tistory.com/390)
1-1. 단, 낙관적 락을 사용했을 때 데드락이 발생할 경우 비관적 락 고려 (성능 저하 감수) -
redis 분산락 이용 (spin lock은 지양)
2-1. mysql 분산락을 이용하는 방법도 있는 듯한데, 해본 적은 없습니다...(https://techblog.woowahan.com/2631) -
ThreadLocal 변수 사용 -> 이건 아직 저는 경험이 없긴 합니다. 스프링 빈으로 관리하고 있는 service나 controller에 상태변수를 넣는 것을 최대한 지양하고 있어요.
DB 의 락 관련한 동시성 처리는 아니지만, 동시 및 분산 처리를 Akka 로 구현하고 있어 공유드립니다.
Akka 와 actor 모델에 대한 글이 많기도 하고 막상 저도 Akka 관련 코드는 눈으로 보기만 할 뿐 건들인 적은 없어서(너무 잘 짜여져 있어서 수정할 일이 없는..).. 저희 팀에서 어떻게 활용되고 있는지 정도만 공유드릴 수 있을 것 같습니다.
저희 팀은 akka 패턴 중에 scatter-gather 패턴을 사용하고 있습니다.
위 그림처럼 액터를 Scatter
, Subtask
, Gather
로 나누는 패턴입니다.
Scatter
: 요청받은 작업(MainTask)을 동시 처리 가능한 여러 SubTask
로 뿌려줍니다.
SubTask
: Scatter
가 분담해준 task 를 수행하고, 결과를 Gather
로 전송합니다.
Gather
: 각 SubTask
로부터 전달받은 결과를 합쳐서 처리합니다.
Akka 는 각 MainTask 마다 Scatter
, SubTask
, Gather
의 그룹을 매번 생성하고 관리합니다.
그룹 안에서 메시지를 전달하면 그룹 내부에서만 메시지를 주고 받겠죠. 다른 MainTask 와 겹칠 가능성을 고려하지 않아도 됩니다.
실제로 저희 코드에서도 TaskUnitGather
클래스가 var receivedCount
라는 전역 변수를 가지고 있습니다. TaskUnitGather
각각은 receivedCount
로 SubTask
의 응답 갯수를 관리할 수 있습니다.
저희 팀에서 사용 중인 Akka 동시 처리의 사용 예를 말씀드리면
저희 팀은 여러 개의 조건(true/false)을 묶은 HQL 이라는 자체 쿼리를 관리합니다. 각 조건들은 AND 들만으로 혹은 OR 들만으로 묶일 수 있습니다. (AND, OR 혼용 불가)
각 조건은 다른 서비스의 API 를 호출해야 하기 때문에 지연이 발생합니다. 만약 동시 처리를 하지 않는다면 모든 조건을 순차적으로 판단하고, 모두 판단이 끝나야 전체 HQL 에 대한 판단이 가능하겠죠.
Scatter
로 각 조건을 각각의 SubTask
로 쪼개고, SubTask
는 동시 처리되어 Gather
로 조건 판단 결과를 전송합니다.
여기서 첫 번째로 각 API 호출이 동시 처리되어 성능 이점을 얻을 수 있습니다.
또, 모든 조건은 모두가 AND 혹은 OR 로만 묶여있기 때문에, 다른 조건을 skip 할 수 있습니다.
만약 모든 조건이 AND 로 묶여있는데 가장 먼저 온 결과가 false 라면 다른 조건을 기다리지 않고 최종 결과를 false 로 반환할 수 있겠죠.
이번 기회에 Akka 코드를 자세히 훑어보게 되었는데, 확실히 각 actor 의 메시지를 따라가면서 전체 구조를 파악하기 쉽다는 느낌을 받았습니다.
여러 동시성 이슈를 Akka 가 차단하고 각각 독립적인 actor 의 로직만 살피면 되니 상당히 직관적으로 보여지더라구요.
사실 Akka 관련 자료를 보는게 더 도움이 되실꺼라 생각하지만.. Akka 의 활용 예시를 공유해보는 것도 좋을 것 같아 짧게나마 정리해 보았습니다..ㅎㅎ