목록전체 글 (317)
ecsimsw
문제 사항 PICUP은 사용자 사진, 동영상을 저장하고 읽는 스토리지다. 기존 PICUP의 파일 읽기 구조는 아래와 같다. 사용자가 WAS에 자원을 요청하면 WAS 에선 토큰을 확인해 사용자의 자원 액세스 권한을 확인하고 파일 시스템으로 실제 파일을 읽어와 반환한다. 중간 WAS 는 오롯이 권한 확인의 용도일 뿐이었다. 사용자가 파일을 요청할 때마다 WAS 는 같은 파일이라도 매번 Disk I/O 를 사용해 파일을 로드할 것이다. 메모리 캐시를 사용하자니 크기가 큰 동영상이나 이미지 파일을 올리는 데는 적합하지 않아, 근본적인 해결 방법은 안된다고 생각했다. html, js, css 나 FE의 에셋들과 같은 다른 정적 자원처럼, CDN이나 웹 서버의 캐싱을 사용해 파일 요청에 대한 WAS의 부하를 분산하..
0. 배경 PICUP 에서는 WAS 전면에 Nginx 를 두고 TLS, HTTP2.0, RateLimit, 정적 자원 호스팅 등 요청을 전처리하고 있다. 이 Nginx 의 메트릭을 모니터링하려고 한다. WAS 의 응답 시간, 요청 수뿐만 아니라, Nginx가 전면에서 처리하는 응답 시간, 요청 수, 리다이렉트 수가 궁금했다. 1. nginxlog-exporter 처음에는 Nginx가 기본적으로 제공하는 exporter 를 사용했었다. nginxinc/prometheus-exporter 에서 알 수 있듯, 해당 exporter 에서 제공하는 메트릭은 충분하지 않았고, 응답 시간을 포함한 원했던 메트릭은 대부분 Nginx plus 에서만 제공했다. nginx 의 액세스 로그에 응답 시간을 남기는 설정이 있음..
파일 삭제 롤백 불가 문제 앨범을 삭제하면 그 안에 있는 모든 사진 정보, 파일이 삭제된다. 사진 파일 다중 제거하는 시간은 오래 걸리기에 이를 비동기 처리하여 DB 정보 삭제, 사진 파일 다중 삭제 이벤트 발행만 완료하고 그 즉시 앨범 삭제 처리 완료를 응답한다. @Transactional public void deleteAlbum(Long userId, Long albumId) { var pictures = pictureRepository.findAllByAlbumId(albumId); fileService.deleteAllAsync(pictures); albumRepository.delete(album); pictureRepository.deleteAll(pictures); // 후처리 } 코드의 ..
소개 이 글은 PIC-UP 프로젝트에 데이터가 쌓였을 때 조회 성능이 어떻게 되고, 어떤 개선 포인트가 있을지 확인했던 과정을 적어보았다. DB 쿼리 빈도를 줄여 조회 성능을 개선하는 캐싱이나 DB 부하 분산은 다루지 않는다. 대신 데이터를 만드는 방법부터 DB 엔진에 넣는 데 걸리는 시간, 인덱스나 쿼리 수정 고민 과정을 적어볼 생각이다. 다루는 내용은 아래와 같다. 1. 데이터를 삽입하는 방법 / 배치 삽입과 파일 삽입 2. 쿼리 조회 성능 확인 3. 인덱스 추가 / 인덱스와 커버링 인덱스 4. 실행 계획 확인 5. OFFSET 기반 페이지네이션 문제 확인과 개선 더미 데이터 추가 유저 정보를 담는 테이블로 더미 데이터를 먼저 넣어봤다. 컬럼은 ID:BIGINT, USERNAME:VARCHAR(20)..
소개 내 첫 번째 보물은 가족사진, 두 번째는 일기장, 그리고 세 번째 보물은 티스토리 블로그이다. 자유로운 글 관리부터 백업까지, 언젠가 직접 블로그 서버를 운영하길 꿈꿨었다. 이 프로젝트에선 티스토리 글을 백업하고, 그 데이터로 직접 블로그 서버를 운영한다. 저장소 : https://github.com/ecsimsw/blog.me 배포 링크 : https://www.ecsimsw.com 기능 1. 블로그 글을 수집할 수 있다. 2. 카테고리 별 글을 확인할 수 있다. 3. 게시물 별 조회수를 확인할 수 있다. 4. 전체 혹은 날짜 별 최다 조회수 게시물을 집계 할 수 있다. 기록 1. 조회수 캐시 조회수를 메모리에 기록해 두었다가, 10초에 한번 그 기간 발생한 수를 DB에 기록한다. 게시물 별 조회..
미리 보기 핸들러의 요청 처리 속도를 제한한다. 아래 핸들러는 0.1초에 한 번으로 처리 속도가 제한되고, 5개까지 보관해 두었다가 속도에 맞춰 처리한다. 10 개의 요청을 동시에 전송했을 때 5개만 처리되고 나머지는 429 (Too Many Requests) 를 응답받는 것을 확인할 수 있다. 그리고 처리되는 5개의 요청은 속도 제한에 따라 0.1초에 하나씩 처리된다. Leaky bucket algorithm 처리 속도를 일정하게 정하여 네트워크 트래픽 체증을 제어한다. bucket 크기를 미리 지정하여 순차적으로 처리하고, 버킷 크기를 넘어선 요청은 버려진다. 즉시 처리 rate는 0.1초, 사이즈는 3 인 버킷에, 5개의 패킷이 동시에 도착하고 0.2초 후에 3개의 패킷이 이어 도착했다고 가정해 보..
대기에 DB Connection 을 점유하는 비관적 락 이전 글 에서 프로젝트에서 생긴 동시성 문제가 왜 발생했는지 소개하고 이를 해결할 수 있는 락 종류를 소개했다. 추가적인 인프라와 적은 코드 수정, 그리고 확실한 동시성 문제 처리를 원했기에 비관적 락을 선택했다. 인덱스 조건을 수정하여 사용자별 로우락을 유도해 불필요한 대기를 없앴다. 그리고 얼마 후 DB 락 대기 시간 동안 커넥션을 점유하고 있음을 로그로 확인했다. 사용자 간 독립적으로 락 처리를 했지만, 한 사용자가 락으로 모든 커넥션을 물고 있으면 결국 락이 걸린 로우와 독립적인 다른 사용자는 그 사용자를 대기해야 했다. 이 글에서는 동시성 문제를 해결하기 위해 여러 락 방식을 적용하면서 발생했던 에러 사항들과 해결 과정을 소개한다. 목차는 ..
미리 보기 컨트롤러에 @ShutDown 어노테이션을 추가하고 임시 응답을 어떻게 전달할지를 지정해주는 것으로 ShutDown 조건에서 해당 컨트롤러 아래 모든 핸들러의 임시 응답을 자동으로 생성해 준다. 위 예시에서 DailyCountRepository 타입의 빈이 존재하지 않으면 /api/counts 를 GET 요청하는 경우 아래와 같이 응답한다. HTTP status : 503, SERVICE_UNAVAILABLE Content type : application/json Message : This API is currently unavailable. 아래 사용 방법이나 버전, 기능은 현재 글을 쓰는 첫 배포 시점을 기준으로 한다. 최신 변경 사항은 https://github.com/ecsimsw/ap..