최신

카테고리 없음

Tomcat Thread Pool 고갈과 Coroutine, WebFlux 적용 테스트 (Spring MVC)

들어가며외부 API를 연동하다 보면 여러 네트워크 문제를 만난다. 그중에서도 외부 API 응답 시간 지연에 대응하다가 고민했던 이야기다. 어느 날 API 연동사인 A업체에서 특정 기간 동안 API timeout 60초 이상 설정 권고 메일을 받았다. 타임아웃 설정 자체는 간단하지만, 60초라는 시간이 눈에 띄었다. 하지만 "낮은 트래픽, (트랜잭션 등과 엮여 있지 않은) 단순 조회용, 특정 조건에서만 호출되는 API"였다. (Spring MVC 환경 기준) 다만 timeout 시간을 조정할 수 있었던 건 단순히 운이 좋았을 뿐이다. 트래픽이 높았다면 Tomcat Thread Pool 고갈부터 시작해 여러 문제가 발생했을 것이고, 단순 조회가 아니었다면 DB 트랜잭션 범위 분리 같은 작업도 필요했을 것이다..

회고록

확률적 도구 시대

Claude Code가 개발 워크플로우에 깊숙이 들어오면서 직접 타이핑하는 코드의 양이 줄었습니다. 요구사항을 전달하면 구조를 잡고, 코드를 짜고, PR 본문까지 작성해 주는 덕분에 효율이 높아진 것은 사실입니다. 하지만 시스템의 무결성을 책임지는 엔지니어로서, 이 도구를 실무에 적용할수록 근본적인 질문과 마주하게 되었습니다. 입력값에 따라 매번 다른 아웃풋을 뱉는 이 '확률적 도구'를 가지고, 어떻게 우리가 만드는 소프트웨어의 '결정론적 신뢰성'을 보장할 수 있을까요? 수많은 시행착오 끝에 내린 결론은 하나입니다. LLM 자체를 통제하려 들지 말고, LLM이 뱉어낸 결과를 검증하는 '외부 안전망'을 촘촘하게 짜서 최종 시스템의 정합성을 멱등하게 보장해야 한다는 점입니다. Claude Code를 사용하며..

회고록

[회고] 기대했던 2023년이 끝나고

2023년에서 가장 기억에 남는 이벤트는 단연 '우아한테크코스'이다. 수료한 지 이제 두 달이 조금 안 되었지만, 좋은 경험이었고 여러므로 많이 성장을 할 수 있었다. 2023년이 끝난 지 일주일이 넘었지만, 간단하게 회고를 하며 이 시간을 정리해보려 한다. 데브코스, 우아한테크코스 2022년 10월 말에 시작한 데브코스 3기를 2023년 2월 초까지 진행했다. 중간에 우아한테크코스 5기에 합류하게 되었고 새로운 경험을 할 기회가 생겼다. 데브코스에서 진행하던 프로젝트를 완료하고 '헤나'라는 닉네임도 추천받았다. 그리고 멘토님, 서브멘토님, 알팀원들에게 인사를 건네고 우아한테크코스에 합류했다. 우아한테크코스 첫날은 여전히 신기한 느낌이다. 2022 유스콘 오프라인 행사에 참여할 수 있게 되어 잠실 캠퍼스..

💽 데이터베이스

데이터베이스 인덱스 맛보기

🟩 랜덤 I/O와 순차 I/O 랜덤 I/O와 순차 I/O는 하드 디스크 드라이브의 원판을 돌려서 읽어야 합니다. 이때 데이터가 저장된 위치로 디스크 헤더(disk arm)를 이동시켜 데이터를 읽습니다. 순차 I/O는 디스크 헤더를 한 번만 움직이면 됩니다. 하지만 랜덤 I/O는 디스크 헤더를 데이터의 개수만큼 움직여야 합니다. 이처럼 랜덤 I/O는 읽을 데이터가 물리적으로 불연속하게 위치하기 때문에 순차 I/O에 비해서 작업에 더 큰 부하가 생깁니다. 일반적으로 쿼리를 튜닝한다는 말은 랜덤 I/O 자체를 줄여주는 것이 목적입니다. 즉, 랜덤 I/O를 줄인다는 것은 쿼리를 처리할 때 필요한 데이터만 읽도록 쿼리를 개선하는 것을 의미합니다. 디스크 성능은 얼마나 많은 데이터를 한 번에 기록하는가로 결정됩니다..

👨‍🚀 우아한테크코스 5기

레이어드 아키텍처에 패키지 구조를 개선해서 코드 생산성 높이기

🟩 레이어드 아키텍처와 팀의 선택 레이어드 아키텍처는 유사한 책임을 지닌 계층으로 구성하고 계층이 하위 계층에만 의존할 수 있도록 구성하는 패턴입니다. 각 계층에 맞는 개체를 포함시켜 높은 직관성으로 코드 생산성을 향상시킬 수 있었습니다. 프로젝트에서는 크게 4계층으로 나누기로 결정했습니다. Controller 계층 : 클라이언트의 요청, 응답을 담당 Service 계층 : 비즈니스 로직을 담당 Domain 계층 : 도메인 로직을 담당 Repository 계층 : 데이터를 담당 팀원들 모두 공통적으로 가장 이해도가 높은 구조이며 관심사를 계층별로 분리하여 유지보수가 쉬워짐을 기대했습니다. 이에 더해서 팀원들 간의 DTO의 의존 방향까지 회의를 진행했습니다. 🟩 Service는 클라이언트를 모르게 Cont..

💽 데이터베이스

Connection 생성 비용이 비싸다고? 응 비싸더라

🚀 이번 포스팅 키워드 Pooling, No Pooling Connection Pool Connection Socket 💬 포스팅 흐름 요약 No Pooling과 Pooling을 iftop 툴을 이용해서 두 실행 속도를 비교하고 있었습니다. Connection Pool을 이용하느냐 마느냐에 차이였고 Connection 생성 비용이 비싸서 그렇다는 것은 많이 들어왔습니다. 데이터베이스 서버와 연결을 미리 해놓고 계속해서 재사용하는 말을 수도 없이 들어왔지만 실제로 눈으로 확인해보지 않았으니 이번 기회를 통해서 한 번 디버깅해보면서 연결되는 부분을 찾고 그 흐름을 파악할 수 있었습니다. No Pooling Connection Pool을 사용하지 않고 요청이 들어올 때마다 새로운 Connection을 생성합니..

💽 데이터베이스

태그 자동 완성 검색 기능에 인덱스를 걸어보자

🟩 태그 검색 진행 중인 프로젝트에서 태그를 검색하는 기능이 있다. 검색 바에 'ja'를 치면 'java', 'javascript', ... 이 나오면서 사용자가 태그 자동 완성을 사용하여 편리함을 제공하고 있다. 하지만 이런 검색 기능은 생각보다 많은 비용이 발생할 수 있다. 먼저 자동 완성 기능에 나오는 태그 목록은 모두 사용자에 의해서 만들어진 태그들이다. 즉, 언제든지 새로운 태그는 만들어질 수 있고 현재는 태그가 100개, 1000개 정도의 규모라고 해도 이후에 수십만, 수백만이 생길 가능성이 있다. 사실 그정도면 검색 엔진을 도입해야하는 수준이지 않을까 싶지만 인덱스를 학습하게 되면서 인덱스를 이용해서 쿼리 비용을 절감할 수 있을 거라 생각하고 실험해보려 한다. Î tag 테이블은 id, na..

🔑 Oauth

[Oauth] AccessToken, RefreshToken 눈물의 테스트 작성기 (1 / 2)

[Oauth] AccessToken, RefreshToken 눈물의 테스트 작성기 (2 / 2) 글이 길어져서 포스팅을 두 편으로 나눴습니다. 🚀 이번 포스팅에서 알아갈 것 AccessToken Mocking Oauth 인수테스트 ✅ 테스트 진행 방식 인수테스트로 진행한다. RestAssured를 이용한다. 외부에 의존되는 부분은 Mocking 한다. 💬 상황 프로젝트를 진행하면서 Oauth2.0을 이용한 깃허브 소셜 로그인 구현을 맡게 되었다. 기능 구현에 초점을 두었고 먼저 RefreshToken 없이 AccessToken의 시간을 무려 한 달이라는 시간동안 지속되도록 했다. AccessToken을 짧게 30분, 1시간 유지되도록 할 수 있었지만 사용자가 없었던 개발 단계였기 때문에 길게 잡아도 큰 ..

👨‍🚀 우아한테크코스 5기

우아한테크코스 5기 LEVEL3 - 회고

🚀 우아한테크코스 5기 레벨3 끝 - 2023년 8월 18일 금요일 약 2개월의 시간 동안 백엔드 + 프론트엔드 프로젝트를 3번의 데모데이 + 런칭 페스티벌을 진행하고 릴리즈 할 수 있었다. 백엔드 + 프론트엔드가 하나가 되어 제대로 된 프로젝트를 진행한 게 이번이 처음이었고 그만큼 재밌었고 힘들기도 한 기간이었다. 2023년 8월 18일 금요일 '바톤(baton)'이라는 프로젝트명으로 '코드 리뷰 중개 사이트'를 런칭했다. 첫 데모데이에 발표한 기획을 갈아엎어보기도 하며 '바톤(baton)'에 3번의 데모데이와 론칭 페스티벌으로부터 잊지 못할 추억들도 생기고 그 과정에서 만나보지 못한 새로운 고민을 해결해볼 수도 있었다. 또한 개발자라는 생각만으로 단순히 다양한 기능을 구현하는데 초점을 두지 않고 '바..

😋 JPA

일단 테스트 통과시키기 (count 타입 체크, 일급 컬렉션 주소, Page.getContent())

테이블 목록 : [Runner, Supporter, RunnerPost, RunnerPostTags, SupporterRunnerPost] 시나리오 : Runner가 Supporter에게 리뷰 요청을 하기 위해 RunnerPost를 작성한다. Supporter는 RunnerPost에 리뷰 해준다고 신청할 수 있다. 이 때 Supporter가 지원한 RunnerPost 목록을 페이징하여 조회한다. 추가적으로 RunnerPost에 지원한 Supporter 수를 ApplicantCount라 부르고 이것은 테이블 컬럼에 저장되어 있지 않다. 즉, 하나의 RunnerPost에 관련된 Supporter가 몇 명이 있는지 카운트해서 찾아야 한다. 이번 포스팅은 ApplicantCount를 RunnerPost 내부에 ..

hyena0608
헤나의 블로그