상품의 좋아요 기능을 구현해볼려고 한다.
git: 좋아요 기능 구현
우선 좋아요를 구현해보았다. 일반적인 방법으로 요청을 하면 아무런 락이 없이 바로 DB에 데이터를 가져와 좋아요의 수를 증가하고 유저의 아이디와 상품의 아이디를 저장한다.
Jemeter를 사용해서 1000명의 사용자가 1초에 1번의 좋아요 요청을 하는 테스트를 진행 해보았다.

테스트를 해보니 정상적으로 error: 0% Throughput: 313.2/sec가 나왔다.
그럼 DB에 상품의 좋아요의 수는 1000개가 되어야한다.

보면 like의 수는 93으로 기대와다르게 1000이 아니다.
동시성의 문제가 발생한거다.
동시성 문제를 해결하기 위해서 DB락을 적용해보겠다.
비관적 락과 낙관적 락중에서 비관적락은 쓰기중에 데이터를 조회 할 수 없다. 하지만 좋아요는 조회가 빈번하게 이루어지는 데이터라 생각되어 낙관적 락을 선택하였다.
기존에는 상품 테이블에 좋아요의 컬럼이 있었지만 버전이 있는 낙관적 락을 위해서 테이블을 불리했다.
git: 낙관적 락을 사용한 동시성 문제 해결
성능을 테스트를 해본 결과

Error: 0%, Throughput: 151.9/sec가 나왔다.
낙관적락은 여러 요청이 동시에 들어올 경우, 읽기 작업은 동시에 수행되지만, 한 트랜잭션이 먼저 쓰기를 완료하면 다른 트랜잭션들은 재시도 로직을 수행하게 됩니다. 이로 인해, 1000번의 요청이 들어오면 DB에서 1000번 이상의 읽기 작업이 발생하게 됩니다.
재시도 로직을 피하려면 비관적 락이나 네임드 락을 사용할 수 있지만, 비관적 락의 경우 쓰기 작업이 완료되기 전에는 다른 요청이 읽기를 수행할 수 없는 문제가 있습니다. 좋아요 기능에서는 정확한 숫자를 실시간으로 알 필요가 없으므로, 비관적 락은 적합한 해결책이 아닙니다.
네임드 락을 사용할 경우에도 여러 마이크로 서비스가 실행 중이면 각 서비스의 트랜잭션에 별도로 락이 걸리기 때문에 동시성 문제가 여전히 발생할 수 있습니다.
결론적으로, 여러 마이크로 서비스 환경에서 쓰기 중에도 읽기 요청을 허용하려면 분산 락도 적합한 방법중 하나라고 생각됩니다.

Error: 0%, Throughput: 150.3/sec가 나왔다.
낙관적 락과 비교했을 때 성능 차이는 거의 없지만, 재시도 로직이 없고 읽기와 쓰기가 1000번씩 발생합니다.서 동일한 성능을 유지하면서도 DB I/O가 줄어들었기 때문에, 분산 락이 성능 상 이점이 크다고 생각된다.
빠른 쓰기와 읽기 속도를 제공하는 Redis를 더 활용하는 것도 좋은 선택일 수 있습니다. Redis는 단일 스레드로 작동하기 때문에 INCR 명령을 사용하여 수치를 증가시키는 경우 동시성 문제가 발생하지 않습니다. 또한, SET 명령을 활용하면 동일 사용자의 중복된 좋아요 요청을 효과적으로 차단할 수 있습니다. 이를 통해 별도의 락 없이도 동시성 문제를 해결할 수 있습니다.
단, 추가적으로 스케줄러를 활용해 일정 시간마다 하나의 애플리케이션에서 좋아요 수와 해당 사용자의 정보를 업데이트하는 로직이 필요합니다.
하지만 금융서비스의 상품의 좋아요 기능은 SNS와 달리 많이 사용되는 기능이 아니기 때문에 복잡한 구성으로 설계할 필요가 없다고 판단됩니다.
상품 마이크로 서비스는 다른 마이크로 서비스와 달리 레디스가 다운이 되어도 작동이 되도록 설정되어 있어 레디슨을 사용한 분삭락 대신 DB의 낙관적 락을 사용한 동시성 문제 해결이 적합하다고 판단된다.