TCP 데이터를 세그먼트 단위로 보내는 연결형 서비스. 속도는 느리지만 높은 신뢰도를 갖고 있다. 가상 회선 방식 사용 흐름 제어, 혼잡 제어, 오류 제어 등을 사용 높은 신뢰성 보장 UDP 보다 느림 전이중(전송이 양방향으로 일어날 수 있음), 점대점(각 연결이 정확히 2개의 종단점을 가짐) 멀티캐스팅이나 브로드캐스팅을 지원하지 않음 UDP 데이터를 데이터그램 단위로 보내는 비연결형 서비스. 속도는 빠르지만 신뢰도가 낮다. 신뢰성이 낮다. TCP 보다 빠르다. UDP는 왜 사용할까? 데이터의 신속성 연결을 위한 오버헤드가 없다. 실시간 스트리밍, DNS, HTTP 3 DNS에 UDP가 사용되는 이유 TCP가 3-way handshake를 사용하는 반면, UDP는 connection 을 유지할 필요가 없..
OSI 7계층 네트워크에서 통신이 일어나는 과정을 쉽게 파악하기 위해 계층화 시켜놓은 것 응용 : 최종 목적지, 응용프로그램과 연관하여 서비스 수행 ex) HTTP, FTP, DNS 표현 : 데이터 표현에 대한 독립성을 제공하고 암호화. 사용자 시스템에서 데이터가 올바르게 표현 ex) JPEG, MPEG 세션 : 데이터가 통신하기 위한 논리적 연결 담당 ex) API, Socket 전송 : 통신을 활성화 ex) TCP, UDP 네트워크 : 데이터를 목적지까지 전달, 라우터로 경로를 선택해 IP 지정, 경로에 따라 패킷 전달 ex) 라우터, IP 데이터링크 : 물리 계층으로 송수신되는 정보 관리, Mac 주소로 통신 ex) 브릿지, 스위치 물리 : 데이터 전송 ex) 리피터, 케이블, 허브 TCP/IP 4..
동시성 이슈가 발생할 수 있는 여러가지 상황들 동시성 이슈에 있어서는 워낙 여러가지 종류의 문제들이 있다만, 내가 지금까지 프로젝트에서 직접 경험해봤던 문제들은 다음과 같다. 재고 감소 문제 팔로우 중복 신청(더블 클릭 이슈) 교환 쌍방 제안 경험했던 이슈들에 따라서 각각 해결책도 달라졌지만, 크게 구분해보면 두 가지로 분류할 수 있을 것 같다. 이미 생성된 자원에 동시에 접근하는 경우 같은 자원을 생성하려고 동시에 시도하는 경우 구글링하면 많이 나오는 재고 감소 문제가 주로 1번에 해당한다. 여러 해결책이 많이 나오지만 주로 소개되는 건 비관락(접근하려는 row에 lock을 걸어서 다른 요청이 접근하지 못 하도록 방지)과 낙관락 (version, timestamp 등의 칼럼을 추가하여 lock을 잡지 ..
사용자가 게시글을 조회하면 조회수가 증가한다 당연한 말이다. 당연한 말을 그대로 구현하기 위해 처음엔 다음과 같이 코드를 작성했다. { // (1) DB에서 card 정보 조회 Card card = cardRepository.findActiveCardById(cardId) .orElseThrow(() -> new BaseException(ErrorCode.CARD_NOT_FOUND)); // (2) JPA dirty checking을 통한 조회수 업데이트 card.increaseViewCount(); // 응답 DTO 변환(생략) } 당연하게도 사용자가 1회 조회를 할 때, 다음과 같은 두 개의 쿼리가 날아간다. card select 쿼리 card update 쿼리 조회를 위한 메서드인데, 갱신까지 해야..
여러 건을 DB에 삽입해야 할 때 나비 장터에는 이미지들을 업로드하는 상황이 있다. 교환글 하나당 최대 10장 까지 사진을 업로드할 수 있다. 이미지 등록은 다음과 같은 과정으로 이루어진다. 이미지를 bucket에 업로드한다. 생성된 bucket image 링크를 post 요청으로 서버에 보낸다. 서버는 자체 DB에 상세 이미지 링크들을 저장한다. JPA의 saveAll은 어떻게 구현되어있을까? 한 게시글이 업로드될 때, 다수의 image url도 같이 DB에 저장되어야한다. 이 프로젝트에선 JPA를 사용하고 있기 때문에 다수의 엔티티를 저장할 때 saveAll 메서드를 호출하도록 구현했었다. { // ... 생략 ... List images = cardCreateRequestDTO.images() .s..
리스트 형태의 응답은 어떻게 내려줘야되지? 응답 데이터의 갯수가 많은 상황이 있다. 대표적으로 목록을 조회해야되는 상황이 그러한 예시이다. 친구 목록, 상품 목록, 게시글 목록 등등 여러 개의 데이터를 응답으로 내려줘야 되는 상황에서 고려할 것은 당연하게도 데이터의 크기이다. 게시글 목록을 조회하려고 서버에 요청했는데, 게시글의 수가 100만개라고 가정해보자. 한 응답에 모두 실어서 보내는 것은 불가능하다고 볼 수 있다. 따라서 여러 개의 데이터를 마치 페이지처럼 특정 단위로 몇 개씩 묶어서 반환해줘야 하고, 이것을 페이지네이션 이라 한다. 페이지 방식과 스크롤 방식 web이나 app 서비스를 이용하다 보면 목록을 조회하는 방식에는 크게 2가지가 있다는 것을 알 수 있다. 페이지 방식: 목록 맨 아래에 ..
중고거래에 맛들리기 시작했다..! 말 그대로다. 대청소를 하면서 옷장 정리를 했는데, 사 놓고 안 입는 옷이라던지, 살이 쪄서 몇 번 입어보지 못 한 옷 등등.. 버리기엔 아까운 옷들을 처분하기 위해 중고거래를 시작했다. 뭔가 나에겐 필요없어진 물건들을 갖고 밖에 나가서 돈을 얻어올 수 있다는게 무슨 게임 퀘스트 하는 것 같고 해서 재미있는 것 같다ㅋㅋㅋ 좀 애매한 상황들 하지만 중고거래를 하다보면 좀 애매한 상황들이 더러 있다. 이건 버리긴 아까운데, 잘 안 팔리네.. 저건 갖고 싶긴 한데 내가 지금 돈이 없네 ㅠㅠ 모든 물건들이 다 잘 팔리는 건 아니다. 금방 팔리는 물건들이 있는가 하면 잘 안 팔리는 물건들도 꽤 있다. 이런 친구들은 버리기도 참 아까운 경우가 있어서 아쉬운 순간들이 종종 있었다. ..
문제 상황과 원인 누군가 팔로우 신청을 걸면 팔로우 신청을 받은 사용자에게 push 알림을 보내야하는 상황이 있었다. 기존의 방식은 팔로우를 거는 메인 로직과 알림을 보내는 로직이 결합되어있어 여러 문제가 있었다. @Transactional public FriendResponseDto requestFriend(FriendRequestDto friendRequestDto, String accessToken) { /* 팔로우 신청 메인 로직 */ Authentication authentication = getAuthByAccessToken(accessToken); User to_user = userRepository.findByEmail(friendRequestDto.getEmail()) .orElseThr..
솔직히 동시성 이슈 이런건 남 일이라고 생각했습니다. 동일한 자원에 짧은 시간 간격으로 들어오는 요청 같은 건 솔직히 사용자가 아주 많은 상황에서나 발생할 거라고 생각했었다. 근데, 데모 버전 발표회 당일날 발표장에서 그런 이슈를 맞이할 거라고는 예상하지 못했다.. 더블 클릭 이슈 아주 짧은 시간 간격으로 동일한 요청이 오는 상황에서는 동시성 문제가 터질 수 있다. 다만, 간과한건 이런 문제는 사용자가 많은 상황뿐만 아니라 한 사용자가 같은 요청을 짧은 시간에 여러 번 할 때도 발생할 수 있다. 더블 클릭 이슈가 이런 예시이다. 팔로우 신청 기능에서 발생한 문제..! 발표 행사장에 네트워크 환경이 좋지 않아, 사용자들이 버튼을 연타하는 상황이 빈번했다. 사용자들끼리 팔로우 신청하는 기능이 있었는데, 이 ..
Message Queue 뒷 단에서 수행되는 task에 대해서 서버에서 어떻게 확인할 수 있을까..? 음성 합성을 위한 작업은 python 컨테이너에서 수행되므로 spring boot 서버에서 컨테이너 쪽으로 작업 메시지를 넘기면 그 작업 결과에 대해 클라이언트가 알 수가 없었다. 하지만 wav 파일 생성을 마치면 해당 wav파일을 gcs 버킷에 업로드하기 때문에, 클라이언트에서 gcs로부터 다운로드 받기 위해서는 해당 작업이 끝난 시점을 알아야만 했다. 따라서, 며칠 동안 머리를 싸맨 결과 나름의 해결책을 고안했다. 끝났는지 계속 물어보기(Polling 방식) 당최 해결법이 떠오르지 않다가, 문득 하나의 생각이 머리를 스쳤다. celery backend가 있구나? celery는 작업의 결과를 backe..