![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bsld4k/btsK66tzyXy/kmGBRAGayEFjEp5qeZTa1k/img.png)
요구사항과 문제 정의공연에 대한 조회 시 조회한 공연의 조회수를 늘려주는 기능이 존재한다. 조회수를 단순히 1 늘려주는 작업이며 DB에 접근하며 수정이 진행된다.여러 트랜잭션에서 조회수 갱신 시도 시 조회수가 예상보다 적은 수치로 기록되는 동시성 문제가 발생한다. 해당 조회수는 다른 API의 조회 기능에서 사용되며, 실시간으로 반영되어야 하기에 아키텍처의 Redis INCR 연산으로 미리 계산해두어 주기적으로 DB 반영하는 방법은 고려할 수 없었다. 공연을 조회하는 API에서 조회수 갱신이 같이 수행되고 있다.현재, 조회수를 갱신하는 API에는 크게 두가지 문제점이 존재한다. 문제1: 조회수 동시성 문제여러 트랜잭션이 동시에 조회수 증가 업데이트 요청 시 조회수가 정확하지 않게 갱신될 수 있다.문제2: ..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/bBShml/btsK6850EPC/UiclKgaBHMMjIJP6rvudE1/img.png)
서버 배포와 함께 모니터링을 세팅하면서 다음과 같은 의문이 들었다.Spring Actuator가 기본으로 제공하는 메트릭으로는 파악하기 어려운 부분을 모니터링할 수 없을까? 특히나, 외부와 상호작용하거나 통신하는 부분을 모니터링하고 싶었다. 이러한 부분들에 대한 커스텀 메트릭을 만들기로 결정하였다. 다음과 같은 부분을 타겟으로 success, failure 횟수와 소요 시간을 메트릭화 하고자 한다.OpenAPIInternal API (core alarm)Redis Pub/Sub 모니터링을 위한 메트릭 추가를 횡단 관심사로 보았고, 각 메서드마다 이름을 주어 간편히 사용할 수 있도록 어노테이션과 AOP 기반으로 적용해보았다. 어노테이션, AOP 코드 예시@Target({ElementType.METHOD..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/czNYB3/btsK7aoYdoJ/7oeTwjQIGjCYR4WKdG841K/img.png)
기존 상황 및 문제 정의기존 인프라 비용이 달마다 30만원 이상이 소요되고 있었으며, 딱히 트래픽을 받지 않는 상황에서 과하게 인프라 자원을 사용 중이었다.(ecs-fargate 를 과하게 사용하고 있었다.)이러한 인프라 구성을 개편하여 비용을 줄이고 우리가 예상하는 운영 시 트래픽에 맞게 사용하고 싶었다.이를 위해 작업한 내용을 공유하고자 한다. 다음과 같은 예상되는 초기 유저 수를 고려하고 있으며, 인스턴스의 크기와 개수는 경험을 토대로 프리티어 인스턴스로 충분할 것으로 예상하여 프리티어를 초기 테스트용 인스턴스로 설정했다.예상 유저 수: 100명원하는 처리량: 50 ~ 100tps사용 중인 인스턴스: aws t2.micro (프리티어)메모리: 1GB + swap memory 2GBvCPU: 1성능 ..
아모르각코 프로젝트에 코드 리뷰어로서 참여하고 있으며, 요청을 받아 시스템 설계를 돕기로 했다.백엔드 개발자 분과 함께 고민하며 알림 시스템을 설계한 과정을 소개해보고자 한다.참고로 서비스에서 알림은 총 6가지 케이스에 발송되며 주변 모각코 생성시 알림, 모각코 참여 수락 알림 등이다. 흐름은 다음과 같다:1. 요구사항 파악2. 고려할 케이스 파악3. 기술 선택4. 데이터 흐름 설계5. 전체 아키텍처 1. 요구사항 파악지원하는 알림 종류(email, sms, app push 등) 및 지원하는 기기 종류서비스 상에서 알림 전송SMS 알림, 푸시 알림현재 클라이언트는 웹 브라우저만 지원실시간성의 수준무조건 실시간은 아니어도 되지만, 가능하면 빠르게 전송알림이 어떤 경우에 발송되는가클라이언트의 API 호출시 ..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/NWPMf/btsH9EGD9PJ/yVKmigzEF8evmRIQkfHSr1/img.png)
이길저길의 실시간 양방향 위치 공유 시스템 설계 과정에 수행한 성능테스트 결과를 공유하고자 한다.성능테스트 결과 뿐만 아니라 이전 글의 분석까지 종합하여 기술을 선정하였다. 시스템의 요구사항은 간략하게 다음과 같다:각 클라이언트는 연결이 된 시점부터 3초에 한 번 자신의 위치를 공유한다.위치 공유 대상은 사용자가 생성한 그룹의 그룹원들이며, 설계 단계의 예상 평균 그룹 인원수는 4명이다. 실시간 통신 기술들을 성능테스트 사전에 비교했던 흐름은 다음과 같다:SSE vs Short PollingSSE로 구현시 API를 총 2개를 구현하여 사용해야한다.SSE 커넥션 API자신의 위치를 전송하여 그룹원들에게 알리는 API Short Polling 에 비해 커넥션을 하나 더 가지고 있게 되어 SSE는 비효율적..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/cmcDza/btsH9JnzkPC/hTEvaDQDQAvu1mKP2R5fL1/img.png)
문제상황‘TWTW’의 테스트는 크게 Controller, Service, Repository Layer에서 진행되었다. 우리의 목표는 단위 테스트 적용이었다. 하지만 Service 테스트 코드 내에서 Repository를 통한 실제 DB 접근이 이루어져 완벽한 단위 테스트를 수행할 수 없었다. Repository Layer의 Mock 처리?Mock으로 처리할 수도 있다. 하지만 단위테스트 도중 무분별한 중복 Mock 사용이 많아졌다.또한, Mock으로는 동적인 테스트 불가로 구조 개선을 고민했다.Ex) 하나의 테스트 내에서 save한 엔티티를 조회해야 한다면 두 번의 Mock을 거쳐야 하고 동적으로 테스트가 불가하게 되며, Mock으로 시작해 Mock으로 끝나는 테스트가 되어버린다.접근 방식Reposit..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/qBPGl/btsH8kpipz9/S2XTbVXJOSGbp8uGEFHk61/img.png)
문제상황사용자 경로 제공에 있어 Kakao, Naver, Tmap Open API를 사용하였고 Open API에 장애가 발생한 경우 처리에 있어 유연한 처리가 필요함을 느낌장애가 발생하더라도 지속적으로 [OpenAPI 요청 -> 예외 발생] 이 반복되는 상황다음과 같은 부분이 가장 개선하고 싶었다.지속적으로 네트워크를 활용해 요청하는 부분어차피 데이터를 못 받아오는데, 매번 요청하여 에러를 반환할 때까지 기다리는 부분여러 OpenAPI에 의존하고 있는 이길저길 서비스에서 OpenAPI를 동적으로 호출하지 않도록 제한하면 비용을 많이 아낄 수 있을 것이라 기대했다.이러한 자잘한 문제도 있었다.DB를 같이 활용하는 API의 경우 OpenAPI 정보를 제외한 정보는 반환하고 싶은데, DB 정보까지 반환 못하는..
![](http://i1.daumcdn.net/thumb/C148x148.fwebp.q85/?fname=https://blog.kakaocdn.net/dn/boEF0S/btsH831ltR1/HPyUvt73QH8nU1KAJlVfak/img.png)
Redis Cache 성능 비교문제상황사용자에게 지명 정보, 경로를 제공하기 위해 Kakao, Naver, Tmap Open API를 사용한다. 위 API 제공에 있어 호출까지의 시간이 소요되고 비용 낭비가 발생이미 반환된 정보를 사용자가 재사용하는 경우가 많기 때문에 경로를 임시 메모리에 저장하는 로직 필요데이터 특성 상 한번 참조된 값에 대해 변경이 자주 일어나지 않음접근Redis Cache를 이용하여 Open API의 반환값을 일부 저장하여 사용자에게 제공적용@CachePut과 @Cacheable Annotation을 사용하여 API에 레디스 캐시 적용캐시 적용시 동작 흐름 @CachePut과 @Cacheable을 사용하는 API 분리 (동일 로직 수행)위와 같이 API를 분리해 구현한 이유사용자가..