모임 서비스는 이번 서비스의 핵심 서비스로 해당 서비스가 망가지면 정상적으로 서비스를 운영할 수 없음. 그렇기 때문에 가용성이 높아야 함. 1000TPS를 견디는 것을 목표로 성능 개선을 할 예정
모임 서비스 유저 권한 체크 api 테스트
쓰레드들의 수 : 1000
Ramp-up : 1초
지속시간 : 60초
상수처리량 타이머 :60000
각 스레드당 1초에 한번씩 요청 (1000TPS 테스트)
결과
TPS가 평균 903 나왔음.
이에 따라 응답 지연시간은 평균 496ms
연결 휙득 시간이 0.8초가 소요됨.
현재는 기본값으로 10개의 커넥션 풀을 사용하고 있음. 이를 늘려보고 테스트해보자.
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=15
spring.datasource.hikari.connection-timeout=30000
maximum-pool-size를 30으로 설정하면 동시에 최대 30개의 데이터베이스 연결을 사용할 수 있게 됩니다. minimum-idle을 15로 설정하면 사용량이 적을 때도 15개의 연결을 유지하므로 갑작스러운 트래픽 증가에 더 빠르게 대응할 수 있습니다.
테스트 결과
큰변화가 없었음.
가변적인 시스템 요인을 고려한다면 거의 변화없음. 1000TPS를 목표로 1초에 1000개씩 요청을 보낼때 커넥션풀을 10개에서 30개로 늘려도 큰 의미없음.
로컬에서 테스트 하는 환경이라 커넥션 풀을 30으로 고정하고 코드레벨에서 성능을 개선하는것을 더 집중해서 진행할 예정
Redis 캐시 도입
대부분의 요청 소요시간이 ConnectionPool을 기다리는데 소요되었습니다. 그렇기 때문에 DB부하를 줄이고 읽기 성능을 향상시키기위해 캐싱을 동비하였습니다.
- 관련된 모든 서비스들은 organization_service로 해당 모임의 멤버 권한, 정보, 모임 정보등 다양한 정보들을 조회하기 위해 요청을 함.
- 즉 조회 요청이 빈번하게 발생함. 이때 주어야할 데이터는 한정적이고, 매번 RDB에서 접속하여 주는것은 위에서 나타나다 시피 DB부하가 심하고 원하는 처리량을 이루어 내지 못함.
- 이를 해결하기 위해 캐시를 도입
캐시에 저장할 데이터는 다음과 같습니다. ( TrackingId는 내부적으로 pk대신 사용하는 unique값)
- OrganizationName
- OrganizationTrackingId
- UserTrackingId
- Nickname
- MemberRole
대부분의 요청들은 해당 정보들로 처리 가능합니다. ex) 권한 체크, user가 모임에 가입한 여부, 모임에 참여하는 유저 리스트등
또한 가변 데이터인 OrganizationName, Nickname, MemberRole은 조회에 비해 업데이트가 상당히 적습니다.
이러한 이유들이 종합되어 캐시를 적용하였습니다.
캐시를 적용한 후 동일한 환경에 테스트를 진행하였습니다.
오히려 처리속도가 느려졌습니다. 시스템 환경을 고려하더라도 유의미하게 감소하였기 때문에 원인을 분석하였습니다.
🚨문
DB 접근을 하지 않고 캐싱된 데이터를 가져오더라도 Connection Pool을 기다리는것이 동일하였습니다. 그렇다보니 Connection Pool을 기다리는 시간에 Reddis에 데이터를 가져오는 시간까지 합쳐져 오히려 속도가 늦쳐진 것이었습니다.
원인은 @Transactional(readOntly=true) 였습니다. 실제 DB에 접근하여 데이터를 가져오지 않더라도 해당 어노테이션이 있다면 ConnectionPool을 받아와야했습니다.
해당 Transactional을 캐시 히트시 작동하는 로직에서 제거하고 성능 측정을 다시 진행해보니 999TPS로 목적치를 달성하였습니다.(1초에 1000개 보내기 때문에 999TPS면 거의 지연이 없는것).
댓글