스프링

    분산 시스템에서 메시지 안전하게 다루기

    분산 시스템에서 메시지 안전하게 다루기

    채팅 시스템을 개발하던 도중 코드 리뷰를 받게 되었는데, Kafka를 통해 메시지 발행, 채팅 저장을 하나의 트랜잭션에서 실행하는 코드를 보고, Kafka를 통해 메세지 발행이 실패하여도 채팅이 저장된다는 리뷰를 받게 되었고, 이를 해결하기 위해 여러 가지 방법을 찾아보았습니다. 먼저 문제의 함수를 먼저 보겠습니다. 함수를 간단하게 설명하면 채팅방안에 사람이 있다면 message를 읽은 메세지로 처리하고 메세지를 저장하고 메세지를 발행하는 함수입니다. 메세지 발행(messageSender.send)에서 오류가 생기면 메세지를 저장하지 않고 rollback을 하게 되지만, 메세지 발행은 무사히 됐으나 Transaction commit 과정에서 오류가 생긴다면 메세지를 발행했으나 메세지 저장이 되지 않는 상..

    쿠폰 발급 동시성 제어하기, 성능테스트로 성능 개선하기

    쿠폰 발급 동시성 제어하기, 성능테스트로 성능 개선하기

    Coupon을 발행하는 파일럿 프로젝트를 진행하며 겪은 동시성 문제를 해결하는 글입니다. 우선 Coupon을 발행하는 코드입니다. 플로우를 간단하게 살펴보면 사용자가 Coupon을 받을 수 있는지 없는지 체크 한 후 Coupon을 받을 수 있다면 Coupon 발부에 성공하게 됩니다. 동시에 여러명이 Coupon을 발급하였을 때, 정확한 Coupon 개수만큼 발급하는지에 대한 테스트 코드를 작성해보겠습니다. 동시에 Coupon을 발행하게 되면 테스트는 실패한다. 왜 실패할까? 로그를 살펴보자 위 로그를 보면 Lock을 얻는 과정에서 Deadlock이 생긴다고 한다. Lock은 언제 얻을까? 답은 Mysql 연관관계에 있다. 외래 키 계약조건이 있는 테이블에 삽입, 삭제, 갱신을 할 때 제약조건을 위반하는지..

    스케줄러와 Transactional 테스트 코드에서 생긴 문제 해결하기

    스케줄러와 Transactional 테스트 코드에서 생긴 문제 해결하기

    프로젝트 진행 중 상세페이지 한 명이 상세 페이지를 조회 시 조회수를 Update 처리해줘야 하는 과정을 구현하며 겪은 문제들에 대해 얘기해 보겠습니다.저는 상세 페이지를 조회할 때마다 DB에 Update Query를 날려 조회수를 업데이트해주고 있었습니다.문제점하지만 이렇게 상세페이지를 조회할 때마다 DB에 Update쿼리를 날리게 되면 DB에 부하가 증가하고, 또한 Lock으로 인해 성능저하가 생길 수 있습니다. 해결책프로젝트에서 조회수가 아주 중요한 정보는 아니라고 생각하여 Redis에 조회수를 저장한 후 Scheduler를 통해 DB에 Update 하여 저장하기로 하였습니다.이렇게 한 이유는 DB에 Update쿼리를 조회할 때마다 날리지 않아도 되어 성능상 이득을 취할 수 있다고 생각하였기 때문입..

    Spring WebSocket Ping / Pong

    Spring WebSocket Ping / Pong

    채팅 프로젝트를 진행하던 도중 WebSocket Session을 효율적으로 관리하려면 어떻게 해야할까? 에 대한 질문을 공부하며 이를 코드로 작성하였고 본 포스팅을 작성하게 되었습니다. 서버와 사용자가 WebSocket 연결이 되어있을 때, 사용자가 정상적으로 연결을 끊는다면 서버도 이를 파악하고 정상적으로 사용자와의 연결을 끊을 수 있습니다. 하지만 사용자 측에서 비정상적으로 연결이 끊긴다면 서버가 사용자가 연결이 되어있는지 안되어있는지 판단하지 못해 연결되어 있다고 판단할 수 있습니다. 이번 포스트에선 이를 보완하기 위해 서버와 사용자의 WebSocket 연결이 의도치 않게 끊겼을 때, Ping / Pong 으로 서버가 사용자와의 WebSocket 연결 상태를 확인하는 코드를 작성해 보겠습니다. Pi..

    WAS, Servlet 용어 정리

    WAS, Servlet 용어 정리

    백앤드 공부를 하던 도중 서버와 관련된 헷갈리는 용어가 많아 이번기회에 정리하려 한다. 0. 웹서버 등장 배경 초창기엔 정적 웹사이트만 존재하여 모든 페이지의 모든 내용이 정해져 있어 사용자의 요구를 맞출 수 없었다. 이에 대해 동적인 웹사이트가 등장하였고, 이때 등장한 것이 CGI(Common Gateway Interface)였다. CGI는 서버에서 수행 중인 프로세스 사이에 정보를 주고받는 규칙을 의미했다. CGI는 Perl, C, C++ 등의 언어를 지원하면서 웹 서버를 통해 요청을 받고 실행 결과를 다시 웹 서버를 거쳐 클라이언트의 브라우저로 보낼 수 있는 기능을 지닌다. 하지만 CGI는 각각의 클라이언트의 요청에 대해서 독립적인 별도의 프로세스가 생성하기 때문에 , 프로세스가 많아질수록 시스템에..

    Controller , Service , Repository 이해하기

    스프링은 하나의 Layer가 여러가지 하는 일을 좋아하지 않는다. 따라서 각자 하나의 layer는 한 가지 일을 해야한다. layer의 역할과 특징을 간단히 적어보면 이렇다. controller (web) 외부 요청과 응답에 대한 영역 요청 url에 따라 view, mapping 처리 @Autowired Service를 통해 service의 method를 이용 ResponseEntity(DTO)를 body에 담아 Client에 반환 ( Object type 일 경우 엔 ResponseController 를 사용해도 된다. ) Service Controller 과 Repository 사이에 존재 @Service Annotation 사용 @Autowired Repository를 통해 repository의 m..