전체 글

Back-end/Spring Boot

[Spring Boot] logback으로 CloudWatch에 서버 요청 로깅하기

💡 발단 앱을 런칭하기 전부터 불안한 점이 있었다. "만약 서버가 터진다면... 어떻게 해결하지?". 그래서 생각한게 로깅이었다. 로깅이 모든 문제를 해결할 수는 없겠지만, 문제를 해결하는데 필요한 결정적인 실마리를 줄 수 있다고 생각했다. 적어도 비정상적인 요청 혹은 서버내의 에러를 파악할 수 있다고 생각해서 바로 적용하게 됐다. 물론 서버에 SSH 접속해서 직접 로그를 확인하는 방법도 있다. 그래서 해당 프로젝트에선 docker를 사용해서, docker log 명령어를 사용해서 확인해왔다. 그러나 만약 서버가 죽는다면? SSH 접속 자체가 안된다면 원인을 파악할 방법이 없어지게 된다. 외부의 어딘가에 로그들을 저장해둘 필요가 있었다. 그래서 찾아본게 AWS CloudWatch. 공식적으로 로그 기능을..

프로젝트

[복쟉복쟉] 비정규화로 6초 쿼리를 105ms로 줄이기

프로젝트의 요구사항과 전반적인 맥락은 여기에 정리해놓았습니다 : 실시간으로 적재되는 데이터와 부모 엔티티 한번에 가져오기 ⚠ 발단 실시간 혼잡도 데이터가 계속해서 쌓이면서 60만개가 넘어가던 상황이었다. 앱을 켜보니 응답이 너무 오래 걸리는 상태가 지속됐고, 나중에는 아예 에러가 터졌다. 스프링의 기본 read timeout(서버의 response time에 대한 제한) 시간은 5초인데, 이를 초과한 것. 직접 쿼리를 날려봤더니... 무려 6초를 넘기고 있었다 혼잡도 데이터는 매일 몇만개씩 쌓여가고 있기 때문에, 정상적인 서비스를 위해선 빠르게 개선해야만 했다. 💡 해결 과정 : 기존 쿼리문 안에서 INDEX 사용 🤔문제 파악 기존의 쿼리에서 가장 문제가 됐던 부분은, 가장 최근의(실시간) 혼잡도를 가져..

CS/운영체제

[OS] 스터디 3주차 : CPU 스케줄링

기아 상태가 무엇인가요? : 스레드가 스케줄링 과정에서 선택되지 못한 채 오랫동안 준비 리스트에 있는 상황 우선순위를 기반으로 하는 시스템에선 높은 우선순위의 스레드가 계속 준비 리스트에 들어오면서 발생하며 실행 시간이 짧은 스레드를 우선 실행시키는 알고리즘이 사용되는 경우엔 계속 더 짧은 스레드가 준비리스트에 들어오면서 발생한다. 기아 상태를 어떻게 해결할 수 있나요? : 에이징(aging) 기법으로 해결할 수 있습니다. 에이징이란 스레드가 준비 리스트에 머무르는 시간에 비례하여 우선순위를 높여주는 기법입니다. CPU 스케줄링에 대해 설명해주세요. : 준비(Ready) 상태에 있는 스레드들 중 하나를 선택하여 CPU를 할당하는 과정입니다. CPU 스케줄링의 기본 목표는 CPU 활용률 (CPU Utili..

회고 및 성찰

[회고] 스터디를 처음 운영해보면서 생긴 시행착오와 배운 점들

💡서론 분명 컴퓨터공학과에서 공부를 하고 있는데, 채워지지 않는 부분들이 있었습니다. 개발을 하면서 지식을 응용한다는 생각이 들지 않고 별개로 느껴졌습니다. 그건 시험, 과제만을 위해서 공부했기 때문이라고 생각합니다. 휘발되지 않게 장기 기억으로 저장하고 싶었습니다. 그래서 블로그를 시작했고 소기의 목적은 달성했지만, 사람들에게 정말 지식을 공유한다고 생각하지 못해서 개인 메모장의 느낌으로 작성하게 되었습니다. 그래서 스터디를 꾸려보기로 했고 팀원을 구하기 시작했습니다. 복수전공 초기였기 때문에 당시의 유일한 소통창구는 에브리타임이었습니다. 감사하게도 생각보다 많은 학생분들이 관심을 가져주셨고 총 4명의 팀으로 시작하게 됐습니다. 🖊본론 진행 방식에 대한 고민 목표는 컴퓨터공학에서 다루는 주요 CS 지식..

Back-end/Spring Boot

[Spring JPA] 페이지네이션 일대다 FETCH JOIN 문제와 default_batch_size

💡발단 HHH90003004: firstResult/maxResults specified with collection fetch; applying in memory WARN이 반복적으로 나오는 걸 보게 됐다. 이때까지만 해도 ERROR은 아니니까 적당히 나중에 리팩토링해야겠다고 생각했다. 그러나 쿼리문을 자세히 보니 큰 문제가 있다는걸 깨달았다. 실제 쿼리를 날릴 때 limit 을 걸지 않는다. 알고보니 DB에서 모든 row를 가져온 뒤에 메모리상에 올려두고 처리하는 방식이었다. 아래는 Querydsl 코드. location_bookmark는 location에 대한 일대다 엔티티이다. location_bookmark를 레프트 조인하고 fetch join하면서 발생하는 부분이 핵심이다. public JPA..

CS/DB

[DB] MySQL EXPLAIN 쿼리 실행 계획 분석 방법

💡발단 프로젝트의 필수 구현이 마무리되고, 리팩토링을 하면서 쿼리를 최적화할 일이 생겼습니다. 경험적으로, 감으로 하기보다는 체계적으로 최적화할 방법을 고민하던중에 EXPLAIN(쿼리 실행 계획 분석)을 알게 되었습니다. 그 과정에서 EXPLAIN을 공부하게 된 내용을 서술합니다. EXPLAIN 🤔 그게 뭔데? MySQL에서는 최적의 쿼리를 실행하기 위해 각 테이블의 데이터가 어떤 분포로 저장되어 있는지를 참조하고, 해당 데이터를 기반으로 최적의 실행 계획을 수립해주는 쿼리 옵티마이저가 내부적으로 동작한다. EXPLAIN이란 여기서 MySQL 옵티마이저가 생성하는 실행 계획을 테이블(엑셀에 가까운) 형태로 볼 수 있게 하는 명령이다. 사용 방법 간단하다. SQL 앞에 EXPLAIN을 명령을 넣고 실행하면..

CS/운영체제

[OS] 스터디 2주차 : 프로세스와 스레드

프로세스에 대해 설명해주세요. : 운영체제로부터 메모리 공간을 할당 받아 실행중인 프로그램을 의미합니다. 프로세스의 특징 프로세스들은 서로 독립된 메모리 공간을 가지므로, 프로세스끼리는 임의로 서로의 영역에 접근할 수 없습니다. IPC(inter process communication)를 통해 프로세스간에 통신할 수 있다. 프로세스는 운영체제 커널에 의해 관리됩니다. 커널은 프로세스를 위해 사용자 공간에 메모리를 할당하고, 프로세스 ID를 부여하며, 프로세스 테이블을 이용하여 생성된 모든 프로세스의 정보를 관리합니다. 프로그램에 대해 설명해주세요. : 하드 디스크나 USB 등 저장장치에 저장된 실행 가능한 파일입니다. 프로세스의 메모리 공간에 대해 설명해주세요. : 프로세스는 4개의 메모리 영역으로 구성..

Back-end/Spring Boot

[Spring JPA] 엔티티 컬렉션 필드를 초기화해야 하는 이유

💡 발단 발단 부분은 Java적인 문제이고, 본론은 이 다음에 나오니 건너뛰시길 추천드립니다. 프로젝트를 진행하다가 엔티티 생성자쪽에서 에러가 발생했다. Builder 생성자에서 엔티티 컬렉션 필드를 할당하는 쪽에서 생긴 문제인데, 너무 당연하게 생각했어서 더 많은 생각을 하게 됐다. Spring 프로젝트를 2번 하는 동안 컬렉션 필드를 생성자에서 만들어본 적이 없었던 것. 상황은 이렇다. 컬렉션 필드를 addAll()로 할당하는 부분에서 NPE(Null Pointer Exception)가 발생한 것. 문제는 NULL값이 들어갈 때였다. // ... 필드 private List feedImages = new ArrayList(); @Builder private Feed(String title, Strin..

zorbathegeek
쓰기 전에 생각하자