Данная система предназначена для обработки событий, связанных с различными аккаунтами, с сохранением порядка обработки событий для каждого аккаунта. Система построена с использованием Redis для хранения очереди и PHP для обработки событий.
- Event: Класс, представляющий событие с идентификатором аккаунта и идентификатором события
- QueueInterface: Интерфейс, определяющий методы для работы с очередью
- RedisQueue: Реализация интерфейса очереди с использованием Redis
- EventProcessorInterface: Интерфейс, определяющий метод обработки события
- SimpleEventProcessor: Простая реализация обработчика событий с задержкой в 1 секунду
- Worker: Класс, координирующий обработку событий в режиме round-robin по аккаунтам
- События хранятся в Redis в отдельных списках для каждого аккаунта
- Система поддерживает множество активных аккаунтов (с ожидающими обработки событиями)
- Воркеры обрабатывают по одному событию от каждого активного аккаунта за один проход
- Это обеспечивает обработку событий для каждого аккаунта в правильном порядке
- Запуск нескольких процессов-воркеров параллельно (по одному на каждое ядро CPU) максимизирует пропускную способность
Ключ к ускорению этого решения — запуск нескольких процессов-воркеров параллельно. Каждый воркер независимо обрабатывает события от разных аккаунтов, но события для одного аккаунта всегда обрабатываются по порядку. Скрипт start-workers.sh запускает по одному воркеру на каждое ядро CPU для использования всех доступных вычислительных ресурсов.
Проект настроен для запуска в Docker с использованием docker-compose.
- Docker
- Docker Compose
- Клонировать репозиторий:
git clone https://github.com/ma1exe/event-queue-processor.git
cd event-queue-processor- Запустить приложение с помощью docker-compose:
docker-compose up -dЭто запустит:
- Redis контейнер для хранения очереди
- PHP контейнер для добавления событий в очередь и их обработки с несколькими воркерами
- Просмотр системных логов контейнеров:
docker-compose logs -f- Просмотр логов обработки событий:
# Просмотр всего лог-файла
cat logs/log.txt
# Просмотр в реальном времени
tail -f logs/log.txtПо умолчанию система запускает количество воркеров, равное числу ядер процессора.
Вы можете изменить это значение в docker-compose.yml:
environment:
- WORKERS_COUNT=4 # Задаем нужное количество воркеровДля удобства в проекте есть Makefile с основными командами:
# Запуск контейнеров
make up
# Остановка контейнеров
make down
# Просмотр логов контейнеров
make logs
# Просмотр логов обработки событий
make log
# Запуск тестов
make test
# Пересборка и перезапуск
make resetНастройки Redis хранятся в файле .env:
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=
- PHP 7.4 или выше
- Расширение Redis для PHP
- Redis сервер
composer install- Убедитесь, что Redis сервер запущен
- Добавьте события в очередь:
php bin/enqueue.php- Запустите обработку событий:
bash bin/start-workers.shСистема включает модульные тесты для проверки корректности работы компонентов очереди и воркера.
vendor/bin/phpunitdocker-compose exec app vendor/bin/phpunit├── bin/
│ ├── enqueue.php # Скрипт для добавления событий в очередь
│ ├── worker.php # Скрипт воркера
│ └── start-workers.sh # Скрипт для запуска нескольких воркеров
├── src/
│ ├── Event.php # Класс события
│ ├── Queue/
│ │ ├── QueueInterface.php # Интерфейс очереди
│ │ └── RedisQueue.php # Реализация очереди на Redis
│ ├── Processor/
│ │ ├── EventProcessorInterface.php # Интерфейс обработчика событий
│ │ └── SimpleEventProcessor.php # Реализация обработчика
│ ├── Utils/
│ │ └── Config.php # Утилита для загрузки конфигурации
│ └── Worker/
│ └── Worker.php # Класс воркера
├── tests/
│ ├── QueueTest.php # Тесты для очереди
│ └── WorkerTest.php # Тесты для воркера
├── .env # Файл конфигурации
├── docker-compose.yml # Конфигурация Docker
├── Dockerfile # Инструкции для сборки PHP-контейнера
├── Makefile # Make-команды для удобства
└── phpunit.xml # Конфигурация PHPUnit
Решение построено с соблюдением принципов SOLID:
- S (Single Responsibility): Каждый класс отвечает только за одну часть функциональности
- O (Open/Closed): Система открыта для расширения через интерфейсы
- L (Liskov Substitution): Подклассы (например, RedisQueue) могут заменить базовые классы
- I (Interface Segregation): Интерфейсы разделены на специфичные (QueueInterface, EventProcessorInterface)
- D (Dependency Inversion): Высокоуровневые компоненты зависят от абстракций, а не от конкретных реализаций