이 글에서는 프로젝트를 진행하면서 간단한 방법으로 성능 개선을 수행했던 방법들을 소개하고자 합니다.
테스트 데이터는 300만개 입니다.
소프트 삭제 정책에 따른 삭제 테이블 분리하기
소프트 삭제(Soft Delete)란 데이터베이스에서 실제로 데이터를 삭제하지 않고, 대신 해당 데이터가 삭제된 것처럼 처리하는 방식입니다. 이를 위해 보통 데이터 테이블에 is_deleted와 같은 플래그(삭제 여부를 나타내는 필드)를 추가하고, 해당 값이 true로 설정된 경우에는 해당 데이터를 "삭제된" 것으로 간주합니다.
따라서 매 조회 쿼리 마다 is_deleted = false라는 조건을 추가해야 하는데, 조건을 추가한다는건 결국엔 DBMS가 추가적으로 작업을 시키게 됩니다. 모든 조회 쿼리에 이 조건을 추가하는 것은 좋지 않다고 판단했습니다.
따라서 삭제 테이블을 따로 만들어서 관리하는 방식을 채택했습니다.
단순히 모든 조회 쿼리에 조건을 추가하고싶지 않다는 아이디어에서부터 시작한 테이블 설계였습니다.
위 클래스는 Spring Data Cassandra를 사용할 때 쓴 감사 필드 클래스입니다.
삭제된 테이블을 따로 저장할 것이기 때문에, 삭제 관련 필드는 BaseEntity에서 없애고 오른쪽 사진처럼 Deleted 클래스에 추가했습니다
데이터 필터링 과정이 없어지고, 쿼리 필드 수가 줄었다.
위 사진은 isDeleted: false라는 조건을 추가한 전체 조회 쿼리 실행에 대한 mongoDB의 explain 키워드를 사용해서 쿼리 실행 계획을 나타낸 지표입니다. 일단 isCached: false이니, 캐싱을 사용하지 않았고 executionTimeMillis: 1089임을 확인할 수 있습니다.
이번엔 삭제 테이블을 분리하고 나서, 조건 없이 쿼리를 했을 때의 지표입니다.
마찬가지로 캐싱을 사용하지 않았고, executionTimeMillis: 585 ms로 약 45% 정도 성능이 개선되었다고 볼 수 있습니다.
isDeleted의 대한 인덱스를 추가하면 되지 않을까? 란 생각도 해보았는데, 그럼 데이터 삽입 때마다 인덱스를 갱신하는 작업을 하게 될 텐데, 이는 불필요한 과정이라 판단했습니다.
Projection으로 필요한 필드만 가져오기
Spring Data에서 Projection은 특정 엔티티에서 전체 데이터를 조회하지 않고 일부 필드만 선택적으로 조회할 수 있게 해주는 기능입니다. 이를 통해 불필요한 데이터를 조회하지 않고 필요한 필드만 가져와 성능을 최적화할 수 있습니다. 이 방식은 데이터 양이 많거나 특정 필드만 필요한 경우에 특히 유용합니다.
Postman으로 요청했을 때 결과입니다. Pageable의 size을 2000으로 하여 2000개의 데이터를 요청합니다. 응답 속도는 6.51s 정도가 나왔습니다.
createdAt, updatedBy 등 감사 필드는 전체 조회 때 크게 필요가 없는 필드들입니다. 이번엔 이러한 필드들을 제거하고, Projection을 적용하여 조회해 보았습니다.
감사 필드를 없애고 필요한 필드들만 가져오도록 한 조회 결과입니다. 응답 속도가 3.34s로, 약 50% 정도 빨라졌습니다.
주목할 점은 처음 테이블 분리 후 성능 평가는 DB에서, Projection에 대한 성능 평가는 Postman으로 했다는 것입니다.
왜냐하면 Projection의 성능 평가는 단순히 DB 쿼리 성능만이 아니라 네트워크 통신 비용을 함께 고려하는 것이 전체적인 시스템 성능 최적화를 평가하는 데 유리합니다.
데이터베이스에서 많은 양의 데이터를 전송할 때 네트워크 대역폭을 많이 차지하게 됩니다. 하지만 Projection을 사용하면
필요한 필드만 전송하므로 네트워크 트래픽이 감소하는 효과를 볼 수 있습니다.
종합 성능 평가
Jmeter로 100개의 스레드 수, 1초의 ramp-up 시간, 루프 카운트 1로 테스트한 결과입니다.
응답 시간이 평균만 보았을 때 약 72458ms에서 59475ms로 약 18% 개선되었습니다.
이는 곧 100개의 스레드에서 동시에 size가 2000인 페이지 조회를 요청했을 경우, 한 명이 기다려야 하는 시간이 응답 시간이 13초 정도단축된 효과를 본 셈입니다.
마치며
Projection이 DB 성능을 개선시켜 주느냐를 좀 찾아봤는데, DB 성능 개선보다는 네트워크 측면의 성능 개선이 더 주된 요인 같습니다.
왜냐하면, Projection이 있더라도 데이터베이스가 필터링할 레코드 수는 동일합니다. 즉, Projection은 데이터베이스가 특정 조건에 따라 데이터 범위를 좁히거나 쿼리 최적화를 수행하는 것이 아니므로 쿼리의 처리 속도(DBMS 내부의 처리 성능)를 직접적으로 개선하는 요인은 아닙니다. 오히려 네트워크 트래픽과 대역폭 사용량이 줄어들어, 응답 속도가 개선되고 네트워크 성능이 향상됩니다.
따라서 정말로 대용량의 데이터를 요청하는 것이 아닌 이상, Projection의 효과는 미미할 것 같습니다.
참조
'Development > Diary' 카테고리의 다른 글
[Diary] INSERT 동작에 동시성 문제 해결 일대기 (0) | 2024.11.06 |
---|---|
[Diary][Spring]GitHub Actions로 단위 테스트 환경 구성하기 (Github Service Container) (3) | 2024.10.16 |
[Diary] Apache Cassandra에서 MongoDB 전환기 (4) | 2024.10.14 |
[Diary] Domain Driven Design에서 Spring Data Repository 의존성 역전하기 (0) | 2024.10.08 |
[Diary][Spring] Spring Data Cassandra에서 @CreatedDate가 안 되는 문제 해결 (Spring Data는 이 데이터가 새 데이터인지 모른다.) (0) | 2024.09.29 |