본 글은 Claude Sonnet 4로 작성한 글입니다.
NoSQL이란?
NoSQL은 "Not Only SQL"의 줄임말로, 전통적인 관계형 데이터베이스가 아닌 데이터베이스 시스템을 의미한다. 관계형 데이터베이스가 테이블과 행, 열로 구성된 구조화된 데이터를 다룬다면, NoSQL은 더 유연한 데이터 구조를 지원한다.
NoSQL의 주요 특징
NoSQL 데이터베이스는 다음과 같은 특징을 가진다:
- 스키마 자유로움: 미리 정의된 스키마 없이 데이터를 저장할 수 있다
- 수평 확장: 서버를 추가하여 성능을 향상시키기 쉽다
- 대용량 데이터 처리: 빅데이터 환경에 적합하다
- 다양한 데이터 타입: JSON, XML 등 다양한 형태의 데이터를 저장할 수 있다
NoSQL 데이터베이스 유형
NoSQL 데이터베이스는 크게 네 가지로 분류된다:
- Document Store: MongoDB, CouchDB
- Key-Value Store: Redis, DynamoDB
- Column Family: Cassandra, HBase
- Graph Database: Neo4j, ArangoDB
MongoDB 소개
MongoDB는 가장 인기 있는 Document Store 타입의 NoSQL 데이터베이스다. JSON과 유사한 BSON(Binary JSON) 형태로 데이터를 저장하며, 스키마가 없어 개발 초기 단계에서 데이터 구조를 자주 변경해야 할 때 매우 유용하다.
MongoDB의 장점
- 개발 속도: 스키마 설계에 시간을 들이지 않고 빠르게 개발할 수 있다
- 확장성: 샤딩을 통해 수평 확장이 용이하다
- 유연성: 복잡한 중첩 구조의 데이터를 자연스럽게 표현할 수 있다
- 인덱싱: 다양한 인덱스 타입을 지원하여 쿼리 성능을 최적화할 수 있다
MongoDB 설치하기
Linux (Ubuntu/Debian)
# MongoDB GPG 키 추가
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
# MongoDB 저장소 추가
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
# 패키지 목록 업데이트 및 설치
sudo apt-get update
sudo apt-get install -y mongodb-org
# MongoDB 서비스 시작
sudo systemctl start mongod
sudo systemctl enable mongod
macOS
# Homebrew를 사용한 설치
brew tap mongodb/brew
brew install mongodb-community
# MongoDB 서비스 시작
brew services start mongodb-community
Windows
MongoDB 공식 웹사이트에서 Windows Installer를 다운로드하여 설치한다. 설치 후 MongoDB Compass GUI 도구도 함께 설치된다.
Python으로 MongoDB 사용하기
pip install pymongo
기본 연결 및 Key-Value 데이터 저장
MongoDB에서 Key-Value 형태의 데이터는 필드-값 쌍으로 저장된다. 다음은 기본적인 사용 예제다:
from pymongo import MongoClient
from datetime import datetime
import json
# MongoDB 연결
client = MongoClient('mongodb://localhost:27017/')
# 데이터베이스 선택 (없으면 자동 생성)
db = client['my_database']
# 컬렉션 선택 (테이블과 유사한 개념)
collection = db['key_value_store']
# Key-Value 데이터 저장
def store_key_value(key, value):
"""키-값 쌍을 MongoDB에 저장"""
document = {
'key': key,
'value': value,
'created_at': datetime.now(),
'updated_at': datetime.now()
}
# 기존 키가 있으면 업데이트, 없으면 삽입
result = collection.replace_one(
{'key': key},
document,
upsert=True
)
if result.upserted_id:
print(f"새로운 키-값 저장됨: {key} = {value}")
else:
print(f"기존 키-값 업데이트됨: {key} = {value}")
# Key-Value 데이터 조회
def get_value(key):
"""키에 해당하는 값을 조회"""
document = collection.find_one({'key': key})
if document:
return document['value']
else:
return None
# Key-Value 데이터 삭제
def delete_key(key):
"""키-값 쌍을 삭제"""
result = collection.delete_one({'key': key})
if result.deleted_count > 0:
print(f"키 삭제됨: {key}")
return True
else:
print(f"키를 찾을 수 없음: {key}")
return False
# 모든 키 목록 조회
def list_all_keys():
"""저장된 모든 키 목록을 반환"""
keys = []
for document in collection.find({}, {'key': 1, '_id': 0}):
keys.append(document['key'])
return keys
# 사용 예제
if __name__ == "__main__":
# 다양한 타입의 값 저장
store_key_value("user:1001", {"name": "김철수", "age": 25, "email": "kim@example.com"})
store_key_value("config:max_users", 1000)
store_key_value("cache:popular_items", ["laptop", "mouse", "keyboard"])
store_key_value("session:abc123", {"user_id": 1001, "login_time": "2024-01-15T10:30:00"})
# 값 조회
user_data = get_value("user:1001")
print(f"사용자 데이터: {user_data}")
max_users = get_value("config:max_users")
print(f"최대 사용자 수: {max_users}")
# 존재하지 않는 키 조회
unknown_value = get_value("unknown_key")
print(f"존재하지 않는 키의 값: {unknown_value}")
# 모든 키 목록 출력
all_keys = list_all_keys()
print(f"저장된 모든 키: {all_keys}")
# 키 삭제
delete_key("cache:popular_items")
# 연결 종료
client.close()
복합 쿼리 예제
MongoDB의 강력한 쿼리 기능을 활용한 예제다:
# 특정 패턴의 키들만 조회
def get_keys_by_pattern(pattern):
"""정규표현식 패턴으로 키를 조회"""
import re
regex_pattern = re.compile(pattern)
documents = collection.find({'key': regex_pattern})
result = {}
for doc in documents:
result[doc['key']] = doc['value']
return result
# 최근 생성된 키-값 쌍들 조회
def get_recent_entries(limit=10):
"""최근 생성된 항목들을 조회"""
documents = collection.find().sort('created_at', -1).limit(limit)
result = []
for doc in documents:
result.append({
'key': doc['key'],
'value': doc['value'],
'created_at': doc['created_at']
})
return result
# 사용 예제
user_keys = get_keys_by_pattern(r'^user:')
print(f"사용자 관련 키들: {user_keys}")
recent_entries = get_recent_entries(5)
print(f"최근 5개 항목: {recent_entries}")
실전 활용 시나리오
1. 세션 저장소
웹 애플리케이션의 사용자 세션을 저장하는 용도로 활용할 수 있다:
def store_session(session_id, user_data, expire_minutes=30):
"""사용자 세션을 저장"""
from datetime import timedelta
expire_time = datetime.now() + timedelta(minutes=expire_minutes)
session_document = {
'key': f"session:{session_id}",
'value': user_data,
'created_at': datetime.now(),
'expires_at': expire_time
}
collection.replace_one(
{'key': f"session:{session_id}"},
session_document,
upsert=True
)
# 세션 저장 예제
store_session("abc123", {
"user_id": 1001,
"username": "john_doe",
"roles": ["user", "admin"]
})
2. 캐시 시스템
자주 조회되는 데이터를 캐싱하는 용도로 사용할 수 있다:
def cache_data(cache_key, data, ttl_seconds=3600):
"""데이터를 캐시에 저장"""
from datetime import timedelta
expire_time = datetime.now() + timedelta(seconds=ttl_seconds)
cache_document = {
'key': f"cache:{cache_key}",
'value': data,
'created_at': datetime.now(),
'expires_at': expire_time
}
collection.replace_one(
{'key': f"cache:{cache_key}"},
cache_document,
upsert=True
)
def get_cached_data(cache_key):
"""캐시에서 데이터 조회"""
document = collection.find_one({'key': f"cache:{cache_key}"})
if document and document.get('expires_at', datetime.now()) > datetime.now():
return document['value']
elif document:
# 만료된 캐시 삭제
collection.delete_one({'key': f"cache:{cache_key}"})
return None
성능 최적화 팁
인덱스 생성
자주 조회되는 키에 대해 인덱스를 생성하면 조회 성능이 크게 향상된다:
# 키 필드에 인덱스 생성
collection.create_index('key', unique=True)
# 복합 인덱스 생성 (키와 생성시간)
collection.create_index([('key', 1), ('created_at', -1)])
# 인덱스 확인
indexes = collection.list_indexes()
for index in indexes:
print(f"인덱스: {index}")
배치 처리
여러 개의 키-값을 한 번에 처리할 때는 배치 연산을 사용한다:
def store_multiple_key_values(key_value_pairs):
"""여러 키-값 쌍을 배치로 저장"""
operations = []
current_time = datetime.now()
for key, value in key_value_pairs.items():
document = {
'key': key,
'value': value,
'created_at': current_time,
'updated_at': current_time
}
operations.append(
pymongo.ReplaceOne(
{'key': key},
document,
upsert=True
)
)
# 배치 실행
result = collection.bulk_write(operations)
print(f"배치 처리 완료: {result.bulk_api_result}")
# 사용 예제
batch_data = {
"config:app_name": "My Application",
"config:debug_mode": False,
"config:max_connections": 100,
"config:timeout": 30
}
store_multiple_key_values(batch_data)
MongoDB를 Key-Value 저장소로 활용하면 관계형 데이터베이스보다 훨씬 유연하고 빠른 데이터 저장이 가능하다. 특히 스키마가 자주 변경되는 개발 환경이나, 대용량의 비정형 데이터를 다룰 때 그 진가를 발휘한다.
다음 단계로는 MongoDB의 집계(Aggregation) 파이프라인이나 샤딩(Sharding) 기능을 학습하면 더 고급 활용이 가능하다. MongoDB의 강력한 기능들을 차근차근 익혀가며 프로젝트에 적용해보자.