Распределённое хранилище и gamedev

Помните эпизод из "Силиконовой долине", где Ричард Хендрикс объясняет свой революционный алгоритм сжатия? Как данные разбиваются на кусочки и распределяются по сети, создавая децентрализованное хранилище которое невозможно взломать?
Я смотрел этот момент и думал: "Это же гениально! А что если попробовать сделать что-то подобное?"

Распределённое хранилище и gamedev

От идеи к архитектуре

Решил начать с простого

  • Загрузка файлов
  • Скачивание файлов
  • Безопасное хранение

Но как сделать это по настоящему круто?

Вдохновившись концепцией middle-out compression из сериала, я решил пойти дальше:

Шардирование файлов

@Entity public class FileShard { private String shardId; private Integer shardIndex; private Long size; private String checksum; private String storageNodeId; }

Каждый файл разбивается на кусочки, сжимается, шифруется и распределяется по сети. Получается уже не просто хранилище, а распределённая система :)

P2P децентрализация

Ещё фичи из сериала
Помните, как в сериале они использовали телефоны пользователей для создания распределённой сети?

Я попробовал реализовать подобную систему

┌───────────────────────────────────────────────────────┐ │ РАСПРЕДЕЛЕННАЯ СЕТЬ ХРАНЕНИЯ │ │ │ │ Master Server (координатор) │ │ │ │ │ ┌──────────────┼──────────────┐ │ │ │ │ │ │ │ Regional 1 Regional 2 Regional 3 │ │ │ │ │ │ │ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │ │ │ │ │ │ │ │ │ │ User A User B User C User D User E User F │ │ (Phone) (PC) (Tablet) (PC) (Phone) (Laptop) │ │ │ │ │ │ │ │ │ │ Shard 1 Shard 2 Shard 3 Shard 4 Shard 5 Shard 6 │ └───────────────────────────────────────────────────────┘

Каждый пользователь, подключенный к системе, становится P2P-нодой

Сценарий пока такой: (ещё в раздумьях как организовать лучше архитектуру)

  • User устанавливает приложение
  • Выбирает, сколько места готов предоставить(условно, 10gb)
  • Его устройство регистрируется как нода
  • Система начинает хранить на его устройстве зашифрованные куски данных
  • Взамен user получает больше места для своих данных

Напрашивается вопрос: Чё если нода упала?
Пока я пришёл к нескольким решениям:

Репликация (как в RAID)

Файл: vacation_video.mp4 (100 MB) Разбит на: 10 шардов по 10 MB Shard 1: ├─ Копия A → User123 (PC, Москва) ├─ Копия B → User456 (Phone, СПб) └─ Копия C → User789 (Tablet, Казань) Shard 2: ├─ Копия A → User234 (Laptop, Новосибирск) ├─ Копия B → User567 (PC, Екатеринбург) └─ Копия C → User890 (Phone, Москва) ... и так далее для всех 10 шардов

Чтобы потерять файл, нужно чтобы одновременно упали все 3 копии каждого из 10 шардов

Автоматическое восстановление

1. Нода IPhone(Vanya) перестала отвечать ↓ 2. Помечает ноду как OFFLINE ↓ 3. Находит все шарды, которые хранились на этой ноде (например, 50 шардов) ↓ 4. Для каждого шарда проверяет количество живых реплик ↓ 5. Если реплик меньше 2 — скачивает шард с другой ноды ↓ 6. Загружает шард на новую здоровую ноду ↓ 7. Данные восстановлены!

Бэкап на сервере (Как самый крайний случай)

Как удержать пользователей для работы системы?

Чтобы моя сеть заработала нам необходимо иметь много активных пользователей - это нужно, чтобы экономить днюшки на дата центрах.
Единственное, что мне пришло в голову - это Hamster Combat (кликер).
Конечно стоит придумать что-то по лучше но пока это.

Почему это работает?

  • User играет в кликер → приложение активно
  • Приложение активно → устройство онлайн как нода
  • Нода онлайн → сеть работает лучше

Технологии

Хотя у меня нет революционного алгоритма сжатия Ричарда Хендрикса, я использую Zstandard - один из лучших современных алгоритмов:

@Service public class CompressionService { public byte[] compress(byte[] data) { // Zstandard // Уровень сжатия: 3 (баланс скорость/размер) return Zstd.compress(data, 3); } public CompressionStats getStats(byte[] original, byte[] compressed) { double ratio = (1.0 - (double)compressed.length / original.length) * 100; return new CompressionStats( original.length, compressed.length, ratio, "Сжатие: " + String.format("%.1f%%", ratio) ); } }

Результаты:

  • Текстовые файлы: сжаты до 80%
  • Изображения: до 20-30%
  • Видео: до 10-15%

(Как будет больше свободного времени, начну писать свой алгоритм сжатия, можно сказать - мечта :) )

JWT и шифрование

@Service public class SecurityService { public String generateToken(User user) { return jwtService.generateToken(user); } public byte[] encryptShard(byte[] data, String key) { // AES-256 шифрование return aesService.encrypt(data, key); } public String calculateChecksum(byte[] data) { // SHA-256 для проверки целостности return DigestUtils.sha256Hex(data); } }

Админка которая дышит

Добавил WebSocket для максимального Real-time

@Service public class WebSocketNotificationService { @Scheduled(fixedRate = 1000) // Каждую секунду public void sendSystemStats() { SystemStatsUpdate stats = new SystemStatsUpdate( nodeService.getActiveNodesCount(), nodeService.getTotalStorageProvided(), nodeService.getTotalStorageUsed(), fileService.getTotalFilesCount(), gameService.getActivePlayersCount(), gameService.getTotalClicks() ); messagingTemplate.convertAndSend("/topic/stats", stats); } }

Сейчас показывает

  • Количество активных нод
  • Общее пространство
  • Скорость загрузок/скачиваний
  • Активность и клики
  • Нагрузка на систему
  • География пользователей

Какие планы?

Не скажу что прям стартап планирую открывать, но реализовать идею полностью было бы круто. Не слышал, что подобное где-то есть, может плохо гуглил или слишком рискованно для бизнеса. Уже готов сервер и мобильное приложение, код не покажу пока, стыдно будет)
Вдруг кто-нибудь богатый и солидный заинтересуется и даст денег на проект, а я уже весь код слил)
Чувствую, что успех будет зависеть от игры...
Хм... может донаты за GB свободного места? Сделать Clash of Clans или типо того? Надо будет подумать хорошенько)
Если будут идеи пишите)

P.S. В отличие от Pier Piper, у меня нет Эрлиха, который бы всё испортил)

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

Backend

  • Spring boot
  • PostgreSQL
  • MinIO
  • Zstandard
  • JWT, BCrypt, AES, SHA, CORS
  • Docker
  • Gradle
  • Git

Frontend

  • Flutter/Dart
1
Начать дискуссию