Java
[My-Storage] 재귀 호출에서 발생할 수 있는 데드락
부하 테스트를 진행하며 위와 같이 서버가 죽어버리는 상황이 발생했다.처음에는 죽었는지 몰라서 DB가 처리를 너무 늦게 하나..?라는 생각을 했었다. 사실 120초라서 말이 안되긴 하지만..DB에는 문제가 없었고,다른 요청을 보내 봤는데, 요청 자체를 처리하지 못하는 것을 볼 수 있었다.힙이 가득 차서 뭔가 처리를 못하고 있나..? 그래서 GC가 계속 돌아가는데 아무것도 지우지 못해서 처리를 못하나..?라는 생각에 확인해 보았다.너무 멀쩡했다!혹시 소켓 수준에서 문제가 있나?라는 생각에 소켓 상태도 확인해 보았다.소켓 상태를 보면 08인 상태들이 대부분이었다. 이건 CLOSE_WAIT을 의미한다.부하테스트가 끝났기에 클라이언트가 연결을 종료했고, 서버는 처리중인 어떠한 작업을 완료하기 전에 CLOSE_WA..
[My-Storage] 폴더 이동 로직에서 사용한 분산락 작업 개선
이전 로직의 문제점기존 폴더 이동은 각각의 root 폴더의 ID 값을 기준으로 락을 획득하고 이동 작업을 진행했다. 그러다 보니 한 번에 하나의 이동 작업만 처리할 수 있었고, 동시에 여러 이동 작업을 처리할 수 없었다.이렇게 했던 이유는 폴더의 순환 구조를 막기 위함이었다. 최근 더 나은 방법이 생각나서 변경하고 테스트를 진행해 보았다. 아이디어이동 작업이 발생한 폴더의 ID를 기준으로 락을 요청한다. 락 획득이 가능하면 획득 후, 해당 폴더를 기준으로 상위로 탐색하며 탐색한 폴더의 ID를 기준으로 락이 걸려 있는지 확인한다. 만약 락이 걸려 있다면 나보다 먼저 이동 작업이 진행 중인 폴더가 존재한다는 것이다. 이 경우 획득한 락을 해제하고 이동 작업에 실패한다. 즉, 현재 이동 작업이 진행 중인 폴더..
[My-Storage 개선하기] Ceph에 파일 저장하기
이전에 간단하게 ceph 클러스터를 구성했으니 spring 서버를 통해 파일을 업로드해 보자.build.gradleimplementation platform('software.amazon.awssdk:bom:2.20.56')implementation 'software.amazon.awssdk:s3' // 필요한 모듈만 추가awssdk를 사용했다. s3 API를 사용하여 RGW에 요청을 보낼 것이기 때문에 s3도 추가했다.RgwConfigurationpackage com.woowacamp.storage.global.config;import java.net.URI;import org.springframework.beans.factory.annotation.Value;import org.springframew..
[My-Storage 개선하기] 로컬 환경에서 Docker로 Ceph 설치하기
현재 파일 처리의 문제점현재 서버는 파일을 직접 처리한다. 즉, InputStream으로 데이터를 읽고, OutputStream으로 쓰고 있다. 그냥 봤을 땐 문제가 없어 보이지만, 사용자의 요청이 증가하면 문제가 발생한다. 트래픽이 문제라면 그냥 서버를 다중화하면 되는 게 아닌가?라고 생각할 수 있다. 하지만, Spring 서버는 파일 처리만 하는 것이 아니라 다른 API에 대한 요청도 처리해야 한다. 이때 모든 스레드가 파일 처리를 하고 있으면 파일 업로드가 완료될 때까지 다른 요청들은 처리할 수 없게 되는 문제가 발생한다. 어떤 API의 요청이 0.1초 만에 끝나도 파일 업로드를 위해 스레드가 10초 동안 사용하지 못한다면 결국 간단한 요청도 오래 기다리거나 timeout이 발생하게 된다. 위 문제..
[My-Storage 개선하기] 데드락 해결, DB lock 사용 줄이기(2) - 테스트
테스트 환경 설정DB, Redis, Spring 모두 별도의 환경에서 테스트를 하고자 했다. 개선 전의 서버와 비교를 하려면 동일한 환경을 보장하는 것이 중요하다고 생각했기 때문이다. 서버를 살 돈은 없었기에 로컬에서 도커를 사용해서 컨테이너 환경에서 cpu와 메모리를 제한했다.Dockerfile# 1. 빌드 단계: Gradle 이미지 사용FROM gradle:7.6-jdk17 AS build# 2. 작업 디렉토리 설정WORKDIR /app# 3. 필요한 파일 복사COPY --chown=gradle:gradle . .# 4. Gradle을 사용해 JAR 파일 빌드RUN gradle clean build --no-daemon --stacktrace || (echo "Build failed. Check bu..

[My-Storage 개선하기] 데드락 해결, DB lock 사용 줄이기(1)
현재 프로젝트의 문제점현재 폴더의 이동이나 삭제 시 하위 폴더와 상위 폴더를 탐색하여 전부 락을 건 후에 작업을 진행한다.삭제의 경우 하위 폴더와 파일까지 모두 탐색하여 일관성 있게 제거하기 위함이고, 위로 거는 락은 이동과 삭제 시 용량 계산을 일관성 있게 하기 위함이다. 위 방법의 가장 큰 문제는 수정을 위해 Read Lock을 사용하면서 읽기 작업에도 영향을 미치게 된다는 점이다. 또한 전부 탐색을 진행한 후에 작업을 처리하기 때문에 커넥션을 길게 소유하게 되고, 동일한 DB를 사용하는 다른 서비스에도 영향을 미칠 수 있다. 또 다른 문제로는 락을 획득하는 과정이 한 방향이 아니라 위, 아래 두 방향으로 데드락이 발생하는 문제도 있었다. 고민그래서 이 모든 문제의 원인인 락을 사용하지 않고 일관성을..
[우아한 테크 캠프 팀 프로젝트] 파일 이동 및 삭제 My-Storage(3)
다음은 파일 이동과 삭제에 대한 내용이다. 데이터 무결성에 과하게 집중했는데, 시간이 지나서 문제가 될 수 있음을 깨달았다. 당시에는 도메인 지식이 부족해서 더 폭넓게 생각하지 못한 것 같아 아쉬움이 있는 부분이다. 당시 구현할 때, 파일 이동과 삭제에 있어서 중요한 것은 폴더의 하위 파일 및 폴더들이 동시에 이동하고 삭제되어야 한다는 부분에 집중했다. 현재 DB 상에 구현된 파일 트리 구조는 pk를 기반으로 parent를 찾아가기 때문에 이동의 경우 해당 파일이나 폴더의 Parent ID 값만 바꿔주면 됐다. 삭제의 경우 하위 파일들을 모두 찾아서 한 번에 삭제해야 했다. 이때 락을 걸지 않으면, 삭제 중인 폴더에 어떤 파일을 추가할 수 있고, 타이밍이 맞지 않아서 새로 추가된 파일은 삭제되지 않는 문..
[우아한 테크 캠프 팀 프로젝트]동기 처리 vs 비동기 처리, 비동기 처리에서 발생한 OOM 문제 My-Storage(2)
내가 학습한 CS를 바탕으로 비동기가 더 적절하다고 가정하고 파일 업로드 기능을 구현했다. 그리고 파일 쓰기 작업을 비동기 처리하며 순차적으로 쓰고, 정확히 잘 써졌는지 확인하는 다른 작업들이 추가되었다. 이론적으론 비동기가 리소스를 많이 사용하더라도 결국 I/O 작업이 가장 오래 걸리기 때문에 동기 처리보다 빨라야 할 것이다. 그래서 두 방식을 직접 비교하는 테스트를 진행했다. 사실 테스트는 가장 마지막에 했지만, 정리하는 글이니까 순서상 먼저 정리하려고 한다. 그 과정에서 여러 문제를 만나고 나름 해결했지만 그건 뒤에서 다시 정리하고 여기선 단순히 비교한 결과를 정리한다.테스트 환경우선 사용한 t3 micro 인스턴스는 대역폭이 5Gbps라서 부하를 주었을 때 서버 처리 속도가 더 빨라서 정확한 비교..