惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
B
Blog RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
Martin Fowler
Martin Fowler
Recorded Future
Recorded Future
Blog — PlanetScale
Blog — PlanetScale
Microsoft Security Blog
Microsoft Security Blog
G
Google Developers Blog
S
SegmentFault 最新的问题
人人都是产品经理
人人都是产品经理
Jina AI
Jina AI
G
GRAHAM CLULEY
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
博客园 - 【当耐特】
Forbes - Security
Forbes - Security
C
Cyber Attacks, Cyber Crime and Cyber Security
S
Securelist
H
Heimdal Security Blog
NISL@THU
NISL@THU
T
Troy Hunt's Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
C
CERT Recently Published Vulnerability Notes
月光博客
月光博客
Engineering at Meta
Engineering at Meta
Google Online Security Blog
Google Online Security Blog
Latest news
Latest news
N
Netflix TechBlog - Medium
Hacker News: Ask HN
Hacker News: Ask HN
S
Schneier on Security
Schneier on Security
Schneier on Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - 叶小钗
V
V2EX
Google DeepMind News
Google DeepMind News
L
LINUX DO - 最新话题
宝玉的分享
宝玉的分享
J
Java Code Geeks
Y
Y Combinator Blog
D
Docker
Help Net Security
Help Net Security
有赞技术团队
有赞技术团队
T
The Blog of Author Tim Ferriss
V2EX - 技术
V2EX - 技术

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
МакКладун или почему балансеруны не нужны
lastrix · 2026-05-17 · via Все публикации подряд на Хабре

МакКладун или почему балансеруны не нужны

Уровень сложностиПростой

Время на прочтение5 мин

Охват и читатели0

Вчера автор побывал на прекрасной конференции Backend Talks 360 от компании Yandex и не в силах спокойно спать, не ответив конструктивной критикой на доклад Ильи Абрамова о работе Яндекс.Диска, автор принялся писать очередной "В интернете кто-то не прав". Что из этого вышло - добро пожаловать под кат.

Почему загрузка больших файлов одним запросов для облачных хранилищ - это тупик

Одним из основных пунктов докладчика было балансирование нагрузки между "кладунами". Но в итоге доклад перерос в балансирование нагрузки между "балансерунами" и "кладунами".

Схематичное обобщение доклада

Схематичное обобщение доклада

Разумеется на диграмме нет "внешнего" балансировщика, которого не было и на слайдах докладчика. Обобщенная логика работы решения следующая:

  1. Пользователь из балансеруна получает ссылку на кладуна;

  2. На указанный кладун загружается файл (целиком).

Из-за разности в скоростях подключений всех пользователей гарантированно получаем при любых попытках в такой архитектуре что-либо балансировать перекосы по нагрузке на кладунов. Гарантированно будут перегруженные, и так же гарантированно будут недогруженные. Причем способ выбора не имеет значения.

Докладчик предложил решение в ходе которого удалось улучшить распределение за счет довольно больших и трудоемких решений, требующих сами по себе инфраструктуру, которой, как говорил докладчик итак не хватает.

Не будем указывать на то, что в случае ошибок сети, все загружаемые гигабайты можно будет выкидывать и заливать заново, поэтому попробуем исправить изначальную ошибку и покажем, что есть решение, при котором не нужны балансеруны вовсе, но при условии, что у всех кладунов есть общее хранилище (например nfs, главное, что бы у всех кладунов в группе было оно общим, а так же общая БД). Так как внешний балансировщик все равно есть, будем опираться именно на него.

Загрузка файлов блоками

Уже давно придумано решение, когда файл заливается блоками и после загрузки проверяется на целостность, так делает Google.drive, а так же некоторые другие облачные хранилища.

Работает блочная загрузка только при условии, что эти блоки всегда выровнены по степени двойки (на самом деле по размеру буфера, который пишется на диск операционной системой), в противном случае будет гарантированное повреждение при передаче (например один пишет пару байт в конце буфера, обнуляя все что писали до него из-за неправильного смещения и гонок).

Архитектура решения для такого варианта тривиальная

Пользователи могут отправлять запросы на любой макладун, так как размер тела запроса не может превышать размер блока + небольшой оверхед на заголовки и остальную обвязку http протокола, нагрузка будет ложиться достаточно ровно, что бы не перегружать никого.

Пользователи могут отправлять запросы на любой макладун, так как размер тела запроса не может превышать размер блока + небольшой оверхед на заголовки и остальную обвязку http протокола, нагрузка будет ложиться достаточно ровно, что бы не перегружать никого.

Все API при этом разделяется на 2 класса: все что меньше блока (маленькие файлы) и все что больше блока (большие файлы). Размер блока можно выбрать любой степенью двойки, например 4194304 (4 мегабайта).

При такой организации мелкие файлы пользователи будут спокойно загружать и не создавать лишней нагрузки на систему (иначе пришлось бы делать 3 запроса). Таких файлов большинство и поэтому нужна отдельная ручка для таких запросов.

В случае больших файлов (а иногда требуется загружать сотни гигабайт), жизненно необходимо гарантировать, что у пользователя всегда будет возможность продолжить загрузку. Поэтому для этого формируется отдельное API. Смысл в том, что в начале отправляется запрос на подготовку загрузки большого файла, в этом запросе сообщается размер загружаемого файла, контрольная сумма для сверки и другие необходимые и полезные пользователю свойства, например флаг "перед открытием удалить". Далее в один или несколько потоков загружаются блоки, а по завершении загрузки всех блоков - специальный запрос на завершение.

Общий алгоритм тогда такой (лишь один из вариантов):

  1. Получить идентификатор для загрузки большого файла;

  2. В один или несколько потоков загружать выровненные блоки, сообщая для каждого блока его смещение;

  3. Дождаться завершения загрузки всех блоков;

  4. По окончании загрузки - сообщить сервису об окончании, и начале процессе удаления загруженного валидации файла (проверки контрольной суммы, можно еще антивирусом погонять). Контрольную сумму можно сообщать на данном этапе, а не создания загрузки.

Такое API - простое для реализации любым разработчиком, да и Яндекс достаточно богатая компания, что бы предоставлять клиенты на различных языках программирования для интеграции своим пользователям.

Простой пример

Дабы не быть голословным, и развеять все сомнения у тех, кто может воскликнуть, что это не будет работать, автор подготовил простое приложение. Написано оно так же на простом языке программирования Rust.

Код доступен по ссылке .

Сервис реализует простейшее апи:

  1. POST /api/upload/small-file/{user_id}/{display_file_name:.*} - Загрузка маленького файла на диск, display_file_name - это специальный параметр, который берет весь остаток пути.
    В запросе ожидается заголовок x-sha-512.

  2. POST /api/upload/large-file/new - создать файл для загрузки, он будет считаться незавершенным, пока не будет завершен процесс загрузки. В запросе передается тело, в котором указывается: идентификатор пользователя, отображаемое имя файла, размер и контрольная сумма.

  3. PUT /api/upload/large-file/{file_id}/chunk/{offset} - пишет блок по смещению, проверяя контрольную сумму полученного блока перед записью; Вернет 400, если контрольная сумма неверна.
    В запросе ожидается заголовок x-sha-512 - контрольная сумма блока.
    Данный запрос можно направлять на любого макладуна, так как запись осуществляется в непересекающиеся блоки.

  4. POST /api/upload/large-file/{file_id}/done - уведомление о завершении загрузки, синхронно (лучше это делать фоновой задачей) проверяет целостность файла, вернет 200, только если контрольные суммы совпали.

В чем главное преимущество данного API? Оно дружелюбно к повторам, если по каким-то причинам сервер не ответил, то клиент может отправить блок заново и не прерывать загрузку.

Как использовать написанное приложение

Для запуска нам потребуется PostgreSQL:

podman run --rm --name test-db \
  -e POSTGRES_PASSWORD=xxXX12341234 \
  -e POSTGRES_USER=user \
  -p 5432:5432 \
  postgres:17

После этого из корня проекта запускаем миграцию БД:

sqlx migrate run

Теперь можно запустить парочку инстансов:

cargo run --bin makladun -- -c config/makladun_local.yaml

И в другом терминале

cargo run --bin makladun -- -c config/makladun_local2.yaml

Если оба сервиса успешно запущены и будут писать в папку /tmp/makladun/1, убедитесь, что она создана. Вы можете смонтировать сетевой диск (smb, nfs), и пробовать загружать туда большие файлы (не рекомендую больше 100мб, так как почему-то расчет SHA-512 занимает много времени, консольная утилита делает быстрее на порядок), маленькие файлы работать перестанут, потому что перемещения между дисками нет, а править это на копирование нет желания.

Пример для загрузки файла:

cargo run --bin disk-io-client -- -u 2 -d "makladun" \
  -f /tmp/makladun/makladun \
  -p 4 \
  -b http://localhost:8080 -b http://localhost:8081

Что сделает эта команда: от пользователя 2, создаст файл makladun в "облачном хранилище в корне", возьмет файл из /tmp/makladun/makladun и будет заливать его в 4 потока. Отправка запросов осуществляется на сервисы http://localhost:8080 и http://localhost:8081 случайно. Если поставите балансировщик, то рекомендую использовать round-robin стратегию балансировки, так как она даст наилучший результат. Ссылку тогда достаточно будет оставить одну.

Конфигурация устроена следующим образом:

http:
  port: 8080
storages:
  - key: "1"
    path: "/tmp/makladun/1" # Можно указать множество хранилищ, в том числе сетевые диски
                            # главное, что бы эта папка существовала. Выбирается случайно.
  # - key: "2"
  #   path: "/tmp/makladun/2"
chunkSize: 4096 # Размер блока в килобайтах, все что меньше - считается маленьким файлом
db:
  host: "localhost"
  port: 5432
  database: "postgres"
  schema: "public"
  user: "user"
  password: "xxXX12341234"
  additionalOptions:
    search_path: "public"

Вместо заключения

Илья Абрамов с командой проделали огромную работу, и на самом деле сложную. Но иногда решение лежит куда как ближе и проще. Не всегда переусложнение имеет смысл.

Возможно, что эта статья позволит Яндекс.Диску стать немного лучше и производительнее. ;)