Мы уже рассказывали о том, как был сделан выбор в пользу протокола WebDAV, а также о проблемах, возникающих на серверной стороне, и их решении.
Сегодня — о том, как устроен загрузчик файлов на сервис, и о чём нужно не забывать, когда пишешь его для сервисов масштаба Яндекс.Диска.
Для начала рассмотрим архитектуру сервиса в целом. В основе сервиса лежит mpfs – Магическая проксирующая файловая система. Это бэкэнд, который содержит в себе всю бизнес-логику по работе с файлами, папками, каталогами: все операции по копированию или созданию новых файлов идут через эту систему. Эта же система отвечает и за хранение метаданных.
Синхронизация с клиентами происходит по протоколу WebDAV. На его основе мы создали клиенты под Windows, OS X и мобильные платформы. Но при необходимости с помощью WebDAV можно настроить синхронизацию с любым приложением, поддерживающим данный протокол.
Через веб-интерфейс пользователям доступны те же функции, что и через клиенты: загрузка, скачивание и просмотр файлов. Кроме того, через наш внутренний API производится взаимодействие с другими сервисами Яндекса. На данный момент это Народ, Почта, Музыка и Браузер. Например, через мобильный клиент Яндекс.Музыки можно получить доступ к загруженным в Диск аудиофайлам.
Меч-кладенец
Но вернемся к нашей основной теме – загрузчику. У нас он проходит под кодовым названием «Кладун». Мы долго не могли подобрать подходящего русскоязычного аналога для пары uploader-downloader, но в итоге остановились на сочетании Кладун-Заберун.
Нетрудно догадаться, что основной задачей Кладуна является загрузка и размещение файлов с метаданными в хранилища. Начинается все с того, что пользователь через клиент или веб-интерфейс добавляет в папку на Диске файл. На сервер посылается запрос, который передается в mpfs. Файловая система возвращает назад ссылку на конкретную машину из кластера загрузчиков, после чего на нее заливается файл. В итоге он попадает в хранилище, далее статус загрузки передается в mpfs, и она сохраняет все метаданные. На каждой машине-загрузчике хранится своя локальная очередь. Это позволяет повысить надежность процесса загрузки. При отключении одного из дата-центров или какаой-нибудь машины в кластере, на всех остальных машинах файлы продолжат заливаться. А на выключавшихся машинах процесс заливки продолжится сразу после их перезапуска.
Помимо наиболее очевидной своей функции – забрать файл у пользователя и положить его в хранилище – загрузчик умеет также переносить файлы между сервисами Яндекса.
Стадии задач
Каждая задача, выполняемая загрузчиком делится на несколько стадий. Первым делом после получения файла от пользователя или сервиса производится подсчет контрольных сумм. В дальнейшем они будут использоваться при синхронизации файла для отслеживания изменений. Так как наш Кладун поддерживает загрузку изменений патчами, каждый файл разбивается на несколько блоков, для каждого из которых генерируется отдельная контрольная сумма. Если файл после заливки был слегка отредактирован, то при синхронизации перезалит он будет не целиком: заново будут загружены только те блоки, в которых произошли изменения и контрольные суммы перестали совпадать. Нечто подобное используется в системах управления версиями.
Использование хэш-сумм также позволяет избежать повторной загрузки уже залитых другими пользователями файлов. К примеру, если вы хотите залить на Диск какой-либо популярный видеоролик или установочный файл, а в хранилище Диска уже есть файл с идентичной контрольной суммой, использоваться будет он. Таким образом, даже очень крупные файлы могут быть помещены в хранилище буквально за пару секунд. Это выгодно обеим сторонам: пользователь получает очень быструю загрузку, а мы экономим ресурсы. Всего повторяющиеся файлы составляют около 12 процентов от всех заливаемых.
После заливки файла на машину загрузчика и подсчета хэш-суммы необходимо переместить файл в хранилище и отправить статус загрузки в mpfs. С этого момента файлы становятся доступны пользователю: они отображаются в веб-интерфейсе и могут синхронизироваться при помощи клиентов. Но на этом работа загрузчика не заканчивается, наступает черед двух стадий пост-обработки: создание превью и проверка на вирусы.
Каждая стадия проходит через определенный набор состояний. Изначально все они находятся в исходном состоянии (initial). Некоторым стадиям на выполнение требуется совсем немного времени, они практически сразу переходят в статус успешно завершенных (success). Но на пути к успеху могут случаться сбои. Они бывают двух видов: временные и окончательные. Например, когда при передаче данных в mpfs случается сбой сети или перестает отвечать один из дата-центров, стадия переходит в состояние временного сбоя (temp fail) и через какое-то время запрос повторяется. Если через определенное количество повторений успешно завершить стадию так и не удается, она переходит в состояние окончательного сбоя (fail).
В случае сбоя на стадии, которая никак не связана с сетью и выполняется локально, она сразу переходит в статус fail, так как повторный ее запуск, скорее всего, никаких результатов не даст. Именно так обстоит дело с генерацией превью. Это достаточно простой и понятный процесс, и если что-то пошло не так, то велика вероятность того, что мы просто пока не научились делать превью для этого типа файлов, а значит, повторение этой стадии – дело бессмысленное. Необходимость повтора операции, а также количество повторов, после которого она окончательно переходит в состояние fail прописывается для каждой стадии отдельно. Приведет ли сбой при выполнении той или иной стадии к провалу всей задачи, зависит от параметра обязательности успешного выполнения. Например, как уже говорилось выше, генерация превью далеко не всегда завершается успешно. Но для пользователя наличие превью в веб-интерфейсе не критично, главное, что доступ к своим файлам получен, а значит, основная задача выполнена. Однако если сбой произойдет на более важной стадии, такой как передача файла в хранилище, провалена будет вся задача. В этом случае десктопный клиент повторит попытку сам, а при заливке через веб пользователю будет передано сообщение о неудаче, после чего он может попробовать загрузить файл заново.
Кроме того, у каждой стадии есть максимальное время выполнения. Если стадии для успешного завершения требуется много времени, она может переходить в состояние «в процессе» (in progress). Обычно это происходит при получении файла от пользователя, так как загружаемые файлы бывают достаточно большими (максимальный объем файла на Диске – 10 ГБ), а скорость подключения – низкой.
Только не дисконнект! Только не дисконнект!
При передаче файла на машину загрузчика может случиться всякое. Например, может пропасть соединение с пользователем. В этом случае стадии присваивается статус temp fail, а после восстановления соединения закачка возобновляется.
Автор: sanches566