Skip to content

Repository files navigation

Image Processing Service

Backend-сервис асинхронной обработки изображений на Go.

Пользователь загружает изображение через HTTP API и выбирает необходимые операции обработки. Исходный файл сохраняется локально, metadata записываются в PostgreSQL, а задача на обработку отправляется в Apache Kafka.

Kafka consumer получает задачу и выполняет обработку изображения в фоне. После завершения результат сохраняется в файловое хранилище, а статус задачи обновляется в PostgreSQL.

Возможности

  • загрузка изображений через multipart/form-data;
  • асинхронная обработка через Apache Kafka;
  • сохранение metadata в PostgreSQL;
  • генерация UUID для изображений;
  • изменение размера изображения;
  • создание thumbnail;
  • добавление watermark;
  • хранение оригиналов и обработанных файлов;
  • получение статуса обработки;
  • получение URL обработанного изображения;
  • удаление изображения и связанных файлов;
  • retry при ошибках обработки Kafka-сообщений;
  • Dead Letter Queue;
  • graceful shutdown HTTP-сервера;
  • Docker;
  • Docker Compose;
  • web-интерфейс;
  • автоматизация через Makefile.

Архитектура

                    HTTP API
                       │
                       ▼
                  ┌─────────┐
                  │ Handler │
                  └────┬────┘
                       │
                       ▼
                  ┌─────────┐
                  │ Service │
                  └────┬────┘
                       │
             ┌─────────┼──────────┐
             │         │          │
             ▼         ▼          ▼
       PostgreSQL   FileStore   Kafka Producer
                                  │
                                  ▼
                            ┌─────────────┐
                            │ image-jobs  │
                            └──────┬──────┘
                                   │
                                   ▼
                            Kafka Consumer
                                   │
                                   ▼
                          Image Processor
                                   │
                         ┌─────────┴─────────┐
                         ▼                   ▼
                     FileStore          PostgreSQL

Жизненный цикл изображения

После загрузки изображение получает статус:

pending

Когда Kafka consumer начинает обработку:

processing

После успешного завершения:

done

Если обработка завершается ошибкой:

failed

Таким образом:

pending → processing → done
                   ↘ failed

Асинхронная обработка

HTTP-запрос не выполняет тяжёлую обработку изображения непосредственно.

После загрузки:

  1. создаётся UUID изображения;
  2. оригинал сохраняется в файловое хранилище;
  3. информация об изображении сохраняется в PostgreSQL;
  4. создаётся Kafka message;
  5. задача публикуется в topic image-jobs;
  6. клиент получает 202 Accepted.

Kafka consumer независимо получает сообщение и выполняет фактическую обработку.

Такой подход отделяет HTTP API от ресурсоёмкой обработки изображений.

Kafka

Основной topic:

image-jobs

Consumer group:

image-processor-group

Для неуспешно обработанных сообщений используется:

image-jobs-dlq

Retry

Kafka processor настроен на:

max attempts: 3
base retry delay: 200 ms
max retry delay: 2 s

Если сообщение не удаётся успешно обработать после повторных попыток, оно может быть отправлено в Dead Letter Queue.

Обработка изображений

В текущей реализации доступны три операции.

Resize

resize=true

Изображение уменьшается до ширины 500 пикселей с сохранением пропорций.

Используется фильтр:

Lanczos3

Thumbnail

thumb=true

Создаётся thumbnail:

200 × 200

Watermark

watermark=true

На изображение добавляется простая светлая плашка в нижнем правом углу.

Операции можно комбинировать.

Например:

resize=true
thumb=true
watermark=true

Форматы изображений

Для декодирования используются стандартные Go image packages.

Поддерживается чтение:

  • JPEG;
  • PNG.

Обработанный результат сохраняется в:

JPEG

с качеством:

90

Файловое хранилище

Файлы разделены на три категории:

uploads/
├── original/
├── processed/
└── thumbs/

original

Исходные изображения.

processed

Результаты основной обработки.

thumbs

Миниатюры изображений.

При удалении изображения сервис удаляет:

  • оригинал;
  • обработанный файл;
  • thumbnail;
  • запись из PostgreSQL.

PostgreSQL

PostgreSQL используется для хранения состояния задачи и metadata изображения.

Для каждого изображения сохраняются:

  • UUID;
  • исходное имя;
  • MIME type;
  • статус обработки;
  • выбранные операции;
  • пути к исходному и обработанным файлам;
  • текст ошибки;
  • timestamps.

REST API

Загрузка изображения

POST /upload
Content-Type: multipart/form-data

Параметры:

Поле Описание
file изображение
resize выполнить resize
thumb создать thumbnail
watermark добавить watermark

Пример:

curl -X POST http://localhost:8080/upload \
  -F "file=@photo.jpg" \
  -F "resize=true" \
  -F "thumb=true" \
  -F "watermark=true"

При успешной постановке задачи сервис отвечает:

202 Accepted

Пример ответа:

{
  "id": "94da43a4-5a67-4f05-b26e-a67fe32cb61c",
  "status": "pending"
}

Получение состояния

GET /image/<id>

Например:

curl http://localhost:8080/image/94da43a4-5a67-4f05-b26e-a67fe32cb61c

Во время обработки:

{
  "id": "94da43a4-5a67-4f05-b26e-a67fe32cb61c",
  "status": "processing"
}

После завершения:

{
  "id": "94da43a4-5a67-4f05-b26e-a67fe32cb61c",
  "status": "done",
  "image_url": "/files/processed/94da43a4-5a67-4f05-b26e-a67fe32cb61c.jpg",
  "thumb_url": "/files/thumbs/94da43a4-5a67-4f05-b26e-a67fe32cb61c.jpg"
}

Получение обработанного файла

Обработанные изображения доступны через:

/files/processed/

Thumbnail:

/files/thumbs/

Например:

http://localhost:8080/files/processed/<image-id>.jpg

Удаление изображения

DELETE /image/<id>

Пример:

curl -X DELETE \
  http://localhost:8080/image/94da43a4-5a67-4f05-b26e-a67fe32cb61c

Ответ:

{
  "result": "deleted"
}

Web-интерфейс

Статические файлы доступны по:

http://localhost:8080/

Структура проекта

.
├── cmd
│   └── image-processor
│       └── main.go
│
├── configs
│   └── config.yaml
│
├── internal
│   ├── broker
│   │   ├── consumer.go
│   │   └── producer.go
│   ├── config
│   ├── dto
│   ├── handler
│   ├── model
│   ├── repository
│   ├── service
│   │   ├── processor.go
│   │   └── service.go
│   ├── storage
│   └── transport
│
├── migrations
├── static
├── Dockerfile
├── docker-compose.yml
├── makefile
├── go.mod
└── go.sum

Запуск

Клонирование

git clone https://github.com/MarmulevSemyon/image-processing-service.git
cd image-processing-service

Запуск через Docker Compose

Рекомендуемый способ:

make docker-up

Перед запуском Docker Compose выполняется цепочка:

fmt → vet → lint → build

После этого запускаются:

  • PostgreSQL;
  • ZooKeeper;
  • Apache Kafka;
  • Kafka topic initializer;
  • Image Processing Service.

Kafka initializer автоматически создаёт:

image-jobs
image-jobs-dlq

Сервис доступен:

http://localhost:8080

PostgreSQL с host-машины:

localhost:5433

Kafka с host-машины:

localhost:9093

Просмотр логов

make docker-logs

Остановка

make docker-down

Полный перезапуск

make docker-restart

Команда выполняет:

docker compose down -v
docker compose up --build -d

При выполнении docker-restart удаляется PostgreSQL volume, поэтому данные базы будут потеряны.

Локальный запуск

make run

Команда:

go run ./cmd/image-processor

Для локального запуска необходимо самостоятельно обеспечить доступ к PostgreSQL и Kafka либо изменить конфигурацию приложения.

Сборка

make build

Перед сборкой автоматически выполняется:

fmt → vet → lint → build

Бинарный файл:

bin/image-processor

Проверка качества кода

Форматирование

make fmt

Выполняется:

gofmt -w ./cmd ./internal

Go Vet

make vet

Цель vet зависит от fmt.

Линтер

make lint

Цепочка:

fmt
 ↓
vet
 ↓
golint

Если golint не установлен:

go install golang.org/x/lint/golint@latest

Основные команды Makefile

Команда Назначение
make run локальный запуск приложения
make build проверки и сборка
make fmt форматирование Go-кода
make vet форматирование + go vet
make lint форматирование + go vet + golint
make docker-up сборка + запуск Docker Compose
make docker-down остановка Docker Compose
make docker-logs просмотр логов
make docker-restart полный перезапуск с удалением volumes
make clean удаление бинарных файлов

Очистка

make clean

Удаляет:

bin/

Использованные технологии

  • Go
  • Apache Kafka
  • PostgreSQL
  • HTTP / REST API
  • JSON
  • Multipart Form Data
  • Image Processing
  • Kafka Consumer Groups
  • Retry
  • Dead Letter Queue
  • Docker
  • Docker Compose
  • Makefile
  • WB Framework

Демонстрируемые навыки

Backend-разработка на Go

Организация backend-приложения с разделением ответственности между:

transport
handler
service
repository
broker
storage

Асинхронная архитектура

Отделение HTTP API от непосредственной обработки изображения.

HTTP-handler принимает запрос и публикует задачу, а фактическая обработка выполняется Kafka consumer'ом независимо от HTTP-request lifecycle.

Apache Kafka

Работа с:

  • producer;
  • consumer;
  • topics;
  • consumer groups;
  • message keys;
  • JSON payload;
  • retry;
  • Dead Letter Queue.

Retry и DLQ

Обработка временных и постоянных ошибок Kafka consumer'а с ограниченным количеством повторных попыток и возможностью отправки проблемных сообщений в отдельный DLQ topic.

PostgreSQL

Хранение:

  • metadata;
  • состояния задачи;
  • параметров обработки;
  • путей к файлам;
  • ошибок обработки.

Image Processing

Практическая работа со стандартным Go Image API и библиотекой resize:

  • decoding;
  • resize;
  • thumbnail;
  • drawing;
  • JPEG encoding.

Работа с файлами

Организация локального файлового хранилища с раздельным хранением:

  • оригиналов;
  • обработанных изображений;
  • thumbnails.

Согласованность данных

При ошибке отправки задачи в Kafka сервис удаляет уже сохранённый исходный файл и запись PostgreSQL, предотвращая появление незавершённого объекта.

HTTP API

Реализация:

  • multipart upload;
  • JSON responses;
  • HTTP status codes;
  • GET;
  • POST;
  • DELETE;
  • static file serving.

UUID

Использование UUID как уникальных идентификаторов изображений и Kafka message key.

Graceful Shutdown

Обработка:

SIGINT
SIGTERM

и корректная остановка HTTP-сервера.

Docker Compose

Оркестрация нескольких компонентов:

Go application
PostgreSQL
ZooKeeper
Kafka
Kafka initializer

Makefile

Автоматизация:

  • форматирования;
  • статического анализа;
  • линтинга;
  • сборки;
  • локального запуска;
  • управления Docker Compose.

История проекта

Основная цель проекта — практическая работа с асинхронной обработкой задач, Apache Kafka, PostgreSQL, файловым хранилищем, image processing и архитектурой backend-сервисов.

About

Сервис асинхронной обработки изображений на Go с Kafka, PostgreSQL, retry и DLQ.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages