Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Winushkin/url-shortener

Repository files navigation

URL Shortener (Сервис сокращения ссылок)

Высокопроизводительный сервис на Go для создания коротких ссылок и отслеживания аналитики переходов в режиме реального времени. Приложение спроектировано по принципам Clean Architecture (Чистой архитектуры) и оптимизировано для работы под высокой нагрузкой.

🚀 Ключевые особенности

  • Генерация уникальных кодов: Быстрое создание коротких идентификаторов для длинных URL.
  • Высокопроизводительная аналитика (Async Clicks): Учет кликов по ссылкам вынесен в асинхронный воркер через Go-каналы (chan string). Это позволяет отдавать оригинальный URL пользователю мгновенно, не дожидаясь блокирующих операций записи аналитики в базу данных.
  • Чистая архитектура: Четкое разделение ответственности на слои (Интерфейсы, UseCase, Репозитории/Сущности), что упрощает поддержку и тестирование кода.
  • Тестируемость (Table-Driven Tests): Более 50% кодовой базы покрыто тестами с использованием табличного подхода и моков.

🛠 Технологический стек

  • Language: Go 1.26+
  • DataBase: PostgreSQL, Redis
  • Testing: unit testing, benchmark testing, mocking

🧠 Архитектура асинхронного счетчика кликов

Для обеспечения минимального времени задержки (Latency) при редиректе, инкремент счетчика переходов выполняется в фоновом режиме:

  1. При вызове GetLongURL(ctx, shortCode) сервис извлекает ссылку из кэша/БД.
  2. Код ссылки отправляется в буферизированный канал: uc.clicksChan <- shortCode.
  3. Фоновый воркер (worker) читает из канала и пакетами или поштучно обновляет данные в хранилище.
  4. Пользователь получает ответ немедленно, минуя ожидание транзакции БД.

🧪 Тестирование

Бизнес-логика (usecase) протестирована изолированно от внешних зависимостей (баз данных, кэша) с помощью интерфейсов и использования мок-объектов. Тесты проверяют как успешные сценарии, так и обработку ошибок со стороны слоя данных.

Запуск тестов

Для запуска всех юнит-тестов в слое usecase выполните команду:

go test -v ./internal/usecase/...

Для запуска тестов с проверкой отсутствия состояний гонки (Race Condition):

go test -race ./internal/usecase/...

Оптимизации

Схема назначения короткого кода ссылки, заменена с последовательной: INSERT в базу -> генерация кода из id -> UPDATE кода в базу на генерацию числа для генерации кода в слое бизнес-логики(Snowflake ID): генерация ID -> генерация кода -> INSERT в базу

Это позволило:

  1. Сократить кол-во запросов в базу
  2. Уменьшить время выполнения операции
  3. Уменьшить кол-во памяти требуемой на операцию
  4. Повысить безопасность короткой ссылки, тк теперь коды расположены не по порядку и просто так перебрать коды не получится

📊 Брейк-даун производительности (Бенчмарки)

Для замера эффективности перехода от схемы INSERT + UPDATE (последовательный ID) к схеме 1 INSERT (Snowflake ID) были проведены макро-бенчмарки слоя бизнес-логики в связке с pgxpool (PostgreSQL).

Окружение:

  • OS/Arch: darwin/arm64 (Apple M1)
  • Пакет: shortener/internal/usecase
Подход Скорость (ns/op) Память (B/op) Аллокации (allocs/op)
Old (2 запроса: Ins + Upd) 1.117.467 ns/op 5.413 B/op 107 allocs/op
New (1 запрос: Snowflake) 610.794 ns/op 2,140 B/op 45 allocs/op

Итог оптимизации:

  • Скорость обработки запроса выросла на ~45%.
  • Выделение памяти в куче уменьшилось на ~61%.
  • Нагрузка на Garbage Collector (аллокации) снизилась в 2.4 раза.

Самостоятельно этот тест можно запустить с помощью:

> make testUsecase

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /