스프링 부트 프로젝트를 하면서 에러 로그에서 프록시 객체라는 단어를 많이 보았습니다.

그래서 프록시 객체에 대해 알아보자 합니다.

 

프록시 객체란?

프록시 객체는 원본 객체를 대신해서 호출될 객체로, 원본 객체를 감싸서 클라이언트의 요청을 처리하는 중간 단계에 위치합니다.

프록시 객체는 원본 객체와 같은 인터페이스를 구현하고 있어서, 클라이언트는 프록시 객체를 호출하는 것으로 인해 원본 객체의 메소드를 호출하는 것과 같은 효과를 얻을 수 있습니다.

 

프록시 객체를 사용하는 이유는, 프록시 객체를 통해 원본 객체에 대한 접근을 제어하거나, 부가적인 기능을 제공하기 위해서입니다.

예를 들어, 보안을 위해 원본 객체의 메소드에 접근할 때 권한 검사를 수행하거나, 성능을 개선하기 위해 캐싱을 사용하는 등의 기능을 프록시 객체에서 추가할 수 있습니다.

이렇게 함으로써, 원본 객체의 코드를 변경하지 않고도 클라이언트의 요구사항에 맞추어 기능을 추가하거나 변경할 수 있습니다.

 

이 프록시 개념은 AOP에서 사용됩니다.

 

AOP란?

AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 합니다.

관점 지향은 어떠한 로직을 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것입니다.

예를 들어 핵심적인 관점은 비지니스 로직이 될 수 있고, 부가적인 관점은 로깅이 될 수 있습니다.

 

위의 그림에서 Class A, B, C는 핵심적인 관점이고, 노랑, 파랑, 빨강은 부가적인 관점입니다.

여기서 노랑, 파랑, 빨강 부분을 모듈화하여 재사용하는 것이 AOP의 취지입니다.

'채워가는 지식 > Spring Boot' 카테고리의 다른 글

JPA란?  (0) 2024.04.17
커넥션 풀이란?  (0) 2024.04.17
영속성 컨텍스트란?  (0) 2024.04.03
Bean에 대하여...  (0) 2024.02.16

자바에서 리스트를 만드는 방법은 new ArrayList<>(), Arrays.asList(), List.of()가 있는데, 저는 List.of()는 불변이고 나머지는 가변 정도로만 이해하고 있었습니다.

 

어느날 팀원이 알려주신 자바 리스트에 대한 블로그 글을 보니 좀 더 세밀한 차이점이 있었고, 잘 알고 적재적소에 사용한다면 좋을 것 같다는 생각이 들어서 글을 쓰게 되었습니다.

각 리스트 비교 표

  add/remove 가능 set 가능 원소 null 허용 참조 배열 복사 깊이
new ArrayList<>() o o o -
Arrays.asList() x o o 얕은 복사
List.of() x x x 깊은 복사

 

표에 나타나 듯이 add/remove, set이 불가능한 List.of()는 완전 불변이고, add/remove만 불가능한 Arrays.asList()는 반만 불변입니다.

 

그렇다면 불변의 이점은 무엇일까요?

  • 스레드 안정성: 불변 객체는 추가, 삭제가 안되기 때문에 동기화 없이도 여러 스레드에서 안전하게 공유하고 액세스할 수 있습니다.
  • 코드 간소화: 불변 객체는 동시성을 위해 설계할 필요가 없으므로 코드가 간소화되고 버그 가능성이 낮습니다.
  • 향상된 성능: 변경 불가능한 객체는 항상 동일한 상태를 유지하므로 캐시하고 재사용할 수 있습니다.

    ※ 변경 불가능한 컬렉션은 JVM 내에서 캐싱될 수 있다고 합니다.

 

참고 블로그

https://inpa.tistory.com/entry/JAVA-%E2%98%95-ArraysasList-%EC%99%80-Listof-%EC%B0%A8%EC%9D%B4-%ED%95%9C%EB%B0%A9-%EC%A0%95%EB%A6%AC

 

🧱 Arrays.asList() 와 List.of() 차이 한방 정리

자바에서 리스트를 만드는 방법 자바에서 리스트를 만드는 방식은 대표적으로 3가지 정도 존재한다. 하나는 생성자로 직접 리스트 객체를 인스턴화 시키는 것이고, 좀 더 간편하게 원소가 들은

inpa.tistory.com

 

'채워가는 지식 > Java' 카테고리의 다른 글

멀티 모듈  (1) 2023.12.05
객체 지향 설계 - 프로그래밍 관점  (0) 2023.11.30
객체 지향 설계 - 이론  (0) 2023.11.30
Java에 대해..  (0) 2023.09.27

Bean? Configuration? Context?

저는 스프링 부트로 프로젝트를 하다보면 Bean, Configuration, Context라는 단어를 자주 접했습니다.

접할 때마다 헷갈려서 개념에 대해 간단하게 정리하고자 합니다.

Bean

스프링에서 빈은 스프링 컨테이너에 의해 생성 및 관리되는 객체를 말합니다. 이 빈들은 스프링 애플리케이션에서 재사용 가능한 구성 요소로, 컨테이너에 등록되어 관리됩니다.

 

Bean은 다음과 같은 특징이 있습니다.

  • 재사용성: 빈들은 재사용 가능한 구성 요소로 설계되어 있으며, 이를 통해 코드의 중복을 줄이고 유지보수성을 향상시킵니다.
  • 의존성 주입: 빈들 간의 의존성은 스프링의 DI (Dependency Injection)를 통해 주입되며, 이는 객체 간의 결합도를 낮추고 테스트 가능한 코드를 작성할 수 있게 합니다.

Configuration

스프링에서 설정은 애플리케이션의 구성 정보를 담은 클래스로, 주로 @Configuration 어노테이션을 사용하여 표시됩니다. 이 클래스에서는 빈들의 정의와 의존성을 설정하고 관리합니다.

 

Configuration은 다음과 같은 특징이 있습니다.

  • 빈 정의: 설정 클래스에서는 @Bean 어노테이션을 사용하여 빈들을 정의합니다. 이를 통해 스프링 컨테이너에 등록되고 관리됩니다.
  • 외부 설정 연동: 설정 클래스에서는 @ConfigurationProperties 어노테이션을 사용하여 외부 설정 파일의 값을 빈에 주입할 수 있습니다.
  • 조건부 빈 등록: @ConditionalOn... 어노테이션을 사용하여 특정 조건에 따라 빈을 등록할 수 있습니다.

Context

스프링 부트 컨텍스트는 스프링 프레임워크의 핵심 기능인 IoC (Inversion of Control)와 DI (Dependency Injection)를 지원하는 컨테이너입니다. 이 컨텍스트는 애플리케이션의 구성 요소들을 관리하고, 객체들 간의 의존성을 관리하여 애플리케이션을 구성하고 실행하는 역할을 합니다.

 

Context는 다음과 같은 특징이 있습니다.

  • 빈 관리: 컨텍스트는 빈(bean)이라 불리는 객체들을 생성하고 관리합니다. 빈은 스프링 애플리케이션에서 재사용 가능한 구성 요소로, 컨텍스트는 이러한 빈들을 생성하고 관리합니다.
  • 의존성 주입: 빈들 간의 의존성은 컨텍스트가 관리하며, 이를 통해 객체 간의 결합도를 낮추고 테스트 및 유지보수를 용이하게 합니다.

따라서 일반적인 스프링 애플리케이션에서는 설정 클래스에 @Bean 어노테이션을 사용하여 빈을 정의하고, 이 설정 클래스를 스프링 컨텍스트에 등록하여 빈들이 관리되게 됩니다.

이렇게 하면 컨텍스트가 설정 클래스를 기반으로 빈들을 생성하고 의존성을 주입하게 됩니다.

 

@Component 외 내가 사용한 어노테이션들은 Bean으로 등록해주는 기능이 있나?

Bean에 대해서 알아보다가 제가 사용했던 @Component, @Repository, @Service, @RestController가 생각이 났습니다.

그래서 Bean의 관점에서 같이 알아보고 간단하게 정리하고자 합니다.

 

@Component

@Component 어노테이션은 스프링에서 관리하는 빈으로 등록하기 위해 사용되는 가장 기본적인 어노테이션 중 하나입니다.

이 어노테이션을 사용하면 해당 클래스를 스프링의 컨테이너에서 빈으로 인식하게 되어, 의존성 주입과 같은 스프링의 기능을 활용할 수 있습니다.

 

@Component 어노테이션을 사용하는 클래스는 주로 비즈니스 로직이나 다양한 기능을 수행하는 클래스로서, 스프링 애플리케이션 컨텍스트에 등록되어 다른 클래스에서 이를 주입받아 사용할 수 있습니다.

 

이 외에도 @Repository, @Service, @Controller 등은 @Component를 확장한 특수한 종류의 어노테이션으로 사용되기 때문에 @Repository, @Service, @Controller를 사용하는 클래스도 빈으로 등록됩니다.

 

※ @RestController는 @Controller를 확장한 것입니다.

'채워가는 지식 > Spring Boot' 카테고리의 다른 글

JPA란?  (0) 2024.04.17
커넥션 풀이란?  (0) 2024.04.17
영속성 컨텍스트란?  (0) 2024.04.03
스프링에서 프록시와 AOP란?  (0) 2024.03.04

https://www.acmicpc.net/problem/2630

 

2630번: 색종이 만들기

첫째 줄에는 전체 종이의 한 변의 길이 N이 주어져 있다. N은 2, 4, 8, 16, 32, 64, 128 중 하나이다. 색종이의 각 가로줄의 정사각형칸들의 색이 윗줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다.

www.acmicpc.net


구현 과정

문제를 보고 저는 크게 다음 2가지 로직이 필요하다고 생각했습니다.

  • 체크하는 범위 내 모든 원소가 0인지 1인지 확인하는 로직
  • 1/2의 크기로 4개로 분할하는 재귀 로직

구현 코드

import java.io.*;
import java.util.*;

public class Main {
    public static int white = 0;
    public static int blue = 0;

    public static int[][] board;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());

        board = new int[N][N];

        for (int i=0; i<N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j=0; j<N; j++) {
                int value = Integer.parseInt(st.nextToken());
                board[i][j] = value;
            }
        }

        partition(0, 0, N);

        System.out.println(white);
        System.out.println(blue);
    }

    public static boolean isAllOneOrZero(int row, int col, int size) {
        int color = board[row][col];
        for (int i=row; i<row+size; i++) {
            for (int j=col; j<col+size; j++) {
                if (board[i][j] != color) {
                    return false;
                }
            }
        }
        return true;
    }

    public static void partition(int row, int col, int size) {
        if (isAllOneOrZero(row, col, size)) {
            if (board[row][col] == 0) {
                white++;
            } else {
                blue++;
            }
            return;
        }

        size /= 2;

        partition(row, col, size);
        partition(row+size, col, size);
        partition(row, col+size, size);
        partition(row+size, col+size, size);
    }
}

 

로직 설명

체크하는 범위 내 모든 원소가 0인지 1인지 확인하는 로직

public static boolean isAllOneOrZero(int row, int col, int size) {
        int color = board[row][col];
        for (int i=row; i<row+size; i++) {
            for (int j=col; j<col+size; j++) {
                if (board[i][j] != color) {
                    return false;
                }
            }
        }
        return true;
    }

 

row와 col은 board에서 체크하는 범위의 시작인 행과 열입니다.

size는 체크하는 범위의 길이입니다.

color는 체크하는 범위의 가장 처음 확인하는 색깔입니다.

그 이후 이중 for문으로 체크하는 범위의 모든 원소들이 color와 같은지 확인합니다.

모두 color와 같다면 true, 아니라면 false를 반환합니다.

 

1/2의 크기로 4개로 분할하는 재귀 로직

public static void partition(int row, int col, int size) {
        if (isAllOneOrZero(row, col, size)) {
            if (board[row][col] == 0) {
                white++;
            } else {
                blue++;
            }
            return;
        }

        size /= 2;

        partition(row, col, size);
        partition(row+size, col, size);
        partition(row, col+size, size);
        partition(row+size, col+size, size);
    }

 

row와 col은 board에서 체크하는 범위의 시작인 행과 열입니다.

size는 체크하는 범위의 길이입니다.

isAllOneOrZero 결과가 true라면 색깔에 따라 white 또는 blue에 1을 더해줍니다.

1을 더해준 다음 return;을 통해 재귀를 종료합니다.

 

isAllOneOrZero 결과가 false라면 size를 절반으로 줄입니다.

그리고 4사분면으로 분할하여 재귀를 합니다.

프락시

프락시는 클라이언트와 서버 사이에 위치하여 그들 사이의 HTTP 메시지를 정리하는 중개인처럼 동작합니다.

 

1. 웹 중개자

HTTP 프락시 서버는 웹 서버이기도 하고 웹 클라이언트이기도 합니다.

1.1 개인 프락시와 공유 프락시

프락시 서버는 하나의 클라이언트가 독점적으로 사용할 수도 있고, 여러 클라이언트가 공유할 수도 있습니다.

대부분의 프락시는 공유 프락시입니다.

 

공유 프락시

중앙 집중형 프락시를 관리하는 것이 더 비용효율이 높고 쉽습니다.

여러 사용자들의 공통된 요청에는 캐시 프락시 서버를 사용하는 것으로 이득을 취할 수 있습니다.

 

개인프락시

브라우저의 기능을 확장하거나 성능을 개선하거나 무료 ISP 서비스를 위한 광고를 운영하기 위해 작은 프락시를 사용자의 컴퓨터에서 직접 실행합니다.

 

1.2 프락시와 게이트웨이

엄밀하게 말하면, 프락시는 같은 프로토콜을 사용하는 둘 이상의 애플리케이션을 연결하고, 게이트웨이는 서로 다른 프로토콜을 사용하는 둘 이상을 연결합니다.

 

하지만 실질적으로 프락시와 게이트웨이의 차이점은 모호합니다.

브라우저와 서버는 다른 버전의 HTTP를 구현하기 때문에, 프락시는 때때로 약간의 프로토콜 변환을 하기도 합니다.

그리고 상용 프락시 서버는 SSL 보안 프로토콜, SOCKS 방화벽, FTP 접근, 그리고 웹 기반 애플리케이션을 지원하기 위해 게이트웨이 기능을 구현합니다.

 

2. 프락시 사용성

프락시 서버는 실용적이고 유용한 것이라면 무슨 일이든 합니다.

보안을 개선하고, 성능을 높여주며, 비용을 절약합니다.

그리고 프락시 서버는 모든 HTTP 트래픽을 들여다보고 건드릴 수 있기 때문에, 프락시는 부가적인 가치를 주는 여러 유용한 웹 서비스를 구현하기 위해 트래픽을 감시하고 수정할 수 있습니다.

 

사용 예시

  • 어린이 필터 : 초등학교는 어린이들에게 교육 사이트를 제공하면서 동시에 동시에 성인 콘텐츠를 차단하려고 필터링 프락시를 사용할 수 있습니다.
  • 문서 접근 제어자 : 각 클라이언트마다 문서에 접근할 수 있는 권한을 주거나 비밀번호를 요구할 수 있습니다.
  • 보안 방화벽 : 조직 안에 들어오거나 나가는 응용 레벨 프로토콜의 흐름을 네트워크의 한 지점에서 통제합니다.
  • 웹 캐시 : 인기 있는 문서의 로컬 사본을 관리하고 해당 문서에 대한 요청이 오면 빠르게 제공하여, 느리고 비싼 인터넷 커뮤니케이션을 줄입니다.
  • 대리 프락시 : 공용 콘텐츠에 대한 느린 웹 서버의 성능을 개선하기 위해 사용될 수 있으며, 서버 가속기라고도 부릅니다.
  • 콘텐츠 라우터 : 인터넷 트래픽 조건과 콘텐츠의 종류에 따라 요청을 특정 웹 서버로 유도하는 콘텐츠 라우터로 동작할 수 있습니다.
  • 트랜스코더 : 콘텐츠를 클라이언트에게 전달하기 전에 본문 포맷을 수정할 수 있습니다.
  • 익명화 프락시 : HTTP 메시지에서 신원을 식별할 수 있는 특성들을 적극적으로 제거함으로써 개인 정보 보호와 익명성 보장에 기여합니다.

3. 프락시 위치

어떻게 사용할지에 따라서 프락시는 어디에든 배치할 수 있습니다.

 

프락시 서버 배치

  • 출구 프락시 : 로컬 네트워크와 더 큰 인터넷 사이를 오가는 트래픽을 제어하기 위해 프락시를 로컬 네트워크의 출구에 배치할 수 있습니다.
  • 접근(입구) 프락시 : 고객으로부터의 모든 요청을 종합적으로 처리하기 위해 ISP 접근 지접에 배치하기도 합니다.
  • 대리 프락시 : 네트워크의 가장 끝에 있는 웹 서버들의 바로 앞에 위치하여 웹 서버로 향하는 모든 요청을 처리하고 필요할 때만 웹 서버에게 자원을 요청할 수 있습니다.
  • 네트워크 교환 프락시 : 캐시를 이용해 인터넷 교차로의 혼잡을 완화하고 트래픽 흐름을 감시하기 위해, 충분한 처리 능력을 갖춘 프락시가 네트워크 사이의 인터넷 피어링 교환 지점들에 위치할 수 있습니다.

프락시 계층

프락시들은 프락시 계층이라고 불리는 연쇄를 구성할 수 있습니다.

 

4. 프락시의 트래픽 처리 방법

클라이언트 트래픽이 프락시로 가도록 만드는 방법에는 네 가지가 있습니다.

  • 프락시를 사용하도록 설정된 클라이언트
  • 트래픽을 가로채어 프락시로 리다이렉트하는 네트워크
  • 웹 서버를 위해 설치된 대리 프락시
  • HTTP 요청을 프락시로 리다이렉트하는 서버

5. 마치며...

이번 글을 프락시에 대해 가볍게 정리한 글입니다.

 

저는 이번 공부에서

  • 프락시가 무엇인지,
  • 어떤 용도로 사용할 수 있는지,
  • 어디에 위치할 수 있는지
  • 어떤 방법으로 프락시가 트래픽을 처리하는지

에 대해 알아갔습니다.

'채워가는 지식 > 네트워크' 카테고리의 다른 글

REST API란?  (0) 2024.04.12
STOMP 웹소켓 프로그래밍  (0) 2024.02.15
웹 서버  (0) 2023.12.29
커넥션  (0) 2023.12.20
HTTP 메시지  (0) 2023.12.18

1. 웹소켓

웹소켓은 http 환경에서 클라이언트와 서버 사이에 하나의 TCP 커넥션을 통해 실시간으로 전이중 통신을 가능하게 하는 프로토콜입니다.

※ 전이중 통신은 전화기처럼 양방향으로 송신과 수신이 가능한 통신을 뜻합니다.

2. HTTP vs 웹소켓

그럼 이러한 웹소켓과 HTTP와의 차이점은 무엇일까요?

HTTP는 클라이언트가 요청을 보낼 때마다 연결을 맺고 응답을 받은 후 연결을 끊어버리기 때문에 비 연결성 프로토콜이며, 클라이언트가 요청하고 서버가 응답하는 단방향 통신입니다.

반면에 웹소켓은 한번 연결을 맺으면 어느 한쪽에서 연결을 끊으라는 요청을 보내기 전까진 연결을 유지하기 때문에 연결 지향 프로토콜이며, 양 쪽에서 데이터를 주고 받을 수 있는 양방향 통신입니다.

 


2.1 실시간 측면에서는...?

http는 비 연결성이기 때문에 데이터를 주기 위해선 매번 연결해야 하고 그만큼 연결 비용이 발생하게 됩니다.


즉, 오버헤드가 커집니다.


위 이미지에서 왼쪽은 일반적인 http로 주고받는 데이터양이고,

오른쪽 위는 웹소켓 연결요청할 때의 데이터양이고,

그 아래는 연결 이후의 데이터양입니다.

웹소켓은 처음 연결할 때 http로 하기 때문에 처음 데이터 양은 유사하지만, 이후 데이터 양이 매우 줄어든 것을 확인할 수 있습니다.

이러한 점들에서 웹소켓이 http 보다 실시간성에 더 유리합니다.

 

3. 웹소켓 동작 방식


웹소켓의 동작 방식은 크게 3가지로 나눌 수 있는데요,

  • 빨간 박스는 Opening Handshake,
  • 노란 박스는 Data transfer,
  • 보라 박스는 Closing Handshake에 해당됩니다.

3.1 Opening Handshake

 

빨간 박스 부분인 Opening Handshake는 먼저 웹소켓 클라이언트에서 http 프로토콜을 통해 웹소켓으로 Upgrade 해달라는 요청을 보냅니다.

이 요청의 의미는 웹소켓 프로토콜로 전환해달라는 것입니다.

그 다음 웹소켓 서버는 101 응답과 함께 웹소켓 프로토콜로의 전환을 승인했음을 알립니다.

 

3.2 Data Transfer


노란 박스 부분인 Data Transfer는 Opening Handshake가 끝나서 전환된 웹소켓 프로토콜을 통해 클라이언트와 서버 간 실시간 전이중 통신을 하는 부분입니다.

 

3.3 Closing Handshake


보라 박스 부분인 Closing Handshake는 서로 간의 커넥션을 종료하는 부분입니다.

 

4. STOMP

STOMP는 streaming text oriented messaging protocol의 줄임말이며,
메세지 브로커를 활용하여 쉽게 메시지를 주고 받을 수 있는 프로토콜입니다.

이 프로토콜은 웹소켓 위에 얹어 하위 프로토콜로 함께 사용할 수 있습니다.

 

4.1 웹소켓만 사용하는 것 비해 어떤 이점이...?

웹소켓 프로토콜은 메시지 데이터 타입이 Text인지 Binary인지는 정의하지만, 메시지 내용에 대해서는 정의하지 않습니다.

이는 복잡한 메시지를 주고 받으려면 어떤 메시지인지 알기 위한 로직이 필요하다는 것입니다.

STOMP 프로토콜은 메시지 내용을 구조화 할 수 있어서 효과적인 메시징을 도와줍니다.

예를 들어, A라는 사람이 B라는 사람에게 “안녕”이라는 내용으로 보내는 메시지가 있다고 해보겠습니다.
웹소켓로 보낼 때는 “안녕”이라는 메시지만 보내면 됩니다.

클라이언트가 1명이라면 문제가 없지만, 클라이언트가 여러명이라면, 이 메시지를 누가 보냈는지, 누구한테 가야하는지, 어떤 용도로 보내는 것인지 서버가 알 수가 없습니다.

 

물론, 단순히 안녕이 아닌 모든 정보가 담긴 한줄의 긴 텍스트 문자열로 보낼 수 있습니다.
하지만 이러면, 서버가 이 메시지를 이해하고 처리하기 쉽지 않을 수 있습니다.


또한 연결된 클라이언트 주소마다 메시지 핸들러를 구현해야 합니다.

 


STOMP는 이미지처럼 

destination /app/chat/message로 보내는, 
sender A가,
content “안녕”의 내용의 메시지를,
send 전송했음을

구조화 된 형태로 보낼 수 있기 때문에 서버는 이 메시지가 어떤 메시지인지 이해하고 처리하기 쉽습니다.

또 다른 이점은 STOMP는 pub/sub 구조로 되어있다는 것입니다.

 



pub/sub 구조란 이 이미지처럼 publisher에서 메시지 브로커의 Topic1이라는 특정 토픽에 메시지를 보내면, Topic1을 구독하고 있는 subscribe들에게 메세지를 전달하는 구조를 말합니다.

이 구조로 인해 최대 토픽별로만 메시지 핸들러를 구현해주면 되기 때문에 웹소켓로만 구성된 것에 비해 메시지 핸들러 구현 양이 줄어든다는 이점이 있습니다.

 

4.2 pub/sub 구조의 특징

저는 pub/sub 구조의 특징을 크게 3가지로 나눠볼 수 있었습니다.

  • pub과 sub을 쉽게 추가할 수 있어서 확장성이 좋습니다.
  • pub과 sub 간에 강한 의존성이 없어서 비동기적으로 처리할 수 있습니다.
  • sub은 관심 토픽에 대한 메시지만 받을 수 있어서 선택적 수신이 가능합니다.

5. 마치며...

Kernel 360에서 기술세미나를 하게되어 이번 글을 작성했습니다.

 

이 글에서

  • 웹소켓이 무엇인지,
  • 웹소켓과 HTTP의 차이점이 무엇인지,
  • 웹소켓이 어떻게 동작하는지,
  • STOMP가 무엇이고, 어떤 이점이 있는지,
  • pub/sub 구조가 무엇인지

에 대해 알아가셨으면 좋겠습니다.

 

저는 여러분들이 채팅, 실시간 업데이트, 알림 같은 실시간성 기능을 구현하고자 하면, STOMP도 선택지 중 하나라고 생각합니다.

'채워가는 지식 > 네트워크' 카테고리의 다른 글

REST API란?  (0) 2024.04.12
프락시  (0) 2024.02.15
웹 서버  (0) 2023.12.29
커넥션  (0) 2023.12.20
HTTP 메시지  (0) 2023.12.18

웹 서버

웹 서버는 HTTP 요청을 처리하고 응답을 제공합니다.

 

1. 공통적으로 웹 서버가 하는 일

  • 커넥션 맺기
  • 요청 받기
  • 요청 처리
  • 리소스 접근
  • 응답 만들기
  • 응답 보내기
  • 트랜잭션을 로그로 남기기

1.1 커넥션 맺기

클라이언트가 이미 서버에 대해 열려있는 지속적 커넥션을 갖고 있다면, 클라이언트는 요청을 보내기 위해 그 커넥션을 사용할 수 있습니다.

그렇지 않다면, 클라이언트는 서버에 대한 새 커넥션을 열어야 합니다.

1.1.1 새 커넥션 다루기

클라이언트가 웹 서버에 TCP 커넥션을 요청하면, 웹 서버는 그 커넥션을 맺고 TCP 커넥션에서 IP 주소를 추출하여 커넥션 맞은편에 어떤 클라이언트가 있는지 확인합니다.

일단 새 커넥션이 맺어지고 받아들여지면, 서버는 새 커넥션을 커넥션 목록에 추가하고 커넥션에서 오가는 데이터를 지켜보기 위한 준비를 합니다.

웹 서버는 어떤 커넥션이든 마음대로 거절하거나 즉시 닫을 수 있습니다.

그래서 어떤 웹 서버들은 클라이언트의 IP 주소나 호스트 명이 인가되지 않았거나 악의적이라고 알려진 것인 경우 커넥션을 닫습니다.

 

1.2 요청 받기

커넥션에 데이터가 도착하면, 웹 서버는 네트워크 커넥션에서 그 데이터를 읽어 들이고 파싱하여 요청 메시지를 구성합니다.

요청 메시지를 파싱할 때, 웹 서버는 다음과 같은 일을 합니다.

  • 요청줄을 파싱하여 요청 메서드, 지정된 리소스의 식별자(URI), 버전 번호를 찾습니다.
  • 메시지 헤더들을 읽습니다.
  • 헤더의 끝을 의미하는 CRLF로 끝나는 빈 줄이 있다면 찾아냅니다.
  • 요청 본문이 있다면, 읽어 들입니다.(길이는 Content-Length 헤더로 정의)

요청 메시지를 파싱할 때, 웹 서버는 입력 데이터를 네트워크로부터 불규칙적으로 받습니다.

네트워크 커넥션은 언제라도 무효화될 수 있기 때문에, 웹 서버는 파싱해서 이해하는 것이 가능한 수준의 분량을 확보할 때까지 데이터를 네트워크로부터 읽어서 메시지 일부분을 메모리에 임시로 저장해 둘 필요가 있습니다.

1.2.1 메시지의 내부 표현

몇몇 웹 서버는 요청 메시지를 쉽게 다룰 수 있도록 내부의 자료 구조에 저장합니다.

예를 들어, 헤더는 속도가 빠른 룩업 테이블에 저장되어 각 필드에 신속하게 접근할 수 있습니다.

1.2.2 커넥션 입력/출력 처리 아키텍처

커넥션 입출력 처리 아키텍처는 다음과 같이 있습니다.

 

a) 단일-스레드 I/O 아키텍처

한 번에 하나씩 요청을 처리합니다.

즉, 현재 커넥션의 트랜잭션이 완료되어야 다음 커넥션이 처리됩니다.

이 아키텍처는 구현이 간단하지만 심각한 성능 문제를 만듭니다.

 

b) 멀티스레드 I/O 아키텍처

멀티 스레드로 여러 요청을 한번에 처리합니다.

즉, 매 커넥션마다 스레드 하나를 할당하여, 여러 커넥션을 동시에 처리합니다.

이 아키텍처는 많은 수의 커넥션을 동시에 처리하게 되면, 너무 많은 메모리나 시스템 리소스를 소비합니다.

그렇기에 스레드의 최대 개수에 제한을 둡니다.

 

c) 다중 I/O 아키텍처

다중 아키텍처에서는 모든 커넥션은 동시에 그 활동을 감시당합니다.

커넥션의 상태가 바뀌면, 그 커넥션에 대해 작은 양의 처리가 수행됩니다.

그 처리가 완료되면, 커넥션은 다음번 상태 변경을 위해 열린 커넥션 목록으로 돌아갑니다.

이로써, 스레드는 유휴 상태의 커넥션에 매여 기다리느라 리소스를 낭비하지 않습니다.

 

※ 커넥션의 효율이 높아진다고 보시면 될 것 같습니다.

 

d) 다중, 멀티스레드 I/O 아키텍처

멀티스레딩과 다중화를 결합한 것입니다.

 

1.3 요청 처리

웹 서버가 요청을 받으면, 서버는 요청으로부터 메서드, 리소스, 헤더, 본문을 얻어내어 처리합니다.

 

1.4 리소스의 매핑과 접근

웹 서버는 리소스 서버입니다.

웹 서버가 클라이언트에 콘텐츠를 전달하려면, 요청 메시지의 URI에 대응하는 알맞은 콘텐츠나 콘텐츠 생성기를 웹 서버에서 찾아서 그 콘텐츠의 원천을 식별해야 합니다.

 

웹 서버는 여러 종류의 리소스 매핑을 지원합니다.

  • Docroot : 가장 단순한 형태로 요청 URI를 웹 서버의 파일 시스템 안에 있는 파일 이름으로 사용하는 것입니다.
  • 디렉토리 목록 : 파일 이름이 아닌 디렉토리 이름을 사용함으로써 디렉토리 안에 있는 특별한 색인 파일을 반환합니다.
  • 동적 콘텐츠 리소스 매핑 : 콘텐츠를 생성하는 프로그램에 URI를 매핑하는 것입니다.
  • 서버사이드 인클루드(SSI) : 리소스의 콘텐츠를 클라이언트에게 보내기 전에 처리합니다.

웹 서버는 각각의 리소스에 접근 제어를 할당 할 수 있습니다.

 

1.5 응답 만들기

서버는 요청 메서드로 서술되는 동작을 수행한 뒤 응답 메시지를 반환합니다.

응답 메시지는 응답 상태 코드, 응답 헤더, 그리고 응답 본문(있다면)을 포함합니다.

 

1.6 응답 보내기

만들어진 응답 메시지를 커넥션 너머로 데이터를 보냅니다.

 

웹 서버는 종종 성공 메시지 대신 리다이렉션 응답을 반환합니다.

리다이렉트는 다음의 경우에 유용합니다.

  • 영구히 리소스가 옮겨진 경우
  • 임시로 리소스가 옮겨진 경우
  • URL 증강
  • 부하 균형
  • 친밀한 다른 서버가 있을 때
  • 디렉터리 이름 정규화

1.7 로깅

트랜잭션이 완료되었을 때 웹 서버는 트랜잭션이 어떻게 수행되었는 지에 대한 로그를 로그 파일에 기록합니다.

 

마치며..

 이 글은 웹 서버에 대해 간략히 적은 글입니다.

 

저는 이번 공부에서

  • 웹 서버가 하는 일이 무엇이 있는지,
  • 어떤 순서로 하는지,
  • 각 순서에 어떤 일을 하는지,
  • 커넥션 입출력 처리 아키텍처에 무엇이 있는지

를 알아 갔습니다.

 

이번엔 커넥션 입출력 처리 아키텍처를 제외하고 가볍게 읽었습니다.

'채워가는 지식 > 네트워크' 카테고리의 다른 글

프락시  (0) 2024.02.15
STOMP 웹소켓 프로그래밍  (0) 2024.02.15
커넥션  (0) 2023.12.20
HTTP 메시지  (0) 2023.12.18
URL  (1) 2023.12.18

관계형 모델

관계형 모델은 상업용 데이터 처리 응용을 위한 주요 데이터 모델입니다.

관계형 모델은 이전의 다른 모델과 비교했을 때 프로그래머의 작업을 더 쉽게 만들어 줄 수 있는 단순성으로 인해 아직까지 최고의 자리를 차지하고 있습니다.

 

1. 관계형 데이터베이스의 구조

관계형 데이터베이스는 테이블의 모임으로 구성되며, 각 테이블은 고유한 이름을 가지고 있습니다.

각 테이블은 데이터 필드를 나타내는 열들과, 각 필드에 대한 을 나타내는 행들로 구성되어 있습니다.

각 행은 일련의 값 사이의 관계를 표현합니다.

 

1.1 관계형 모델 구조

관계형 모델에서 테이블은 릴레이션, 열은 속성, 행은 튜플이라 합니다.

 

릴레이션에서 속성의 개수는 인수라 합니다.

 

릴레이션 인스턴스는 특정 시점에서의 릴레이션입니다.

 

※ DB에서의 스냅샷이랑 같은 의미입니다.(또는 데이터베이스 인스턴스)

 

릴레이션의 각 속성은 도메인이란 허가된 값의 집합을 가지고 있습니다.

예를 들어, 교수 릴레이션의 이름 속성의 도메인은 가능한 모든 교수의 이름입니다.

 

모든 릴레이션에 대해서 모든 속성의 도메인은 원자적이어야 합니다.

원자적 도메인이란, 도메인의 요소가 더이상 나뉠 수 없다는 단위라는 것을 의미합니다.

예를 들어, 전화 번호라는 속성이 존재한다고 하면, 번호는 원자적이지 않습니다.

왜냐하면, 전화 번호는 집 번호, 휴대폰 번호, 회사 번호 등의 부분 집합을 가지고 있기 때문입니다.

 

널(null) 값은 알려지지 않거나 존재하지 않는 값을 의미하는 특별한 값입니다.

데이터베이스의 해당 행과 열에 대한 데이터에 값이 존재하지 않으면 널 값이 들어갑니다.

 

※ 책에서는 가능하다면 널 값은 데이터베이스의 접근이나 갱신에 어려움을 주기 때문에 제거하는 것이 좋다고 합니다.

 

릴레이션 스키마는 속성과 그 속성이 가지는 도메인의 명세로 구성됩니다.

 

2. 키

주어진 릴레이션 안에서 튜플을 구별하는 방법이 있어야 합니다.

그러기위해, 튜플을 유일하게 식별할 수 있어야 하는 튜플의 속성값이 필요합니다.

 

2.1 슈퍼 키

한 릴레이션에서 그 튜플을 유일하게 식별할 수 있도록 해 주는 하나 혹은 그 이상의 속성들의 집합입니다.

예를 들어, 교수 릴레이션의 ID 속성이 튜플을 유일하게 식별할 수 있는 속성이라고 하면, ID뿐만 아니라 ID를 포함한 속성들의 집합이 슈퍼 키가 될 수 있습니다.

 

2.2 후보 키

모든 슈퍼키 중에서 최소한의 집합을 가진 슈퍼 키들이 후보 키가 될 수 있습니다.

위의 예제에서는 ID가 후보 키들 중에 하나입니다.

 

2.3 주 키(기본 키)

후보 키들 중에 데이터베이스 설계자에 의해 선택된 키가 주 키가 됩니다.

  • 주 키 제약 조건
    릴레이션의 어떠한 튜플도 같은 값을 갖는 주 키가 동시에 존재할 수 없다.

 

2.4 외래 키

하나의 릴레이션 A의 속성이 다른 릴레이션 B의 주 키라면, 그 속성이 외래 키가 됩니다.

이 때, A는 참조하는 릴레이션, B는 참조되는 릴레이션이라 합니다.

  • 외래 키 제약 조건
    참조하는 릴레이션의 각 튜플들의 특정 속성의 값(외래 키)이 참조되는 릴레이션의 어떤 튜플의 특정 속성(주 키)의 값으로 존재해야 한다.
  • 참조 무결성 제약 조건
    외래 키 제약 조건을 조금 더 완화한 것.
    참조하는 릴레이션의 어떤 튜플의 특정 속성의 값(외래키)이 참조되는 릴레이션에서 적어도 하나의 튜플의 특정 속성의 값(주 키)으로 존재해야 한다.

3. 스키마 다이어그램

데이터베이스 스키마는 주 키와 외래 키 종속성을 가지고 있는데, 이를 시각적으로 나타낸 것이 스키마 다이어그램이라 합니다.

 

일반 화살표는 외래키 제약 조건, 이중 화살표는 참조 무결성 제약 조건을 나타냅니다.

 

※ 다른 형태의 다이어그램 표기 방법으로 개체-관계 다이어그램(ERD)도 있습니다.

 

4. 관계형 질의어

질의어는 사용자가 데이터베이스로부터 정보를 요청할 때 사용하는 언어입니다.

 

질의어는 다음 3가지 언어로 구분할 수 있습니다.

  • 명령형 질의어 : 사용자가 원하는 결과를 계산하기 위해 데이터베이스에 특별한 일련의 연산을 수행하도록 명령합니다.
  • 함수형 질의어 : 계산은 데이터베이스에 있는 데이터나 다른 함수의 결과에 대해서 동작하는 함수의 실행으로 표현됩니다.
  • 선언형 질의어 : 사용자는 원하는 정보만 기술하며 이 정보를 얻기 위한 구체적인 단계나 함수 호출을 기술하지 않습니다.

    ※ 데이터베이스 엔지니어가 아니라면, 관계형 질의어에는 이런게 있구나하고 넘어가셔도 될 것 같습니다.

5. 관계 대수

관계 대수는 순수 질의어의 한 종류로 함수형 질의어입니다.

관계 대수는 한 개 혹은 두 개의 릴레이션을 입력으로 받아 그 결과로 새로운 릴레이션을 생성하는 연산들의 집합으로 구성됩니다.

 

선택, 추출, 재명명 연산은 한 릴레이션에 대해 수행하므로 단항 연산,

카티션 곱, 집합 연산은 한 쌍의 릴레이션에 대해 수행하므로 이항 연산이라 합니다.

 

5.1 선택 연산

선택 연산은 주어진 조건을 만족하는 튜플을 선택해줍니다.

예를 들어 속성으로 ID, 이름, 연봉을 가진 릴레이션에서 연봉이 4000이상으로 선택 연산하면 조건에 만족하는 튜플을 선택합니다.

 

5.2 추출 연산

추출 연산은 주어진 속성들만을 결과 릴레이션으로 돌려줍니다.

예를 들어 속성으로 ID, 이름, 직업, 연봉을 가진 릴레이션에서 ID, 이름 속성만을 추출 연산하면 속성이 ID, 이름만 있는 릴레이션을 반환해줍니다.

 

5.3 혼합 관계 연산

혼합 관계 연산은 선택 연산과 추출 연산을 혼합해서 사용한 연산입니다.

 

5.4 카티션 곱 연산

카티션 곱 연산은 한 쌍의 릴레이션의 결합된 릴레이션으로 돌려줍니다.

예를 들어, 2개의 튜플을 가지는 A 릴레이션과 3개의 튜플을 가지는 B 릴레이션이 있다고 하면,

A, B를카티션 곱 연산을 하면, A의 각 튜플은 B의 3개의 튜플 정보를 가지는 3개의 튜플로 늘어나고,

총 2 * 3 = 6개의 튜플을 가지는 새로운 릴레이션이 생깁니다.

 

※ 수학의 경우의 수에 비유하자면, 모든 경우의 수를 보여준다고 생각하시면 됩니다.

 

5.5 조인 연산

조인 연산은 카티션 곱 연산 후 선택 연산한 것입니다.

 

5.6 집합 연산

집합 연산에는 합집합, 교집합, 차집합 연산이 있습니다.

 

집합 연산을 하기 위해서는 다음 2가지를 만족해야 합니다.

  • 릴레이션 A, B는 같은 수의 속성을 가져야 합니다.
  • 릴레이션 A의 i번째 속성의 도메인과 릴레이션 B의 i번째 속성의 도메인은 서로 같아야 합니다.

위 2가지를 만족하는 릴레이션을 호환 가능한 릴레이션이라 합니다.

 

5.7 배정 연산

배정 연산은 일시적인 릴레이션 변수에 질의를 배정하는 것입니다.

 

5.8 재명명 연산

재명명 연산은 관계 대수식의 결과를 참조할 수 있는 이름을 갖게 해줍니다.

또한 동일한 릴레이션에 대해서 서로 다른 유일한 이름을 부여하는 데 사용될 수 있습니다.

 

5.9 동등 질의

질의를 관계 대수로 표현하는 데 한 가지 이상의 방법이 있을 수 있습니다.

즉, 서로 다르게 생긴 질의지만, 같은 결과를 내는 질의를 동등 질의라 합니다.

 

※ 동등 질의지만 효율은 다를 수 있기에 저는 더 효율이 좋은 질의를 선택할 수 있어야 된다고 생각합니다.

 

마치며...

이번 글은 관계 모델에 대해 정리한 글입니다.

 

저는 이번 공부에서

  • 관계형 모델의 구조는 어떤지,
  • 다양한 키와 제약 조건이 어떤 것이 있고 무엇인지,
  • 스키마 다이어그램이 무엇인지,
  • 관계형 질의어 종류에 어떤 것이 있는지,
  • 관계 대수이 무엇이고, 어떤 연산들이 있는지,

를 배웠습니다.

 

이번 공부에서 관계형 질의어 종류 같은 경우에는 이런 게 있구나 정도로만 넘어갔고, 추후에 보완할 필요가 있다면 보완할 것입니다.

그리고 저는 조인 연산이 막연하게 알고 있던 각 릴레이션 선택 후 합집합 연산이 아닌

카티션 곱 연산을 한 후에 선택 연산임을 알아 갔습니다.

 

'채워가는 지식 > DB' 카테고리의 다른 글

인덱스, 뷰, 조인  (0) 2024.04.18
ACID란?  (0) 2024.04.17
쿼리 최적화에 대하여...  (0) 2024.04.17
RDBMS와 NoSQL의 장단점  (0) 2024.04.17

+ Recent posts