← Назад к вопросам

Как масштабировать NoSQL БД?

2.8 Senior🔥 71 комментариев
#Базы данных (NoSQL)

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Масштабирование NoSQL БД

Масштабирование NoSQL баз данных — критически важная тема для разработки высоконагруженных систем. NoSQL имеет свои особенности, отличающие его от реляционных БД.

Типы масштабирования

1. Вертикальное масштабирование (Vertical Scaling)

Увеличение ресурсов на одной машине (CPU, RAM, диск):

Преимущества:

  • Простота реализации
  • Меньше сложности с синхронизацией

Недостатки:

  • Есть физический предел
  • Дорого
  • Downtime при обновлении
# Это касается инфраструктуры, а не кода
# Просто добавляем больше ресурсов к серверу БД

2. Горизонтальное масштабирование (Horizontal Scaling)

Распределение данных между несколькими машинами — основной подход NoSQL:

Преимущества:

  • Линейный рост производительности
  • Отказоустойчивость
  • Нет физических ограничений

Стратегии горизонтального масштабирования

1. Sharding (Шардирование)

Раздача данных на основе ключа:

from hashlib import md5

class ShardingStrategy:
    def __init__(self, num_shards: int):
        self.num_shards = num_shards
    
    def get_shard_id(self, user_id: str) -> int:
        """Определяет номер шарда по ID пользователя"""
        hash_value = int(md5(user_id.encode()).hexdigest(), 16)
        return hash_value % self.num_shards

# Использование
sharding = ShardingStrategy(num_shards=4)
shard_id = sharding.get_shard_id("user_123")
print(f"Направить в шард {shard_id}")

Типы шардирования:

  • Range-based — по диапазонам значений
  • Hash-based — по хешу ключа
  • Directory-based — по таблице маршрутизации
  • Geographic — по географическому расположению
class RangeSharding:
    """Шардирование по диапазонам"""
    
    def get_shard(self, user_id: int) -> int:
        if 0 <= user_id < 1000000:
            return 0
        elif 1000000 <= user_id < 2000000:
            return 1
        elif 2000000 <= user_id < 3000000:
            return 2
        else:
            return 3

2. Репликация (Replication)

Копирование данных на несколько узлов для надёжности и производительности:

# MongoDB репликация (в YAML конфиге)
# rs.initiate({
#   _id: "rs0",
#   members: [
#     { _id: 0, host: "primary:27017" },
#     { _id: 1, host: "secondary1:27017" },
#     { _id: 2, host: "secondary2:27017" }
#   ]
# })

from pymongo import MongoClient
from pymongo.errors import ConnectionFailure

client = MongoClient(
    'mongodb://primary:27017,secondary1:27017,secondary2:27017',
    replicaSet='rs0',
    readPreference='secondaryPreferred'  # Читаем с replica
)
db = client['myapp']

Типы репликации:

  • Master-Slave — один мастер, много реплик (read-only)
  • Master-Master — несколько мастеров (конфликты)
  • Multi-Master — продвинутая синхронизация

3. Партиционирование (Partitioning)

Разделение данных по логическим критериям:

class PartitionedDataStore:
    def __init__(self):
        self.partitions = {
            'active_users': {},
            'inactive_users': {},
            'archived_users': {}
        }
    
    def store_user(self, user_id: str, user_data: dict):
        partition = self._get_partition(user_data)
        self.partitions[partition][user_id] = user_data
    
    def _get_partition(self, user_data: dict) -> str:
        if user_data.get('last_login_days', float('inf')) < 7:
            return 'active_users'
        elif user_data.get('last_login_days', float('inf')) < 30:
            return 'inactive_users'
        else:
            return 'archived_users'

Популярные NoSQL БД и их подходы

MongoDB

from pymongo import MongoClient
from pymongo.errors import DuplicateKeyError

client = MongoClient('mongodb://localhost:27017')
db = client['myapp']

# Sharding ключ
db.command('enableSharding', 'myapp')
db.command('shardCollection', 'myapp.users', 
           key={'user_id': 1})  # user_id — shard key

Redis Cluster

import redis
from redis.cluster import RedisCluster

# Подключение к Redis Cluster
rc = RedisCluster(
    startup_nodes=[
        {"host": "node1", "port": 6379},
        {"host": "node2", "port": 6379},
        {"host": "node3", "port": 6379}
    ],
    decode_responses=True
)

rc.set("user:123:name", "John")
value = rc.get("user:123:name")

Cassandra

from cassandra.cluster import Cluster

cluster = Cluster(
    contact_points=['192.168.1.1', '192.168.1.2', '192.168.1.3']
)
session = cluster.connect('my_keyspace')

# Cassandra автоматически распределяет данные
session.execute(
    'INSERT INTO users (id, name) VALUES (%s, %s)',
    ('user_123', 'John')
)

Кеширование (Caching Layer)

class CacheLayer:
    def __init__(self, cache_client, db_client):
        self.cache = cache_client
        self.db = db_client
    
    def get_user(self, user_id: str):
        # Сначала проверяем кеш
        cached = self.cache.get(f'user:{user_id}')
        if cached:
            return cached
        
        # Если нет — ищем в БД
        user = self.db.find_one({'_id': user_id})
        
        # Кешируем результат на 1 час
        self.cache.setex(f'user:{user_id}', 3600, user)
        return user

Consistency Levels

При распределённых системах появляется CAP теорема:

# MongoDB write concern (уровень консистентности)
db.users.insert_one(
    {'name': 'John'},
    write_concern={
        'w': 3,  # Подтверждение от 3 реплик
        'j': True  # Fsync на диск
    }
)

# Redis Sentinel для автофейловера
# sentinel.conf: sentinel monitor mymaster 127.0.0.1 6379 1

Best Practices

  • Выбирайте правильный shard key — равномерное распределение данных
  • Мониторьте репликацию — lag между мастером и репликами
  • Используйте Read Replicas — снижайте нагрузку на мастер
  • Backup Strategy — регулярные снимки состояния
  • Тестируйте failover — что произойдёт при отказе узла

Масштабирование NoSQL требует понимания как технологии, так и характеристик вашего приложения.

Как масштабировать NoSQL БД? | PrepBro