Moment 개발 지식

이동규·2023년 7월 2일

#1. 즉시 로딩과 지연 로딩

  • 1) fetch 란

    • 사전적 의미 : ‘'(어디를 가서) ~을 가지고 오다’ → JPA에서도 같은 의미로 Fetch는 엔티티의 필드에 DB에서 실제 값을 가져오는 것이다.
  • 2) 차이점

    • EAGER : 즉시 로딩으로 단어의 의미와 같이 예를 들어 User 엔티티에 OneToMany 관계로 Board가 설정되어 있으면, User 조회 시 연관된 모든 Board 데이터들도 가져오는 것이다. 이렇게 가져오게 되면 모든 연관된 Board 데이터들은 영속성 컨텍스트에 등록되고 관리된다.
      • 문제점 : 만약, User의 nickName만 조회할 부분인데 EAGER을 쓰게 되면?? → 필요없는 쿼리를 발생시키고 메모리만 차지하게 되는 낭비가 발생
    • LAZY : 지연 로딩으로 자원이 실제로 쓰일 때까지는 요청하지 않고 있다가 실제로 필요할 때 요청하여 최대한 요청을 미루는 방식이다.
      • 이렇게 설계를 하게 되면 필요없는 데이터를 메모리에 넣고 있을 필요 없이 연관 데이터가 필요한 순간에 쿼리를 발생 시킨다.
      • JPA에서는 LAZY 방식을 프록시 패턴으로 설계되어 있다.
        • 프록시 패턴 : 어떤 객체에 대한 접근을 제어하는 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴
      • FetchType이 Lazy로 설정되었다면 프록시를 먼저 넣어 놓은 뒤 실제로 요청할 때 값을 가져온다는 것이다.
  • JPA 기본값

    • ToMany → LAZY Loading
    • ToOne → EAGER Loading
    • JPA의 ToOne에 해당하는 Fetch 타입은 Eager이다. 그렇기 때문에 ToOne인 매핑은 가능한 전부 LAZY로 설정하는 것을 권장
  • 로딩 과정에서 문제점

    • N+1 문제
      • LAZY로 설정 후, 값을 가져오는 과정에서 문제가 발생한다.
        • N+1
          • ToMany 인 경우 1개 쿼리만 요청했는데 N만큼 쿼리가 추가로 발생하는 문제

            → JPQL 객체 지향 쿼리 언어로 해결 가능

    • LazyInitializationException
      • 프로그램이 기동되면 각 엔티티들이 초기화되는데 LAZY 모드일 때 프록시 객체가 들어가 있다. 이때, 초기화 할 때는 EntityManager를 통해 프록시 객체를 넣어두었지만 초기화가 끝나면 그때는 EntityManager와의 연결이 끊어진 (준영속)상태이다. 즉, 초기화한 상태에서 EntityManager를 통해 연결하지 않은 상태로 프록시를 건드리게 되면 프록시 객체는 진짜 값들을 가져올 수 없는 상태에 놓이고 이때 LazyInitializationException이 발생한다.
        • 이때, EntityManager를 연결해 놓은 상태로 두면 되지 않나? 라고 생각할 수 있지만, 이는 모든 매핑된 값들이 연결된 상태가 되어 버린다. 즉, 트랜잭션이 계속 유지되고 있어 DB의 동시성 성능에 치명적인 영향을 주고 메모리를 차지하게 되므로 매우 비효율적으로 동작하게 된다.
      • 해결 방법
        • EAGER 사용?? 현재 프로젝트에서는 이렇게 사용하여 고쳐볼려 했지만 이치상 맞지 않음
        • @Transactional 사용?
          • 메서드에 이 어노테이션을 적용하면 해당 메서드가 수행되는 동안은 세션이 계속 유지된다.
          • @Transactional을 사용하면 해당 메서드의 시작부터 끝까지 트랜잭션이 유지되어 위 예외가 발생하지 않는다. 그리고 메서드 수행 중 다른 @Transactional을 만나면 기본 전략으로 트랜잭션이 합쳐진다.
          • 이 방법이 가장 간편하지만 동작이 복잡해질 경우 성능적으로 좋지 않다!!
            • 이유
              • 트랜잭션 내에서 데이터베이스 작업이 많이 실행되거나 오랜 시간이 소요되는 경우, 트랜잭션의 일관성을 유지하기 위해 데이터베이스 리소스가 장기간 점유될 수 있음 → 다른 트랜잭션들의 처리를 지연시키고 전체적인 성능을 저하시킴
              • lock 충돌이 발생할 수 있음
                • 트랜잭션이 사용되는 동안 해당 데이터에 대한 락이 유지 So, 동시에 여러 개의 트랜잭션이 동일한 데이터를 수정하려고 할 때 락 충돌이 발생할 수 있음 → 이는 동시성 접근을 제한하고 대기 시간이 늘어나 성능에 영향을 줄 수 있음
        • JPQL?
          • JPQL의 JOIN FETCH를 사용하면 된다.
        • 엔티티 그래프?
          • 엔티티 그래프는 엔티티를 조회하는 시점에 연관된 엔티티를 함께 조회하는 기능이다.
          • 가져온 후, 영속성 컨텍스트에 등록되어 있으면 다음부터는 엔티티 그래프는 적용되지 않는다.
  • Transaction

    • DB의 데이터를 수정하는 도중 예외가 발생할 경우 수정되기 전으로 롤백하기 위해 사용
    • 더 이상 쪼갤 수 없는 최소 작업 단위
    • Spring 트랜잭션
      • 사용하는 이유 : 트랜잭션을 쓰는 이유는 데이터 무결성(integrity) 때문
      • 동기화
        • JDBC를 이용하는 개발자가 직접 여러 개의 작업을 하나의 트랜잭션으로 관리하려면 Connection 객체를 공유하는 등 상당히 불필요한 작업들이 많이 생길 것 → 이를 해결하기 위한 방법
          • 해결 방안 : 트랜잭션을 시작하기 위한 Connection 객체를 특별한 저장소에 보관해두고 필요할 때 꺼내쓸 수 있도록 하는 기술
          • 하지만 개발자가 JDBC가 아닌 Hibernate와 같은 기술을 쓴다면 위의 JDBC 종속적인 트랜잭션 동기화 코드들은 문제를 유발
            • Hibernate?
              • JPA라는 명세의 구현체 → JPA는 기술 스펙이고 하이버네이트는 이 기능을 구현하여 공급해주는 역할
              • 자바 환경에서의 객체-관계 모델 매핑 솔루션
                • orm이라 불리우는 객체-관계 매핑은 어플리케이션레벨의 도메인 객체를 관계형 데이터베이스 테이블의 형태로 혹은 역으로 매핑시켜주는 프로그래밍 기술
      • 추상화
        • 애플리케이션에 각 기술마다(JDBC, JPA, Hibernate 등) 종속적인 코드를 이용하지 않고도 일관되게 트랜잭션을 처리할 수 있도록 해줌
      • AOP를 이용한 트랜잭션 분리
        • 트랜잭션 코드와 비지니스 로직 코드가 복잡하게 얽혀있는 코드는 분리하는 것이 좋지만, 거의 불가능하다.
          • Spring에서는 마치 트랜잭션 코드와 같은 부가 기능 코드가 존재하지 않는 것 처럼 보이기 위해 해당 로직을 클래스 밖으로 빼내서 별도의 모듈로 만드는 AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)를 고안 및 적용하게 되었고, 이를 적용한 트랜잭션 어노테이션(@Transactional)을 지원하게 됨.
  • 3) hard delete와 soft delete
    • hard delete
      • SQL의 DELETE 명령어를 사용하여 직접 데이터를 삭제하는 방법
        • 삭제 대상인 데이터가 필요 없을 때 (추후에 조회할 필요가 없을 때!!) 사용
    • soft delete
      • SQL의 UPDATE 명령어를 사용하여 삭제 여부를 알 수 있는 컬럼에 데이터가 삭제되었다는 값을 넣어서 표현
        • 삭제를 해도 삭제하기 전의 데이터를 보관해야 할 경우에 논리 삭제를 사용
    • hard delete가 안좋은 이유
      • 쿼리를 요청할 때, delete 요청은 다른 요청에 비해 비용이 훨씬 많이 듬. → Delete 쿼리는 데이터의 물리적인 삭제 작업과 함께 인덱스 갱신, 락 충돌, 트랜잭션 로그 등의 추가 작업을 수행해야 하므로 비용이 많이 들게됨.

#2. jpql과 쿼리dsl 차이점

  • 1) 차이점
    • JPQL : JPA의 일부로 Query를 Table이 아닌 객체(=엔티티) 기준으로 작성하는 객체지향 쿼리 언어라고 정의할 수 있음
      • 문제점
        • String 형태이기 때문에 개발자 의존적이다.
        • Compile 단계에서 Type-check 불가능
        • Runtime 단계에서 오류 발견
    • Spring Data JPA는 Spring에서 제공하는 라이브러리 중 하나로, JPA를 쉽고 편하게 사용할 수 있도록 도와줌
      • ex) findByUser(User user);
    • 쿼리 DSL : 정적 타입을 이용해서 SQL, JPQL을 코드로 작성할 수 있도록 도와주는 오픈소스 빌더 API
      • 특징
        • 문자가 아닌 코드로 작성
        • Compile 단계에서 문법 오류 확인 가능
        • 자동 완성 기능 활용 가능
        • 동적 쿼리 구현 가능
  • 2) 성능 차이
    • Querydsl은 JPQL을 코드로 만드는 것이기 때문에 결과적으로 JPQL로 실행되기 때문에 성능에는 거의 차이가 없다.
  • 3) 쿼리 최적화를 진행한다면…
    • SELECT문을 보다 빠르고 효율적으로 실행되도록 하기 위한 것을 쿼리 최적화 작업
    • 쿼리 최적화가 필요한 이유
      • 한 번 데이터를 가져올 때 빠르게 가져오고 사용중이던 커넥션을 다른 쪽에서 사용할 수 있도록 빠르게 반환 해야 하기 때문!
    • 쿼리 평가 엔진 Untitled
      • SQL 구문을 분석하고 어떤 순서로 데이터에 접근할지를 결정 → 즉, 우리가 DB에 쿼리를 전달하게 되면 먼저 쿼리 평가 엔진의 파서를 통하게 된다.
        • 파서 : 구문 분석 → 쿼리의 문법이나 없는 테이블, 컬럼 등이 작성되어 있으면 실행을 중단 시킴
          • 파서를 통해 파싱된 쿼리는 옵티마이저로 전송
      • 옵티마이저(최적화) : 파싱된 쿼리를 어떻게 실행하는 것이 가장 효율적일지 판단 → 실행계획 수립
        • 인덱스 유무, 데이터 분산, 편향 정도, 매개변수 등의 조건을 고려해서 실행 가능한 계획을 수립하고 그 중 가장 낮은 비용의 실행 계획을 선택 ← 카탈로그 매니저가 제공
        • 옵티마이저는 우리가 쿼리 최적화를 시킴에 있어서 많은 도움을 주지만 완벽하지는 않음. So, 쿼리를 작성하고 실행 계획을 보면서 쿼리를 수정하는 것이다.
          • 수정이 필요한 이유 : 카탈로그 매니저가 제공하는 정보는 시간이 지나면서 데이터 변경이 이뤄지는 것을 갱신해야 하므로 쿼리를 수정해야 한다. 이때, SQL 구문이 너무 복잡하게 작성되어 있다면 최적의 계획을 선택하지 못 할 수도 있다.
      • 실행 계획을 보는 법 : EXPLAN 명령어 사용 → 옵티마이저가 선택한 최적의 실행 계획을 보여줌
        • 눈 여겨 봐야 할 영역
          • rows : 테이블에서 들여다보는 row의 갯수를 의미(작을 수록 좋음)
          • Extra : Using where, Using index 등등의 값이 있다. → where 같은 경우는 쿼리문 조건에 의한 필터가 이루어진 경우 index 같은 경우는 테이블의 설정된 인덱스를 타는 경우를 뜻한다.
            • 대부분의 경우 인덱스를 타는 경우 비용적으로 유리한데 이는 모집합의 데이터가 많을 수록 인덱스 스캔이 유리하기 때문 But, 데이터 수가 많지 않을 때는 full scan이 유리하고 많을 때는 index scan이 유리하다
            • Extra에 어떤 값이 있는지 확인하고 index를 타지 않는 항목이 있다면 인덱스를 타도록 하여 쿼리를 수정해서 쿼리 최적화를 시킬 수 있다.
    • 최적화 방법
      • SELECT * 사용 X
      • UNION과 DISTINCT를 같이 사용 X → UNION에는 중복 값을 제거하는 기능이 존재
      • Distinct와 Group By를 같이 사용 X → Group By절에 입력된 칼럼을 그룹화
      • 서브 쿼리에서 Order By를 사용 X → 브 쿼리(Sub Query)에서 Order By를 사용하는 경우 많은 비용이 발생
      • 서브 쿼리의 결과가 많으면 EXISTS가 나은 성능을 제공하며 그렇지 않으면 IN을 사용하는 것이 좋음 → EXISTS는 일치하는 항목이 발견되는 즉시 검색 프로세스를 종료하지만 IN은 모든 항목을 비교하기 때문

#3. Restful 특징

  • Restful : REST API를 제공하는 웹 서비스를 RESTful 하다고 할 수 있다.
  • Rest : HTTP를 기반으로 필요한 자원에 접근하는 방식을 정해놓은 아키텍처
    • 웹의 기존 기술과 HTTP 프로토콜을 그대로 활용하기 때문에 웹의 장점을 최대한 활용할 수 있다.
    • 속성
      • 서버에 있는 모든 자원은 각 자원 당 클라이언트가 바로 접근할 수 있는 고유 URI가 존재
      • 모든 요청은 클라이언트가 요청할 때마다 필요한 정보를 주기 때문에 서버에서 세션 정보를 보관할 필요가 없다.(stateless)
      • HTTP 메서드를 사용 → HTTP 인터페이스인 GET, POST, PUT, DELETE 등의 메서드로 접근되어야 한다.
      • 서비스 내에 하나의 자원이 주변에 연관된 자원들과 연결되어 표현이 되어야 한다.
    • 구성
      • 자원 : 고유한 ID가 존재하고, 이 자원은 서버에 존재
        • ex) .../feeds/{photoId} -> feeds 아래 {photoId} 자원
      • 메서드 : HTTP 메서드를 사용 → GET, POST, PUT, DELETE 등이 존재
        • GET : 해당 리소스를 조회한다.

        • POST : 해당 리소스를 생성한다

        • PUT : 해당 리소스를 수정한다.

        • DELETE : 해당 리소스를 삭제한다.

          → PUT과 POST의 차이

        • 멱등성

          • POST: POST 요청은 멱등성을 가지지 않음 → 동일한 POST 요청을 여러 번 보내면 서버는 각각의 요청마다 새로운 리소스를 생성하게 됨
          • PUT: PUT 요청은 멱등성을 가짐 → 동일한 PUT 요청을 여러 번 보내더라도 동일한 리소스 상태가 유지
        • 리소스의 위치

          • POST: POST 요청은 서버에 리소스를 제출할 때 서버가 자체적으로 리소스의 위치를 결정 → 서버는 새로운 리소스를 생성하고 해당 리소스의 위치를 클라이언트에 응답으로 반환
          • PUT: PUT 요청은 클라이언트가 명시적으로 리소스의 위치를 지정 → 클라이언트는 PUT 요청을 통해 리소스를 특정 위치에 업데이트 또는 생성
        • 안전성

          • POST: POST 요청은 일반적으로 서버의 상태를 변경하거나 부작용을 초래할 수 있음
          • PUT: PUT 요청은 일반적으로 리소스의 업데이트 작업을 수행하므로, 안전성을 가질 수 있음
      • 메세지 : HTTP header, body, 응답 상태 코드 등으로 구성되어 있다.
        • 즉, header에는 body에 어떤 형식으로 데이터가 담겼는지 표시하고, body는 자원에 대한 정보를 JSON, XML 등으로 전달. 응답 상태 코드는 200~500 사이의 숫자로 클라이언트의 요청에 대한 상태를 나타내 줌.
    • 특징
      • Server-Client 구조
        • 자원이 있는 쪽이 서버, 자원을 요청하는 쪽이 클라이언트
      • Stateless
        • HTTP 프로토콜은 기본적으로 무상태이므로 Rest 역시 무상태
        • 무상태란 클라이언트의 상태(State)를 서버에 저장하지 않는다는 뜻
      • Cacheable
        • HTTP의 캐싱 기능을 적용할 수 있다.
      • 계층화
        • 클라이언트는 REST API 서버만 호출

#4. S3와 Lambda

  • Lambda의 원리

#4. jmeter의 과부화 테스트

#5. 테스트 코드

  • 1) Junit이란…
  • TDD 형식으로 작성한다면…

서버 통신 이슈

#1. MongoDB

  • NoSQL(비관계형 데이터베이스)를 사용 이유
    • 확장성: 채팅 서비스는 대규모의 동시 접속자를 처리해야 할 수도 있다. NoSQL 데이터베이스는 수평 확장성을 제공하여 필요에 따라 서버를 추가하거나 분산 시스템을 구축할 수 있다. 이는 데이터베이스의 성능과 처리 능력을 향상시키는 데 도움이 된다.
    • 유연성: 채팅 데이터는 종종 구조가 복잡하고 다양한 형식일 수 있다. NoSQL 데이터베이스는 스키마가 없거나 유연한 스키마를 가지고 있어 데이터 모델을 자유롭게 변경할 수 있다. 이는 새로운 필드나 속성을 추가하거나 데이터 구조를 수정하는 데 편리하다.
    • 실시간 처리: 채팅 서비스에서는 실시간으로 메시지를 송수신하고 처리해야 한다. NoSQL 데이터베이스는 분산 아키텍처와 메모리 기반 저장소를 활용하여 높은 처리량과 낮은 지연 시간을 제공할 수 있다. 이는 채팅 메시지의 실시간 전송과 응답을 지원하는 데 도움이 된다.
    • 활용성: 채팅 데이터는 대부분 개별 메시지 단위로 발생하고, 사용자, 대화방, 타임스탬프 등 다양한 쿼리 요건이 있을 수 있다. NoSQL 데이터베이스는 쿼리의 유연성과 확장성을 통해 이러한 요구 사항을 처리할 수 있다. 또한 NoSQL 데이터베이스는 대용량 데이터 처리에 특화되어 있으므로 채팅 기록이 많은 경우에 유용하다.
    • 가용성: 채팅 서비스는 항상 사용 가능해야 하므로 데이터베이스의 가용성이 매우 중요. NoSQL 데이터베이스는 데이터 복제, 자동 장애 복구 및 분산 환경에서의 운영을 지원하여 고가용성을 제공할 수 있다.
    • 즉, NoSQL 데이터베이스는 이러한 이점들을 통해 채팅 서비스의 성능, 확장성, 유연성, 실시간 처리 및 가용성을 향상시킬 수 있다. But, 데이터 모델링 및 쿼리 작성 방식에서 기존의 관계형 데이터베이스와 차이가 있으므로, 적절한 선택과 설계가 필요.
  • 만약 관계형 DB를 사용하게 된다면..?
    • 유연성 : NoSQL은 스키마를 사전에 정의하지 않고 유연하게 데이터를 저장할 수 있는 반면, 관계형 데이터베이스는 정해진 스키마를 준수해야 한다. So, 채팅 데이터의 구조 상 비관계형 DB가 더욱 적합하다.
    • 확장성 : 관계형 DB는 수평적 확장보다 수직적 확장을 지원한다. So, 대규모 채팅 애플리케이션에서 트래픽이 많아지면 데이터베이스 서버의 성능 한계에 도달할 수 있다. 이 때문에 NoSQL을 사용함 으로써 분산 DB Architecture를 기반으로 수평적 확장을 통해 대용량의 데이터와 트래픽을 처리하는 데 더 적합할 수 있다.
    • 속도 : 관계형 DB는 탐색과 업데이트가 빠른 반면, NoSQL은 insert가 빠르기에 채팅 서비스는 insert 비율이 1:1이기 때문에 NoSQL이 더 적합하다.

#2. Redis

  • Redis는 인메모리 데이터 스토어로 분산 캐싱, 세션 관리, 실시간 분석, 메시지 브로커 등 다양한 용도로 사용된다.
  • 사용 이유
    • 높은 성능: Redis는 데이터를 메모리에 저장하여 빠른 읽기 및 쓰기 성능을 제공. 따라서 빠른 데이터 접근이 필요한 애플리케이션에서 많이 사용. 또한 Redis는 단일 스레드 모델을 사용하여 데이터 처리를 순차적으로 수행하므로 락 관리에 대한 복잡성이 줄어들어 성능이 향상.
    • 데이터 구조 지원: Redis는 다양한 데이터 구조를 지원한다. 문자열, 해시, 리스트, 세트, 정렬된 세트 등 다양한 데이터 형식을 저장하고 조작할 수 있다. 이는 간단한 데이터 구조부터 복잡한 데이터 모델까지 다양한 용도로 활용할 수 있다는 장점을 제공한다.
  • in-Memory 형식이 아닌 DB 저장을 한다면…?
    • 속도 : in-Memory는 데이터를 RAM에 저장하기 때문에 디스크 I/O가 필요하지 않음 So, 디스크에 접근하는 것보다 RAM에 데이터를 읽고 쓰는 속도가 훨씬 빠름.
    • 인덱싱 및 쿼리 최적화 : 인 메모리 데이터 저장소는 인덱싱 및 쿼리 최적화를 위한 메모리 내 구조를 사용할 수 있음 So, 데이터를 인덱싱하고 쿼리를 실행하기 위한 데이터 구조를 메모리 내에 유지함으로써 데이터베이스 쿼리의 실행 속도를 향상시킬 수 있음 → 빠른 검색 및 조회 성능을 제공할 수 있음
  • in-Memory와 DB에 저장될 데이터 구분
    • in-Memory
      • 자주 access가 필요한 데이터
      • 임시 데이터
        • 이러한 데이터는 일시적으로 필요하지만 오랫동안 보관할 필요가 없으며, 반복적인 액세스 시 매번 계산하는 비용을 줄일 수 있음
      • 적은 용량의 데이터
    • DB
      • 지속성이 필요한 데이터
        • 데이터베이스는 데이터의 안정적인 보관과 백업을 제공하여 데이터 손실의 위험을 줄일 수 있음
      • 동시 액세스가 필요한 데이터
        • 여러 사용자 또는 여러 시스템에서 동시에 액세스해야 하는 데이터는 데이터베이스에 저장하여 동시성 문제를 관리할 수 있음
        • 그러면, In-Memory는 동시성 관리를 어떻게 하나?
      • 보안이 중요한 데이터
        • 민감한 정보나 중요한 데이터는 데이터베이스의 보안 기능을 활용하여 액세스 제어와 데이터 암호화를 보장할 수 있음

#3. 웹 소켓

  • 웹소켓은 실시간 양방향 통신을 제공하는 프로토콜
  • 사용 이유
    • 실시간 업데이트: 웹소켓은 서버와 클라이언트 간에 지속적인 연결을 유지하며, 양방향 통신을 가능하게 한다. 이를 통해 서버에서 클라이언트로 데이터를 실시간으로 업데이트하거나 클라이언트에서 서버로 요청을 보내고 실시간으로 결과를 받을 수 있다. 이는 실시간 채팅의 애플리케이션에 적합합니다.
    • 효율적인 통신: 웹소켓은 HTTP 프로토콜과 달리 상태를 유지하며 연결을 유지하기 때문에, 각 요청마다 새로운 연결을 맺어야 하는 오버헤드가 없다. 이는 요청과 응답 사이에 작은 데이터 패킷을 주고받을 때 특히 유용하며, 데이터 전송의 지연 시간과 대역폭 사용량을 줄일 수 있다.
    • 서버 푸시 기능: 일반적인 HTTP 요청은 클라이언트에서 서버로 요청을 보내는 방식이다. 그러나 웹소켓은 서버에서 클라이언트로 데이터를 프로액티브하게 푸시할 수 있는 기능을 제공. 이를 통해 서버에서 변경된 데이터를 실시간으로 클라이언트에게 전달할 수 있으며, 사용자 경험을 개선하고 서버와의 효율적인 상호작용을 가능케 한다.
    • 단일 연결 유지: 웹소켓은 단일 연결을 유지하므로, 여러 개의 HTTP 요청 및 응답을 처리하는 데 필요한 네트워크 및 서버 자원을 절약할 수 있다. 이는 서버의 확장성과 성능을 향상시킬 수 있는 장점을 제공한다.
    • 크로스 플랫폼 지원: 웹소켓은 다양한 클라이언트 플랫폼과 웹 브라우저에서 지원되는 표준 프로토콜이다. So, 웹, 모바일 앱, 데스크톱 앱 등 다양한 플랫폼 간에 일관된 실시간 통신을 구현할 수 있다.
  • 웹 소켓의 네트워크 통신 프로토콜 흐름
    • HandShake
      • 클라이언트가 서버에 웹 소켓 연결을 요청할 때, 일반적으로 HTTP를 통해 이루어지는데 이때 HTTP의 업그레이드 요청과 응답을 통해 웹 소켓 연결로 전환된다. → 클라이언트는 WebSocket 핸드셰이크 요청 헤더에 'Upgrade' 필드를 포함시켜 웹 소켓 연결을 요청하고, 서버는 핸드셰이크 응답으로 '101 Switching Protocols' 상태 코드를 반환하여 연결을 승인
    • 연결 설정
      • 핸드셰이크가 완료 후, 클라이언트와 서버는 양방향 통신을 위한 웹 소켓 연결이 설정 → 이후부터는 TCP/IP 기반의 지속적인 연결이 유지되며, 양방향 데이터 교환이 가능해짐
    • 양방향 통신
      • 양측은 독립적으로 데이터를 송수신 할 수 있으며, 전송된 데이터는 실시간으로 처리
  • 단점
    • 수평적 확장의 단점이 존재
      • 웹소켓 서버가 일반 서비스 애플리케이션과 붙어있을 경우 , 수평적 확장(Scale Out)이 어렵다. So, 서비스 규모에 따라 웹소켓 서버를 모듈화 해서 일반 서비스와 구분 지어 사용하는 방식도 고려해봐야 함

#4. SSE

  • SSE(Server-Sent Events)는 웹에서 서버로부터 실시간으로 이벤트를 수신하는 기능을 제공하는 웹 표준
  • 사용 이유
    • 실시간 업데이트: SSE는 서버로부터 실시간으로 데이터를 받아와 클라이언트 측에서 업데이트할 수 있다. 이를 통해 서버에서 클라이언트로 데이터를 주기적으로 전송하고, 클라이언트는 이벤트를 캐치하여 UI를 업데이트할 수 있다. 이는 실시간 채팅, 알림등 실시간 정보가 필요한 애플리케이션에 적합하다.
    • 단방향 통신: SSE는 클라이언트에서 서버로의 단방향 통신을 지원. 즉, 클라이언트는 서버로 요청을 보내지 않고도 서버로부터 데이터를 수신할 수 있다. 이는 서버의 푸시 기능을 활용하여 서버에서 변경된 데이터를 클라이언트에게 전송할 때 유용하다.
    • 간편한 구현: SSE는 HTML5 표준으로 지원되며, 일반적으로 사용되는 웹 기술인 JavaScript와 함께 사용할 수 있다. So, 별도의 라이브러리나 프레임워크 없이도 상대적으로 간편하게 구현할 수 있다.
    • 크로스 브라우저 호환성: SSE는 대부분의 최신 웹 브라우저에서 지원된다. 이는 다양한 플랫폼과 브라우저에서 일관된 방식으로 실시간 통신을 구현할 수 있음을 의미.
    • 연결 유지: SSE는 서버와의 연결을 유지하면서 데이터를 전송할 수 있다. So, 클라이언트와 서버 간에 지속적인 연결을 유지하는 WebSocket과는 달리, HTTP 연결을 유지하는 SSE는 서버의 확장성과 성능을 고려할 때 유용할 수 있다.
profile
진짜 개발자가 되고 싶다

0개의 댓글