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

Почему нельзя установить 100000 соединений с БД?

2.0 Middle🔥 81 комментариев
#DevOps и инфраструктура#Базы данных (SQL)

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

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

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

Почему нельзя установить 100000 соединений с БД

Установка 100 тысяч соединений с БД невозможна или непрактична по нескольким причинам, связанным с ресурсами операционной системы и самой СУБД.

1. Ограничение операционной системы (файловые дескрипторы)

Каждое соединение требует файлового дескриптора (file descriptor). ОС имеет лимиты:

# Проверить лимит пользователя
ulimit -n  # Обычно 1024 или 4096

# Проверить системный лимит
cat /proc/sys/fs/file-max  # Может быть 2097152 на сервере

# Увеличить лимит (требует sudo)
ulimit -n 100000  # Временно

# Постоянно в /etc/security/limits.conf
# * soft nofile 100000
# * hard nofile 100000
import resource

# Проверить текущий лимит
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print(f"Soft: {soft}, Hard: {hard}")

# Попытка увеличить
try:
    resource.setrlimit(resource.RLIMIT_NOFILE, (100000, hard))
except (ValueError, PermissionError) as e:
    print(f"Ошибка: {e}")

2. Ограничения PostgreSQL

PostgreSQL имеет встроенные ограничения:

-- Просмотр текущего лимита
SHOW max_connections;
-- По умолчанию: 100

-- Максимум, что можно установить
SET max_connections = 10000;

-- На каждое соединение требуется память
-- ~600KB на соединение (shared_buffers + рабочая память)
import psycopg2
import concurrent.futures

def try_connect(conn_id):
    """Попытка создать соединение"""
    try:
        conn = psycopg2.connect(
            host="localhost",
            database="mydb",
            user="postgres",
            password="password",
            timeout=2
        )
        # Соединение откроется, но будут ошибки
        conn.close()
        return True
    except psycopg2.OperationalError as e:
        return False

# Попытка открыть 1000 соединений
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
    results = list(executor.map(try_connect, range(1000)))
    
successful = sum(1 for r in results if r)
print(f"Успешных: {successful}/1000")  # Вероятно меньше 100

3. Память на сервере БД

Каждое соединение потребляет памяти на БД:

PostgreSQL: ~600KB per connection
MySQL: ~1-2MB per connection
MongoDB: ~1MB per connection

Для 100K соединений:
100,000 * 0.6MB = 60GB памяти (только на соединения!)
-- Расчёт памяти в PostgreSQL
SELECT 
    (SELECT setting::int FROM pg_settings WHERE name=max_connections) as max_conns,
    (SELECT setting::int FROM pg_settings WHERE name=shared_buffers) / 1024 as shared_buffers_mb
    
-- На 100K соединений:
-- max_connections = 100000
-- shared_buffers * max_connections = ОЧЕНЬ МНОГО памяти

4. Сетевые ограничения

# Лимит на количество открытых портов
# Обычно: 65535 (2^16 - 1) портов

# При127.0.0.1:* можно открыть максимум 65535 соединений
# На разных IP может быть больше

# Проверить текущие соединения
netstat -an | grep ESTABLISHED | wc -l

5. Производительность обработки

Даже если открыть 100K соединений, БД не сможет их эффективно обработать:

import psycopg2
import time

# Измерение нагрузки
connections = []
start = time.time()

for i in range(100):
    try:
        conn = psycopg2.connect(
            host="localhost",
            database="mydb",
            user="postgres",
            password="password"
        )
        connections.append(conn)
    except psycopg2.OperationalError:
        print(f"Не удалось подключиться после {i} соединений")
        break

elapsed = time.time() - start
print(f"Открыто {len(connections)} соединений за {elapsed:.2f}s")
print(f"Память БД заполнена на {len(connections) * 0.6}MB")

# Закрытие
for conn in connections:
    conn.close()

6. Правильный подход: Connection pooling

Вместо создания 100K соединений используй пулинг:

from psycopg_pool import ConnectionPool
import asyncio

# Пул из 20 переиспользуемых соединений
async def main():
    async with await ConnectionPool.connect(
        "postgresql://user:password@localhost/mydb",
        min_size=5,
        max_size=20  # Максимум 20 активных соединений
    ) as apool:
        # Обслуживание 10000 параллельных запросов
        async with apool.connection() as conn:
            result = await conn.execute("SELECT 1")
            print(result)

# Или с SQLAlchemy
from sqlalchemy import create_engine

engine = create_engine(
    "postgresql://user:password@localhost/mydb",
    pool_size=20,  # Количество соединений в пуле
    max_overflow=10,  # Дополнительные временные соединения
    pool_recycle=3600  # Переиспользовать каждый час
)

7. Мониторинг текущих соединений

# Проверить текущие соединения в PostgreSQL
SELECT COUNT(*) FROM pg_stat_activity;

# Найти долгие запросы
SELECT pid, usename, state, query, query_start FROM pg_stat_activity
WHERE state != idle
ORDER BY query_start DESC;

# Завершить лишние соединения
SELECT pg_terminate_backend(pid) FROM pg_stat_activity
WHERE pid <> pg_backend_pid() AND usename = myuser;

8. Практическая рекомендация

import psycopg_pool

# Оптимальная конфигурация
class DatabaseConfig:
    # Для приложения с 10 рабочих (gunicorn)
    POOL_SIZE = 10  # 1 соединение на рабочего
    MAX_OVERFLOW = 5  # Запас на пиковые нагрузки
    POOL_RECYCLE = 3600  # Переиспользовать каждый час
    
    # Это даст максимум 15 соединений при пиковой нагрузке
    # Вместо 100K

async_engine = create_engine(
    "postgresql://...",
    pool_size=DatabaseConfig.POOL_SIZE,
    max_overflow=DatabaseConfig.MAX_OVERFLOW,
    pool_recycle=DatabaseConfig.POOL_RECYCLE
)

Итоговые выводы

ПроблемаОграничениеРешение
Файловые дескрипторы ОС1024-4096 по умолчаниюУвеличить ulimit
Лимит БД100 соединений по умолчаниюУвеличить max_connections
Память сервера600KB на соединениеConnection pooling
ПроизводительностьНевозможно обработать все параллельноИспользовать пул из 20-50 соединений
Порты65535 портов максимумРазные IP адреса

Правильный подход: использовать 20-50 переиспользуемых соединений через пулинг вместо попытки открыть 100K. Это даст лучшую производительность и стабильность.