728x90

명령형 프로그래밍

프로그램이 어떻게 작업을 수행할지를 명시적으로 정의하는 방식

상태와 상태를 변경하는 명령어들의 연속으로 구성됨

프로그램이 어떤 작업을 수행해야 하느지 단계별로 기술하며, 컴퓨터에게 명령을 내리는 개념

# 리스트에서 짝수를 찾아 제곱한 후 새로운 리스트에 저장하는 명령형 코드
numbers = [1, 2, 3, 4, 5]
squared_evens = []

for num in numbers:
    if num % 2 == 0:
        squared_evens.append(num ** 2)

print(squared_evens)
  • 장점
    • 직관성, 가독성 : 일반적으로 작업이 어떻게 수행되는지 명확히 보여줌
    • 효율적인 메모리 사용 : 상태를 직접 조작하므로 메모리 효율적 사용에 유리
    • 직접적인 제어 : 작업의 세부사항에 대한 직접적인 제어를 제공하므로 세밀한 최적화가 가능
  • 단점
    • 복잡성 : 코드가 상태를 직접 조작하면서 복잡성이 증가할 수 있음
    • 변수 상태 관리 : 변수상태를 올바르게 관리하지 않으면 버그가 발생할 수 있음
    • 유지보수 어려움 : 코드가 어떻게 동작할지 이해하기 어려울 수 있어 유지보수가 불리

선언형 프로그래밍

프로그램이 무엇을 수행할지를 명시적으로 정의하는 방식

어떤 작업을 어떻게 수행할지를 명시하지 않고, 목표를 기술하는 방식

더 추상화되고 선언적인 방식으로 문제를 해결하며, 내부적으로 시스템이 어떻게 동작하는지를 숨김

함수형 프로그래밍은 선언형 프로그래밍의 대표적인 예시

# 리스트에서 짝수를 찾아 제곱한 후 새로운 리스트에 저장하는 선언형 코드 (리스트 컴프리헨션 사용)
numbers = [1, 2, 3, 4, 5]
squared_evens = [num ** 2 for num in numbers if num % 2 == 0]

print(squared_evens)
  • 장점
    • 간결성 : 코드가 더 짧고 간결하며, 목적에 집중할 수 있음
    • 추상화와 모듈화 : 작업을 높은 수준에서 추상화하고 모듈화하므로 코드를 이해하고 재사용하기 쉬움
    • 병렬처리 용이 : 함수형 프로그래밍의 특징인 불변성과 순수 함수는 병렬처리를 쉽게 만들어줌
  • 단점
    • 초기 학습이 어려움
    • 최적화 어려움 : 목표를 선언하는 것은 좋지만 내부 동작을알기 어려워 최적화가 어려울 수 있음
    • 메모리 사용량 증가 가능성 : 함수형 프로그래밍에서 불변성을 유지하려면 새로운 데이터 구조를 계속 생성해야하므로 메모리 사용량이 증가할 수 있음
728x90

'Computer Science' 카테고리의 다른 글

지역 심벌과 전역 심벌  (0) 2024.07.24
링커란?  (0) 2024.07.17
컴파일 언어와 인터프리터 언어 비교  (0) 2024.07.10
Brute force(브루트 포스)란?  (0) 2024.07.09
스택(stack)과 힙(Heap)  (0) 2024.03.27
728x90

WSGI(웹 서버 게이트웨이 인터페이스)와 ASGI(비동기 서버 게이트웨이 인터페이스)는 웹 애플리케이션 서버와 웹 애플리케이션 간의 표준화된 인터페이스를 제공하는 목적으로 사용되는 두 가지 프로토콜

 

WSGI는 주로 동기적인 애플리케이션에 사용됨

ASGI는 비동기적이며 실시간 기능이 필요한 애플리케이션에 사용하며, ASGI는 특히 웹 소켓을 이용한 양방향 통신과 같은 기능을 지원하여 실시간 애플리케이션을 개발할 때 유용함

 

WSGI (Web Server Gateway Interface):

  1. 동기적인 처리: WSGI는 동기적인 방식으로 동작하며, 요청이 처리될 때까지 블록 됨 (하나의 요청이 완전히 처리되기 전에 다른 요청을 처리하지 못하고 대기)
  2. 대부분의 경우에 적합: WSGI는 대부분의 웹 애플리케이션에 적합하며, 간단한 애플리케이션에서 잘 동작함
  3. 웹 서버와의 통합 용이성: WSGI 애플리케이션은 여러 웹 서버와 쉽게 통합될 수 있음
  4. 플라스크 프레임워크에서 사용

ASGI (Asynchronous Server Gateway Interface):

  1. 비동기적인 처리: ASGI는 비동기적으로 동작하며, 여러 요청을 동시에 처리 가능 → 실시간 기능이 필요한 애플리케이션에 적합
  2. 실시간 기능 및 이벤트 처리: ASGI는 웹 소켓을 비롯한 실시간 기능 및 이벤트 기능을 지원하여 실시간 채팅, 게임 등과 같은 애플리케이션에 유용함
  3. Django, FastAPI와 같은 프레임워크에서 비동기적으로 동작하는 애플리케이션을 지원하는 데 사용
728x90
728x90

1. 동기

작업이 순차적으로 실행됨

 

2. threading (동기, i/o-bound 병렬처리)

I/O bound 동기 작업을 병렬 처리하는 데에 사용

스레드는 별도의 실행 흐름을 생성하고 여러 스레드를 사용하여 동시에 여러 작업을 수행

I/O 바운드 작업에서는 효과적으로 동작할 수 있지만, CPU 바운드 작업에서는 GIL(Global Interpreter Lock)로 인해 병렬성의 이점을 얻기 어려움 (프로세스 하나, 메모리 공유)

 

3. asyncio.gather (비동기, i/o-bound 병렬처리)

I/O bound 비동기 작업을 병렬 처리하는 데에 사용

하나의 이벤트 루프 내에서 여러 작업이 비동기적으로 실행

각 작업이 I/O 바운드 작업이라면 이벤트 루프가 대기 중인 작업을 계속해서 실행 가능

비동기 작업은 비동기 함수 안에서 await를 통해 비동기적으로 실행되기 때문에, 메모리 공유 측면에서는 주로 이벤트 루프 내에서 발생하므로 스레딩보다는 적은 동시 액세스가 발생

I/O 바운드 작업에서는 효과적으로 동작할 수 있지만, CPU 바운드 작업에서는 GIL(Global Interpreter Lock)로 인해 병렬성의 이점을 얻기 어려움 (프로세스 하나, 메모리 공유)

 

4. multiprocessing (cpu-bound 병렬처리)

CPU bound 작업을 병렬처리하는 데 사용

각 프로세스는 독립적인 메모리 공간을 가지고 있어 GIL(Global Interpreter Lock)의 영향을 받지 않아 CPU 바운드 작업에서 높은 병렬성을 얻을 수 있음

프로세스 간 통신이나 데이터 공유는 복잡하고 오버헤드가 큼

 

 

728x90
728x90

소스코드

import time
import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message":"Hello World"}

# FastAPI는 async를 사용하지 않아도 비동기로 작업을 수행
# https://tigris-data-science.tistory.com/entry/FastAPI%EC%9D%98-%EB%8F%99%EA%B8%B0-%ED%95%A8%EC%88%98-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D
@app.get("/sleep") # API처리중에 다른API 처리가능
def time_sleep():
    time.sleep(5)
    return 5

# async를 사용하면 메인쓰레드에서 동작하여 cpu-bound 작업 수행 시 다른 쓰레드 Blocking됨
@app.get("/async-sleep") # API처리 끝날때까지 다른API block
async def async_sleep():
    time.sleep(5)
    return 5

# async를 사용할 땐 메모리 bound작업을 해야 다른 쓰레드가 Blocking되지 않음
@app.get("/async-asyncio-sleep") # API처리중에 다른API 처리가능
async def asyncio_sleep():
    await asyncio.sleep(5)
    return 5

참고 : 개발환경 라이브러리 버전

annotated-types==0.6.0
anyio==4.3.0
click==8.1.7
colorama==0.4.6
fastapi==0.110.0
h11==0.14.0
idna==3.6
pydantic==2.6.2
pydantic_core==2.16.3
sniffio==1.3.1
starlette==0.36.3
typing_extensions==4.10.0
uvicorn==0.27.1

 

728x90
728x90

소스코드

from fastapi import FastAPI
import time
import asyncio
from datetime import datetime

app = FastAPI()

sem = asyncio.Semaphore(3) # 최대 동시처리 가능 개수 제한

@app.get("/")
def root():
    print("/", datetime.now())
    return {"date_time": datetime.now()}

@app.get("/time-sleep")
def time_sleep():
    start_time = datetime.now()
    results = time.sleep(6)
    end_time = datetime.now()
    return {"start_time":start_time, "end_time":end_time, "results":results}


@app.get("/async")
async def async_root():
    print("/async", datetime.now())
    return {"date_time": datetime.now()}

async def _async_sleep(num, sec): # time sleep 은 I/O bound 작업을 테스트할 때 사용
    async with sem:
        print("start sleep", datetime.now())
        await asyncio.sleep(sec)
        print("end sleep", datetime.now())
        return f"hehe {num}"

async def task_in_parallel():
    # 여러 개의 비동기 작업을 동시에 실행
    results = await asyncio.gather( 
        asyncio.create_task(_async_sleep(1,6)),
        asyncio.create_task(_async_sleep(2,6)),
        asyncio.create_task(_async_sleep(3,6)),
        asyncio.create_task(_async_sleep(4,6)),
        asyncio.create_task(_async_sleep(5,6)),
    )
    return results
    
@app.get("/async-asyncio-sleep")
async def parallel_sleep():
    start_time = datetime.now()
    results = await task_in_parallel()
    end_time = datetime.now()
    return {"start_time":start_time, "end_time":end_time, "results":results}

@app.get("/async-sleep")
async def async_sleep():
    start_time = datetime.now()
    results = await _async_sleep(1,6)
    end_time = datetime.now()
    return {"start_time":start_time, "end_time":end_time, "results":results}


@app.get("/asyncio-sleep")
async def asyncio_sleep():
    start_time = datetime.now()
    results = await asyncio.sleep(6)
    end_time = datetime.now()
    return {"start_time":start_time, "end_time":end_time, "results":results}

 

  • 앱 띄우는 방법 : uvicorn main:app --port 8000
  • 브라우저에서 스웨거 접속하는 방법 : http://localhost:8000/docs
  • 동시처리 API 응답 : async-asyncio-sleep API 호출 시 6초짜리 time sleep 함수 5개를 3개 / 2개 비동기처리하여 약 12초만에 응답 받음
{
  "start_time": "2024-02-26T22:36:15.098960",
  "end_time": "2024-02-26T22:36:27.101120",
  "results": [
    "hehe 1",
    "hehe 2",
    "hehe 3",
    "hehe 4",
    "hehe 5"
  ]
}

 

  • 비동기처리 앱 로그 : async-asyncio-sleep API 처리 중 다른 API 요청 처리됨
INFO:     Application startup complete.
start sleep 2024-02-26 22:46:12.735016
start sleep 2024-02-26 22:46:12.735016
start sleep 2024-02-26 22:46:12.736013
/async 2024-02-26 22:46:14.222185
INFO:     127.0.0.1:55682 - "GET /async HTTP/1.1" 200 OK
/ 2024-02-26 22:46:16.353565
INFO:     127.0.0.1:55682 - "GET / HTTP/1.1" 200 OK
end sleep 2024-02-26 22:46:18.739985
end sleep 2024-02-26 22:46:18.740557
end sleep 2024-02-26 22:46:18.741149
start sleep 2024-02-26 22:46:18.741675
start sleep 2024-02-26 22:46:18.741675
/async 2024-02-26 22:46:20.443945
INFO:     127.0.0.1:55682 - "GET /async HTTP/1.1" 200 OK
/ 2024-02-26 22:46:23.335636
INFO:     127.0.0.1:55682 - "GET / HTTP/1.1" 200 OK
end sleep 2024-02-26 22:46:24.738253
end sleep 2024-02-26 22:46:24.738253
INFO:     127.0.0.1:55681 - "GET /async-asyncio-sleep HTTP/1.1" 200 OK

 

참고 : 개발환경 라이브러리 버전

annotated-types==0.6.0
anyio==4.3.0
click==8.1.7
colorama==0.4.6
fastapi==0.110.0
h11==0.14.0
idna==3.6
pydantic==2.6.2
pydantic_core==2.16.3
sniffio==1.3.1
starlette==0.36.3
typing_extensions==4.10.0
uvicorn==0.27.1
728x90

'Python > Web' 카테고리의 다른 글

FastAPI 개발자가 직접 개발한 FastAPI backend 프로젝트 구조  (0) 2024.03.03
WSGI와 ASGI 단순 비교  (0) 2024.02.28
FastAPI 비동기 처리  (1) 2024.02.26
[windows] nginx 프록시 설정 방법  (0) 2022.11.01
nginx 기초  (0) 2022.10.25
728x90

포트 설정

컨테이너 외부에서 도커 컨테이너 내부로 접속할 수 있도록 포트포워딩 설정 필요 (-p 옵션)

docker run -p {host port number}:{container port number} ...

 

서비스 호스트 확인

컨테이너 외부에서도 접속할 수 있도록 호스트 IP 0.0.0.0으로 설정 필요

- 0.0.0.0은 도커 컨테이너가 호스트의 모든 IP 주소에 바인딩되도록 설정하는 것

- localhost는 도커 컨테이너 내부에서 자기 자신을 참조하는 데 사용되는 호스트 이름

# fastapi 실행 예시
uvicorn main:app --host 0.0.0.0 --port 5000 --reload
728x90

'Docker' 카테고리의 다른 글

docker 컨테이너에 환경변수 설정하는 방법  (1) 2024.06.09
728x90

인스턴스 속성 (Instance Attribute)

- 인스턴스 속성은 클래스의 각 인스턴스마다 개별적으로 유지되는 속성

- 각 인스턴스는 자체 인스턴스 속성을 가지고 있으며, 인스턴스마다 값이 다를 수 있음

- 인스턴스 메서드 내에서 'self'를 사용하여 인스턴스 속성에 접근하고 수정할 수 있음

- 인스턴스 속성은 해당 클래스 각각의 인스턴스에 대해 독립적임

- 예시

class MyClass:
    def __init__(self):
        self.instance_attribute = 10  # 인스턴스 속성

obj1 = MyClass()
obj1.instance_attribute = 20  # obj1의 인스턴스 속성을 수정
obj2 = MyClass()
print(obj1.instance_attribute)  # 출력: 20
print(obj2.instance_attribute)  # 출력: 10 (기본값)

 

클래스 속성 (Clase Attribute)

- 클래스 속성은 클래스에 속하는 속성으로, 해당 클래스의 모든 인스턴스가 공유하는 속성

- 클래스 정의 내부에서 클래스 변수로 선언되며, 모든 인스턴스가 동일한 값을 공유

- 클래스 속성은 클래스 자체와 관련이 있으며, 해당 클래스의 모든 인스턴스에서 동일한 값을 공유

- 클래스 메서드 내에서 'cls'를 사용하여 클래스 속성에 접근하고 수정할 수 있음

- 예시

class MyClass:
    class_attribute = 10  # 클래스 속성

obj1 = MyClass()
obj2 = MyClass()
print(obj1.class_attribute)  # 출력: 10
print(obj2.class_attribute)  # 출력: 10

MyClass.class_attribute = 20  # 클래스 속성 수정
print(obj1.class_attribute)  # 출력: 20 (수정된 값)
print(obj2.class_attribute)  # 출력: 20 (수정된 값)
728x90
728x90

인스턴스 속성, 클래스 속성

인스턴스 메서드 (Instance Method)

- 인스턴스 메서드는 클래스의 인스턴스에 의해 호출되는 메서드

- 첫 번째 매개변수로 'self'를 사용하여 현재 인스턴스에 대한 참조를 전달

- 인스턴스 속성에 접근하고 수정하는데 사용됨

- 인스턴스 메서드는 'self'를 통해 인스턴스의 상태를 변경하거나 인스턴스의 속성에 접근 가능

class MyClass:
    def __init__(self):
        self.some_property = 1
        
    def instance_method(self, some_int):
        # 인스턴스 속성에 접근
        self.some_property = some_int

 

정적 메서드 (Static Method)

- 정적 메서드는 특정 클래스와 관련이 있는 동작을 수행하지만, 인스턴스나 클래스에 대한 참조를 받지 않는 메서드

- '@staticmethod' 데코레이터를 사용하여 정적 메서드임을 나타냄

- 정적 메서드는 클래스의 인스턴스 속성에 접근 가능

- 정적 메서드는 주로 클래스와 관련된 유틸리티 함수를 구현하는 데 사용

class MyClass:
    @staticmethod
    def static_method():
        # 클래스의 인스턴스 속성에 접근 불가능
        # some_property = 10 불가능
        # 클래스와 관련된 동작 수행
        pass

클래스 메서드 (Class Method)

- 클래스 메서드는 클래스 레벨에서 호출되지만, 인스턴스에 대한 참조를 받지 않고, 클래스 자체에 대한 참조를 받음

- 첫 번째 매개변수로 'cls'를 사용하여 현재 클래스에 대한 참조를 전달

- 클래스 속성에 접근하고 수정하는데 사용됨

- 클래스 메서드는 'cls'를 통해 클래스 속성을 변경하거나 접근 가능

class MyClass:
    some_class_property = 1
    
    def class_method(cls):
        # 클래스 속성에 접근
        cls.some_class_property = 10
        # 클래스 속성 변경
        cls.some_class_method()

 

 

728x90
728x90

공백

- 스페이스로 들여쓰기 (탭, 공백 혼합 금지)

- 들여쓰기는 스페이스 네 개 사용

- 한 줄의 문자 길이 79자 이하

- 표현식이 길어 다음 줄로 내려쓰는 경우 추가 들여쓰기 사용

- 파일에서 함수와 클래스는 빈 줄 두 개로 구분, 클래스에서 메서드는 빈 줄 하나로 구분

class MyClass:
    def __init__(self):
        self.data = []

    def my_method(self):
        # Some code here
        pass


def my_function():
    # Some code here
    pass

- 리스트 인덱스, 함수 호출, 키워드 인수 할당에는 스페이스 사용하지 않음

- 할당( = ), 증분 할당( +=, -= 등), 비교( ==<>!=<><=>=innot inisis not), Booleans (andornot)과 같은 이항 연산자는 항상 양쪽에 하나의 공백으로 둘러쌈 ( i = i + 1, c = (a+b) * (a-b) )

- 불필요한 공백 사용하지 않음

 

명명규칙

- 함수, 변수, 속성은 lowercase_underscore 형식

- 보호 인스턴스 속성은 _leading_underscore 형식

- 비공개 인스턴스 속성은 __double_leading_underscore 형식

- 클래스와 예외는 CapitalizedWord 형식

- 모듈 수준 상수는 ALL_CAPS 형식

- 클래스의 인스턴스 메서드(instance method)에서는 첫 번째 파라미터(해당 객체 참조)의 이름을 self로 지정

- 클래스 메서드(class method)에서는 첫 번째 파라미터(해당 객체 참조)의 이름을 cls로 지정

 

표현식과 문장

- 긍정 표현의 부정(if not a is b) 대신 인라인 부정(if a is not b) 사용

- 길이를 확인하여 빈 값을 확인하지 않음 (if len(somelist)==0)

  if not somelist를 사용하고, 빈 값은 암시적으로 False가 된다고 가정

- 길이를 확인하여 비어있지 않은 값을 확인하지 않음 (if len(somelist)!=0)

  if somelist를 사용하고, 비어있지 않은 값은 암시적으로 True가 된다고 가정

- 한 줄로 된 if 문, for와 while 루프, except 복합문을 쓰지 말고 여러 줄로 나눠서 명료하게 작성

 

임포트 규칙

- 항상 파일의 맨 위에 import 문을 놓음

- 모듈을 import 할 때는 항상 모듈의 절대 이름을 사용하며 현대 모듈의 경로를 기준으로 상대 경로로 된 이름을 사용하지 않음

  예를들어 bar 패키지 안의 foo 모듈을 임포트할 때는 import foo 가 아닌 from bar import foo 라고 해야함

- 상대적인 임포트를 해야 한다면 명시적인 구문을 써서 from . import foo 로 작성

- 임포트는 '표준 라이브러리 모듈, 서브파티 모듈, 자신이 만든 모듈' 섹션 순으로 구분해야 함

  각각의 하위 섹션에서는 알파벳 순서로 임포트

 

참고 사이트

- https://peps.python.org/pep-0008/

 

 

728x90
728x90

RDB

  • 개념
    • 데이터를 row와 column으로 이루어진 table의 형태의 데이터를 저장
    • 데이터가 테이블(table)에 레코드(record)로 저장되며, 각 테이블에는 명확한 구조(structure)가 존재하여 스키마를 준수하지 않는 레코드 추가할 수 없음
    • SQL(Structured Query Language)을 사용해서 데이터를 관리 및 접근함 (읽기/쓰기/수정)
  • 장점
    • 데이터의 분류, 정렬, 탐색 속도가 빠름
    • 신뢰성이 높고 데이터의 무결성을 보장
    • 관계를 통해 각 데이터를 중복없이 한 번만 저장함
    • 데이터베이스를 추가하기 전에 유효성 검사를 통해 데이터 품질을 향상시킬 수 있음
    • VIEW를 이용한 보안 설정이 가능하기 때문에 허가받지 않는 사용자들로부터 데이터의 조회/변경/삭제 방지 가능
  • 단점
    • 기존에 작성된 스키마의 수정이 어려움
    • 관계를 맺고 있기 때문에 복잡한 JOIN 쿼리를 사용해야 함
    • 데이터베이스의 부하 분석이 어려움
    • 수평적 확장이 어렵고 대체로 수직적 확장만 가능하여 데이터 처리량 성장에 한계가 있음
  • 예시
    • Oracle, DB2, SQL Server, MySQL, PostgreSQL

NoSQL

  • 개념
    • NoSQL(Not Only SQL) 이라고도 부름
    • 관계형 데이터베이스의 한계를 극복하기 위해 만들어진 새로운 형태의 데이터베이스로, 융통성있는 데이터 모델을 사용
    • 데이터의 저장 및 검색에 특화된 메커니즘 제공
    • 분산환경에서 데이터 처리를 더욱 빠르게 하기 위해 개발됨
  • 장점
    • 스키마가 없어 유연성이 높음 (저장한 데이터를 조정하거나 새로운 필드 추가 가능)
    • 한 테이블에 모든 것을 갖춘 문서를 만들어 복잡한 조인문으로 작업할 필요가 없음
    • 자주 바뀌지 않는 데이터인 경우 편리, 애플리케이션에 필요한 형식으로 저장되어 데이터 읽는 속도가 빠름
    • 수직 및 수평 확장이 가능하므로 데이터베이스가 애플리케이션에서 발생시키는 모든 읽기/쓰기 요청의 처리가 가능
  • 단점
    • 문서 저장이 단위 요소 수준에서 세밀한 보안을 제공하지 않음
    • NoSQL마다 쿼리 언어가 다른 경우가 많아 이식성이 낮음
    • 조인이 없어 컬렉션마다 데이터를 복제하여 각 컬렉션 일부분에 속하는 데이터를 생성함 > 데이터의 업데이트가 필요한 경우 특정 데이터를 함께 사용하는 모든 컬렉션에서 수행되도록 주의 필요
  • 분류
    • Key-Value
      • key-value pair로 데이터를 저장
      • key는 unique identifier로도 사용됨
      • 값은 어떠한 형태의 데이터라도 담을 수 있음 (이미지, 비디오 등 가능)
      • Redis, Memcached 등이 해당
      • 활용
        • 간단한 데이터모델을 대상으로 데이터를 자주 읽고 쓰는 경우에 적합
        • 성능 향상을 위해 관계형 데이터베이스에서 데이터 캐싱
        • 모바일 애플리케이션용 사용자 데이터 정보와 구성정보 저장
        • 이미지와 오디오 파일 같은 대용량 객체 저장
    • Graph
      • 데이터를 graph의 형태로 저장
      • 각 항목이 node로 이루어져있고, node간의 관계는 edge를 사용해서 나타냄
      • Neo4j, OrientDB등이 해당
      • 활용
        • SNS등 서로 관계가 복잡한 상황에서 자주 사용됨 (링크드인 - 1촌, 2촌)
    • Document
      • key와 Document의 형태로 저장 (Key-Value 모델과 다른 점: Value가 계층적 형태인 도큐먼트로 저장)
      • row, column과 같은 구조는 없고 일반적으로 JSON 또는 XML 형태로 데이터를 저장
      • 값을 저장하기 전에 schema를 정의하지 않으며, 문서를 추가하면 schema가 됨
      • 각 문서 별로 다른 필드를 가질 수 있기 때문에 애플리케이션에서 데이터 입력 과정에서 컬럼과 필드의 관리를 해주어야함
      • 데이터베이스별로 데이터를 조작할 수 있는 언어가 따로 있음 (Xquery나 다른 도큐먼트 질의 언어)
      • MongoDB, CassandraDB, MarkLogic 등이 해당
      • 활용
        • 블로그 포스트와 같이 형식이 자유로워야 할 때 사용
        • 대용량 데이터를 읽고 쓰는 웹사이트용 백엔드 지원
        • 제품처럼 다양한 속성이 있는 데이터 관리
        • 다양한 유형의 메타데이터 추적
    • Column-family
      • 키는 Row(키 값)와 Column-family, Column-name을 가짐
      • 미리 정의된 스키마를 사용하지 않으므로 컬럼 추가 가능
      • 연관된 데이터들은 같은 Column-family 안에 속해 있으며, 각자의 Column-name을 가짐
      • 이렇게 저장된 데이터는 하나의 커다란 테이블로 표현이 가능
      • Schema-less이긴 하지만 새로운 필드를 만드는 데 드는 비용이 크기 때문에 사실상 결정된 스키마를 변경하는 것이 어려움
      • 컬럼-패밀리 모델은 클러스터링이 쉽게 이뤄지며, Time stamp가 존재해 값이 수정된 히스토리를 알 수 있음
      • 값들은 일련의 바이너리 데이터로 존재하기 때문에 어떤 형태의 데이터라도 저장될 수 있음
      • Blob 단위의 쿼리가 불가능하며, Row와 Column의 초기 디자인이 중요 (테이블 간 조인을 지원하지 않음)
      • 질의는 Row, Column-family, Column-name을 통해 수행
      • HBase, Cassandra, Hypertable 등이 해당
      • 활용
        • 여러 대로 구성된 클러스터에서 운영 (단일서버로 운영해도 될 만큼 데이터가 적다면 document나 key-value DB가 유리함)
        • 쓰기 작업이 많은 경우
        • 복제본 데이터가 단기적으로 불일치하더라도 큰 문제가 없는 경우
        • 동적 필드를 처리하는 경우

RDB vs NoSQL

  • 관계형 데이터베이스는 관련 데이터를 동일한 테이블에 동일한 구조로 저장해야함 vs 비관계형 데이터베이스도 관련 데이터를 동일한 컬렉션에 넣으나, 다른 구조의 데이터를 같은 컬렉션에 추가 가능
  • 관계형 데이터베이스 사용이 유리한 경우 :
    • 어플리케이션의 여러 부분에서 관련 데이터가 비교적 자주 변경되는 경우
  • 비관계형 데이터베이스 사용이 유리한 경우 :
    • 정확한 데이터 요구사항을 알 수 없는 경우
    • 읽기 처리를 자주 하고, 관계를 맺고 있는 데이터가 자주 변경되지 않는 경우
    • 데이터베이스를 수평으로 확장해야 하는 경우 (대량의 데이터를 다뤄야 하는 경우, 읽기/쓰기 처리량이 큰 경우)
728x90

'DataBase' 카테고리의 다른 글

데이터베이스의 원칙  (0) 2023.02.21

+ Recent posts