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

Что такое партиции в Kafka?

1.8 Middle🔥 111 комментариев
#Другое

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

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

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

Партиции в Kafka

Партиции (partitions) — это фундаментальная концепция Apache Kafka, которая позволяет масштабировать обработку событий. Они представляют собой логическое разделение топика на несколько независимых потоков данных, распределённых между брокерами Kafka.

Что такое партиция

Каждая партиция — это упорядоченная, неизменяемая последовательность событий (сообщений). Основные характеристики:

  • Упорядоченность: сообщения в партиции хранятся в порядке поступления
  • Неизменяемость: один раз записанное сообщение не может быть изменено
  • Распределённость: разные партиции могут храниться на разных брокерах
  • Индекс смещения: каждое сообщение имеет уникальный offset в своей партиции

Архитектура с партициями

"""
Топик: orders

Партиция 0 (Брокер 1):  msg0 → msg3 → msg6 → ...
                         offset: 0 → 1 → 2 → ...

Партиция 1 (Брокер 2):  msg1 → msg4 → msg7 → ...
                         offset: 0 → 1 → 2 → ...

Партиция 2 (Брокер 3):  msg2 → msg5 → msg8 → ...
                         offset: 0 → 1 → 2 → ...
"""

Как работает распределение сообщений

При отправке сообщения в топик с несколькими партициями Kafka использует ключ сообщения для определения партиции:

from kafka import KafkaProducer
import json

producer = KafkaProducer(
    bootstrap_servers=["localhost:9092"],
    value_serializer=lambda v: json.dumps(v).encode("utf-8")
)

# Случай 1: Без ключа — партиция выбирается round-robin
producer.send(
    topic="orders",
    value={"order_id": 123, "amount": 100}
)

# Случай 2: С ключом — партиция выбирается по хэшу ключа
producer.send(
    topic="orders",
    key=b"user_42",  # Все события пользователя 42 пойдут в одну партицию
    value={"order_id": 124, "amount": 200}
)

Принцип распределения по ключу

# Python пример логики выбора партиции
def get_partition(key, num_partitions):
    """Определить партицию по ключу"""
    if key is None:
        # Без ключа — round-robin или random
        return random.randint(0, num_partitions - 1)
    else:
        # С ключом — хэш ключа
        hash_value = hash(key) % num_partitions
        return hash_value

# Все сообщения с ключом "user_42" всегда попадут в одну партицию
print(get_partition("user_42", 3))  # всегда одна и та же партиция
print(get_partition("user_42", 3))  # всегда одна и та же партиция

Консъюмеры и партиции

Правило: одна партиция может обслуживаться только одним консъюмером в группе. Это гарантирует упорядоченную обработку:

from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    "orders",
    bootstrap_servers=["localhost:9092"],
    group_id="order_processors",  # Группа консъюмеров
    value_deserializer=lambda m: json.loads(m.decode("utf-8"))
)

# Если в группе 3 консъюмера и 3 партиции:
# - Консъюмер 1 получит партицию 0
# - Консъюмер 2 получит партицию 1
# - Консъюмер 3 получит партицию 2

for message in consumer:
    print(f"Партиция: {message.partition}, Offset: {message.offset}")
    print(f"Значение: {message.value}")

Преимущества партиций

1. Масштабируемость

# Без партиций: один консъюмер обрабатывает всё
# Пропускная способность ограничена одной машиной

# С 3 партициями: 3 консъюмера обрабатывают параллельно
# Пропускная способность увеличивается в 3 раза (минус overhead)

2. Сохранение порядка

# Внутри одной партиции порядок гарантирован
# Если нужен порядок для определённых данных — используй ключ

# Все заказы пользователя обрабатываются в порядке:
producer.send("orders", key=b"user_42", value={"order": 1})
producer.send("orders", key=b"user_42", value={"order": 2})
producer.send("orders", key=b"user_42", value={"order": 3})

# Консъюмер получит их в таком же порядке

3. Отказоустойчивость

"""
Каждая партиция может быть реплицирована на несколько брокеров

Лидер (leader): Брокер 1 — обрабатывает читаемые/записываемые запросы
Репликация (followers): Брокер 2, Брокер 3 — копируют данные

Если Брокер 1 упадёт, Брокер 2 или 3 станет новым лидером
"""

Управление партициями

Создание топика с партициями

# Создать топик с 3 партициями, factor репликации = 2
kafka-topics.sh --create \
  --topic orders \
  --partitions 3 \
  --replication-factor 2 \
  --bootstrap-server localhost:9092

Просмотр информации о партициях

kafka-topics.sh --describe \
  --topic orders \
  --bootstrap-server localhost:9092

Вывод:

Topic: orders
  Partition: 0    Leader: 1    Replicas: 1,2    Isr: 1,2
  Partition: 1    Leader: 2    Replicas: 2,3    Isr: 2,3
  Partition: 2    Leader: 3    Replicas: 3,1    Isr: 3,1

Offset — позиция в партиции

# Offset — это номер позиции сообщения в партиции
# Konsumer отслеживает свой текущий offset

consumer = KafkaConsumer(
    "orders",
    bootstrap_servers=["localhost:9092"],
    group_id="order_processors",
    auto_offset_reset="earliest"  # С какого offset начать
)

for message in consumer:
    # Каждый раз после обработки offset автоматически сохраняется
    print(f"Обработано: offset={message.offset}")

# Если консъюмер упадёт и перезагрузится,
# он продолжит с того же offset

Практический пример

from kafka import KafkaProducer, KafkaConsumer
import json
from threading import Thread

def produce_events():
    """Производитель отправляет события"""
    producer = KafkaProducer(
        bootstrap_servers=["localhost:9092"],
        value_serializer=lambda v: json.dumps(v).encode()
    )
    
    for user_id in range(10):
        for i in range(5):
            producer.send(
                "user_events",
                key=f"user_{user_id}".encode(),
                value={"action": f"action_{i}", "user_id": user_id}
            )

def consume_events():
    """Консъюмер обрабатывает события"""
    consumer = KafkaConsumer(
        "user_events",
        bootstrap_servers=["localhost:9092"],
        group_id="event_processors",
        value_deserializer=lambda m: json.loads(m.decode())
    )
    
    for message in consumer:
        user_data = message.value
        print(f"Партиция {message.partition}: User {user_data[user_id]} - {user_data[action]}")

# Запуск в разных потоках
Thread(target=produce_events).start()
Thread(target=consume_events).start()

Выбор количества партиций

  • Слишком мало партиций: узкое место в обработке, низкая пропускная способность
  • Слишком много партиций: увеличивает latency, потребление памяти, complexity
  • Правило: Количество партиций ≥ Количество консъюмеров

Партиции в Kafka — это ключ к масштабируемости и надёжности распределённых систем обработки данных.