대규모 실시간 채팅의 병목 현상, 메시지 배치 전송으로 해결하기이번 글에서는 대규모 트래픽이 발생하는 실시간 채팅 서비스의 성능을 개선한 경험을 공유하고자 합니다. 가상 사용자가 늘어남에 따라 테스트 결과 병목 현상을 겪었고, 이를 해결하기 위해 메시지 전송 구조를 1:1 방식에서 서버 단위 배치(Batch) 방식으로 리팩토링한 과정을 자세히 소개해 드립니다.실시간은 100ms의 싸움현대의 웹 서비스에서 '실시간성'은 사용자 경험과 만족도를 결정하는 핵심 요소입니다. 특히 동료와의 협업 툴이나 고객 상담 챗봇 같은 서비스에서 메시지 지연이 100ms만 길어져도 사용자는 '느리다'고 느끼기 시작합니다. 저희가 개발하던 서비스는 병원과 연구소 현장에서 실시간으로 뇌 MRI 결과를 공유하고 토론하는 기능을 포..
졸업 프로젝트를 하며 참 많은 생각이 들었다.내가 개발자로서 대체되기 어려운 사람일까? 여러 논문들과 이에 기반한 화려한 용어들로 이해가 안되는 AI나 비전(특히 AI)들 사이에서 내가 임팩트를 어떻게 낼까. 혹은 AI를 하는 팀원들도 내가 하는 일에 어려움을 느낄까 하는 생각이 많았던 것 같다. 실제로 교수님 역시 AI 같은 논문에 기반한 연구에 더 높은 점수를 주실 것이 분명했기에, 백엔드 개발자를 희망하는 내가 Computer Scientist 라고 하려면 무엇을 해야할지 고민을 했다. 팀이 선정되고 주제 자체가 연구에 가까운 MRI 파일 기반 알츠하이머 진단 AI 서비스를 메인 피쳐로 들고 갔기에 할 수 있는 것이 많지는 않았다.그래도 그 주제에 연결점을 찾아서 기존에 해보고 싶었던 실시간 채팅을..
데브옵스도 아닌 제가 이런 글을 작성해도 될지? 싶기도 하고, 아직 이해하지 못한 부분도 많지만ECS를 통한 알파 환경을 구축해보며 트러블 슈팅한 내용들을 정리해 보겠습니다,사실 포기도 몇번하려 했는데, 끝끝내 스웨거 화면을 보긴 했네요. 삽질 경험을 남겨 놓는다면 이후에 조금 더 편하게 인프라를 설계할 수 있을 것 같아 글을 남깁니다.처음 도전해볼 누군가에게 이 글이 도움이 되면 더욱 좋겠네요/ 1. VPC 설정 매번 AWS 계정 생성 시 자동으로 생성되는 VPC만 사용했었는데, 이번엔 아예 10.128.0.0/16로 새롭게 생성했습니다.매번 AWS에서 제공해 주는대로 사용하다, 실질적으로 내부망을 설계 해볼 수 있었습니다. VPC는 말 그대로 논리적인 가상 개념이고, 그 아래서 실질적으로 동작하는..
진행하는 프로젝트에서 KeyCloak을 SSO로 이용하기로 결정했습니다. 외부 API와의 통신프론트에서 OAuth와 관련된 처리를 위임한 후 SSO에서 받은 AccessToken을 전달합니다.따라서 저희 백엔드에선 외부 SSO에 AccessToken을 가지고 SSO가 가진 유저 정보를 받아와야 하는 로직이 존재했습니다.@Service@Transactional(readOnly = true)class AuthService( private val keycloakFeignClient: KeycloakFeignClient,){ fun getUserInfoFromSSO(token: String): KeyCloakUserInfo { return keycloakFeignClient.getUse..
과거 프로젝트를 진행하며 Request DTO의 Int 필드에Json null 데이터가 0으로 저장된 원인에 대해 살펴보겠습니다. 버그 당시는 우선 @Min(1)을 통해 핫픽스를 진행했습니다. 단순히 String은 null이 예외처리되고, Int는 0이 된다로 소중한 경험을 마무리 짓기보다무슨 원리로 null이 0으로 변환되어 들어가게 됐는 지, RequestBody의 매핑 과정을 통해 그 이유를 찾아보겠습니다. 상황 예시당시 상황의 코드를 간략화하면 다음과 같습니다. 코틀린을 사용할 때, Body의 DTO로 자주 이용하는 Data Class를 이용해 컨트롤러를 작성했습니다. Int, String 둘 다 엘비스 연산자 (?) 가 없으므로 NotNull이 필요하지 않습니다. (하지만 이해의 편의를 위해..
본 글은 시대팅 시즌5 백엔드 개발 과정에서 발견한 동시성 문제를 AOP를 이용해 해결하게 된 과정을 담은 글입니다. 문제 상황실수로 동시 요청이 들어왔을 때, 반드시 1:1 관계여야 하는 엔티티가 1:2로 DB에 저장되는 문제 스프링 부트는 실행 시, 미리 쓰레드 풀을 생성하여 톰캣에서 Http 요청마다 하나의 쓰레드를 할당한다. 이를 통해 여러 유저의 요청을 병렬적으로 처리할 수 있다. (기본적으로 200개) 다만 이러한 스프링의 방식이 자칫 DB의 무결성을 해칠 수 있다는 것을 이번 프로젝트를 통해 알게 됐다.그리고 이런 DB의 무결성 문제는 곧 여러 로직에서 런타임 오류의 원인이 된다. 문제 코드 @Transactional override fun requestPayment( ..
기능 외 요구사항프리코스에선 미션의 요구 사항이 다음과 같다. 과제 진행 요구 사항, 기능 요구 사항, 프로그래밍 요구 사항우선 과제 진행 요구사항에서 원하는 건 1. 마구잡이로 진행하지 마라, 문제를 해결하기 위해선 기능 분리와 정리가 우선되어야 한다.2. 과제의 버전 관리와 커밋명에 신경써라 라고 느꼈다. 또한 프로그래밍 요구 사항에선 JDK21 버전 환경과 우테코의 자바 코드 컨벤션을 지키는 것을 요구했다. 기능 요구사항앞선 요구사항에 맞춰 README에 구현 기능을 정리했다. https://github.com/seogwoojin/java-calculator-7/tree/seogwoojin GitHub - seogwoojin/java-calculator-7: 석우진_프리코스 1주차 레포입니다석우..
이 글을 작성하기에 앞서 인프런의 실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화 강의 | 김영한 - 인프런김영한 | 스프링 부트와 JPA를 활용해서 API를 개발합니다. 그리고 JPA 극한의 성능 최적화 방법을 학습할 수 있습니다., 스프링 부트, 실무에서 잘 쓰고 싶다면? 복잡한 문제까지 해결하는 힘을 길www.inflearn.com다음 강의를 수강하고 작성하는 것임을 알려드립니다. 관계형 데이터베이스의 핵심 중 하나는 테이블 간의 관계를 어떻게 정의할지에 있습니다. 이러한 관계를 명확히 설계하는 것은 데이터 모델링의 중요한 부분인데요.스프링 JPA는 테이블 간의 관계를 객체 간의 관계로 자연스럽게 변환해주는 도구입니다. 이번 글에서는 1:N 관계를 중심으로 JPA에서 이를 다..