Почему это важно?
На современных web сайтах объем картинок может составлять от 30% до 70% всего размера страницы. Например, объем изображений на Хабре обычно составляет несколько мегабайт.
Большинство изображений в Web'e — это фотографии. Профильные фото в соц. сетях, альбом с телефона, профессиональные снимки и т.п. Правильная стратегия и инструменты для работы с фотографиями позволят сделать сайт быстрым для посетителей.
Формат для фотографий
Основной формат для хранения фотографий в Web'e — это JPEG. Однако иногда следует использовать и другие форматы.
JPEG
Хорошо подходит для сложных изображений, т.е. как раз для фотографий. Основной принцип сжатия в этом формате — это уменьшение качества путем уменьшения детализации изображения.
Подбор показателя сжатия может уменьшить размер исходного файла в несколько раз без заметного ухудшения качества. Логика такая: чем ниже качество — тем легче файл. Обычно используют показатель качества от 80 до 90.
Webp
Это формат, разработанный специально для обслуживания изображений в Web'e. Может уменьшить размер файла в несколько раз без потери качества. Значительно лучше сжимает фотки, чем JPEG. Однако поддерживается еще не всеми браузерами.
PNG и GIF
Эти форматы не подходят для фотографий. PNG изображения сохраняются без потери качества и лучше всего подойдут для иконок и графики. Формат GIF имеет ограниченную палитру, однако поддерживает анимацию.
Загрузка фотографий на сервер
Если на вашем проекте существует необходимость загружать пользовательские фотографии, сначала необходимо выбрать принцип их хранения на сервере.
Если вы собираетесь работать с сотнями файлов, стоит выбрать древовидную структуру:
Это позволит избежать ситуации с тысячами файлов в одной папке (это тормозит работу файловой системы и вашу собственную). Лучше всего использовать вложенную структуру из папок длинной в два символа:
$photo = $_FILES['image']['tmp_name'];
$name = md5($photo) . '.jpg';
$dir = substr(md5(microtime()), mt_rand(0, 30), 2) . '/' . substr(md5(microtime()), mt_rand(0, 30), 2);
$path = $dir . '/' . $name; # по этому пути сохраняем фотку
Инструменты
После загрузки фотографий на сервер, их следует обработать:
- Уменьшить размер до приемлемого. Нет смысла хранить и показывать оригинал фотографии размером 4000х3000 на сервере.
- Удалить все метаданные. Иногда объем такой инфы может составлять больше половины веса самого изображения.
- Провести оптимизацию для уменьшения размера файлов. Это ускорит загрузку у посетителя.
Для этого существует ряд инструментов.
ImageMagick
Сразу после загрузки фотографии на сервер, имеет смысл удалить все метаданные и изменить размер до 1000х1000:
# 90 - уровень сжатия в итоговом JPEG файле
convert input.jpg -strip -resize 1000x1000 -quality 90 output.jpg
GraphicsMagick
То же самое с помощью более производительного GraphicsMagick:
# изменение размера до 600х500 с уровнем качества в 90
gm convert input.jpg -strip -resize 600x500 -quality 90 output.jpg
Jpegtran
Этот инструмент уменьшает размер JPEG файлов без потери качества.
jpegtran -copy none -optimize -outfile min.image.jpg image.jpg
cwebp
Утилита позволяет преобразовать изображение в формат Webp.
cwebp -q 85 input.jpg -o output.webp
Отдача клиенту
Фотографии лучше всего отдавать Nginx'ом. Обязательно нужно настроить Cache-control и Keepalive для повышения скорости загрузки страниц:
http {
...
keepalive_timeout 75s;
server {
listen 80;
location ~ .\.jpg$ {
expires max;
}
}
}
Превью (thumbnails)
Часто нужно иметь возможность показывать небольшие версии фотографий (например, миниатюра профильной фотки).
Для этого необходимо генерировать нужные размеры при загрузке:
convert file.jpg -resize 50x50 file.s.jpg
convert file.jpg -resize 250x250 file.m.jpg
Тогда у каждого изображения будет соответствующая миниатюра.
Более удобный подход — генерировать превью на лету с помощью, например, Nginx image_filter модуля.
Поддержка Webp
Webp не поддерживается всеми браузерами, однако постепенно набирает популярность. Для того, чтобы извлечь пользу из этого формата, можно отдавать разные версии фотографий в зависимости от браузера посетителя.
Для каждой фотографии нужно сгенерировать webp версию:
cwebp file.jpg -o file.jpg.webp
Теперь необходимо отдать соответствующую версию картинки в зависимости от поддержки этого формата браузером:
server {
...
location ~* ^/.+\.(jpg|jpeg)$ {
if ($http_accept ~* "webp") {
rewrite (.+) $1.webp;
}
}
...
}
Облака
Облачные технологии развиваются и дешевеют. Если у вас нет специфических задач по обработке фоток, лучше присмотреться к варианту использования внешнего сервиса для их хранения и отдачи.
Amazon s3
Это облачное хранилище с которым не придется думать о масштабировании. Храните терабайты и не парьтесь. Пример реализации загрузки фотографий на S3 в PHP:
$path = 'photo_name.jpg';
$s3 = new S3('ключ', 'секрет');
$s3->putObjectFile($_FILES['image']['tmp_name'], 'букет', $path, S3::ACL_PUBLIC_READ, []);
После этого можно показывать фотку прямо с Амазона:
...
<img src="https://s3-eu-west-1.amazonaws.com/букет/photo_name.jpg"/>
...
Cloudinary
Мощный сервис для работы с фотографиями в облаке. Ресайз, кроп, распознавание лиц, разные форматы, онлайн редактор и другие функции.
i.onthe.io
Мега простой сервис, распознает возможности браузера и подбирает оптимальный формат отдачи. Поддерживает URL API для ресайза и кропа.
Конспект
- Правильный формат и сжатие фоток могут сэкономить до 70% объема страницы.
- Используйте только JPEG для фотографий.
- При возможности включайте поддержку Webp.
- Imagemagick, Graphicsmagick и Jpegtran для манипуляций и оптимизации фоток.
- Рассматривайте облачные решения для хранения фоток — это быстро и удобно.
Комментарии (81)
Iktash
08.05.2015 16:17Я не очень понял в каком случае стоит рассматривать облачные решения для хранения фоток? Бонус только в том, что место дешевле? При каких обьемах это становится существенным?
Просто головной боли сразу сильно больше с оплатой отдельной и прочим.edogs
08.05.2015 16:24+3Облачные решения для «обычного использования» весьма дороги получаются.
Мы в результате поигравшись в облака (где каждый раз считаешь сколько обойдется закачать/скачать данные или не дай бог посещаемость повалит внезапная от конкурентов), пришли к выводу, что дешевый сервер в германии за 40 евро с 4 ТБ места и 30Тб траффика на 200мбитном порте во-первых обойдется конкретно дешевле, а во-вторых спать будешь спокойнее… да и сам сайт на нем же можно захостить.sunnybear
08.05.2015 16:45-2в принципе, да. Пока стоимость привлечения клиентов на востоке за Москвой не станет слишком высокой с серверами в Германии. Тогда нужен будет уже CDN по России
raveland
09.05.2015 16:11А что с самой простой отказоустойчивостью?
edogs
09.05.2015 22:19Отказоустойчивостью в каком именно плане?
С железом/софтом? У облаков не так уж редко случаются проблемы, у амазона тоже эпик фэил был, у многих более мелких облаков данные несколько раз пропадали.
Отказоустойчивость к ддос атакам? На облачном провайдере при этом влетаешь на такие деньги за ресурсы, что думаешь «ну его на фиг лучше бы упало».
В случае своего сервера у тебя по крайней мере есть доступ к твоей железке через kvm, а не пассивно ждешь пока «что-то кто-то откуда-то восстановит».
С нашей точки зрения по отказоустойчивости для «обычного использования» (опять же), сервер и облако примерно паритетны. Возможные проблемы разные, по разному решаются, но размер проблем в целом сравним.raveland
09.05.2015 23:46Ну я конкретно интересовался как решаете проблему выхода из строя вашего сервера. Сервис продолжает работать?
edogs
11.05.2015 22:27В случае «обычного сайта» считаем вполне достаточным регулярные бакапы вдс-ки (вдс-ки на своем сервере, сайты уже на вдс-ках) на независимый бакап-сервер (чисто файловый или сайто-файловый готовый к работе), откуда сайт может быть развернут в рабочее состояние за время от 15 минут до пары часов (в зависимости от сценария).
edogs
08.05.2015 16:25+2substr(md5(microtime()), mt_rand(0, 30), 2)
Как бы это развидеть:)neolink
08.05.2015 16:29+2ну, а что в этом уж такого плохого?
«критикуя — предлагай!»gnomeby
08.05.2015 16:42+1преобразуйте microtime в строку, и возьмите последние 2 символа, получится тот же эффект.
neolink
08.05.2015 17:08вообще-то нет, в первом же приближении, microtime это [0-9] а md5 [0-9a-f], то есть для 2х символов в вашем случае будет 100 вариантов, а в исходном коде 256
ну и хеш функция против Н микросекунд это немного разные уровни энтропииgnomeby
08.05.2015 17:56+1Не придирайтесь, возьмите time заместо и три символа с конца будет вам и шире и равномерно.
spuf
08.05.2015 16:52+1$name = md5($photo) . '.jpg'; $dir = substr($name, 0, 2) . '/' . substr($name, 2, 2);
Будет: 02/c4/02c425157ecd32f259548b33402ff6d3.jpgneolink
08.05.2015 17:01-1смысл этих уровней, чтобы файлы распределялись по ним как-можно равномернее, всякие «безымянный.jpg» и т.п. будут портить общую картину
maximw
08.05.2015 18:21$name = md5(mcrypt_create_iv (16)) . '.jpg'; $dir = substr($name, 0, 2) . '/' . substr($name, 2, 2);
или еще проще и можно длину файла изменять
$name = bin2hex(mcrypt_create_iv (16)) . '.jpg'; $dir = substr($name, 0, 2) . '/' . substr($name, 2, 2);
В вашем случае:
MD5 и так дает равномерное распределение символов, совершенно излишне брать его подстроку в случайной позиции.substr(md5(microtime()), mt_rand(0, 30), 2)
neolink
08.05.2015 17:14-1хотя если вы имели ввиду $photo из статьи, то реализация tmp_name лежит на операционке, да там банально может не быть 4х символов, или у вас может получится несколько больше уровней например 1236, или несколько меньше (вот пример значения tmp_name: /tmp/php/php1h4j1o), в общем вместо контролируемого поведения мы получаем platform specific
edogs
08.05.2015 18:27+1ну, а что в этом уж такого плохого?
Избыточен и сходу непонятен. В нем видится куда более глубокий смысл чем есть.
«критикуя — предлагай!»
С учетом того, что «не больше 1000 файлов», mt_rand(1,999); был бы вполне достаточно, плюс было бы сразу понятно что код делает.Halfi
12.05.2015 12:24Не понимаю, как между собой связан «mt_rand(1,999);» с фразой «не больше 1000 файлов»? Этот ранд никак не ограничит количество файлов в одной папке, а энтропия очень мала, чтобы выйти за рамки «1000 файлов в папке», достаточно всего 998 в квадрате файлов.
spuf
08.05.2015 16:45-3Ни слова про то, что надо держать HiDPI/Retina версии.
akubintsev
09.05.2015 22:51+2Не понятно, за что минусы. Человек дело говорит. У статьи название ведь не «о WebP».
cy-ernado
08.05.2015 17:10У webp мало перспектив относительно увеличения его популярности, разве только при полной доминации blink-браузеров (да и то вряд ли).
Просто по политическим причинам. Mozilla принципиально не хочет webp, не обращая внимание на огромное количество запросов и уже реализованную функциональность, предложенную в патчах. Apple получает выгоду от многих закрытых патентов.
Когда сам разбирался в этой теме, было очень грустно, что формат не хотят поддерживать.uazure
08.05.2015 20:54+1А что мозилла проигрывает от того, что в фф будет webp? Или что выигрывает от его отсутствия?
cy-ernado
14.05.2015 15:02Ничего не проигрывает, ничего не выигрывает. Просто не хотят, оправдываясь кто чем может.
Подробности можно найти тут:
bugzilla.mozilla.org/show_bug.cgi?id=600919
bugzilla.mozilla.org/show_bug.cgi?id=856375
Rathil
09.05.2015 12:11+1Не согласен. Давно его уже использую и, почти так, как описано в статье, за счётом небольших нюансов.
На счёт поддержки, на хромиуме уже достаточно много браузеров и он занимает большую долю браузерного рынка. Даже экономя трафик на них — уже есть выигрыш, как минимум для самих пользователей, которые платят за трафик.
К слову, Опера-турбо, именно так и оптимизирует изображения, пережимая все в вебп.Timrael
10.05.2015 19:35Аналогично, на 60%+ юзеров можно нехило экономить трафика. Давно уже используем в проде.
cy-ernado
14.05.2015 15:00Я к тому, что дальше хромиума и его производных WebP не пойдет с высокой вероятностью.
Использовать формат имеет смысл даже при 30% поддержке у пользователей, слишком уж он вкусный.
С вами я полностью согласен :)
lexore
08.05.2015 18:49+1Храните терабайты и не парьтесь.
Только не забывайте оплачивать счета.
Облако полезно, когда неизвестно, насколько выстрелит.
Потом выгоднее переводить на железный сервер.
Можно перейти с s3 на что-то похожее, например на swift, минимальными правками кода.
x88
08.05.2015 20:18Если трафик большой, S3 будет отдавать довольно медленно, так что практически обязательно придется подключать CDN
Rathil
09.05.2015 12:13CDN + S3 того же Амазона выходит дешевле и практичней, чем просто S3
golotyuk
18.05.2015 13:07Cloudfront стоит $120, а S3 — $90 за терабайт. Получается дороже. На для оптимизации можно использовать гибридные схемы.
Rathil
18.05.2015 14:23aws.amazon.com/ru/s3/pricing
До 10 ТБ / месяц $0.090 за ГБ
GET и все остальные запросы $0.004 за 10 000 запросов
aws.amazon.com/ru/cloudfront/pricing
Первые 10 ТБ / месяц 0,085 USD
Запросы HTTP 0,0075 USD
Это если брать в расчет обмен трафиком только по Европе и Штатам.
nikitasius
08.05.2015 20:42Уменьшить размер до приемлемого. Нет смысла хранить и показывать оригинал фотографии размером 4000х3000 на сервере.
Если делать полноценную галерею, то следует оставить и оригиналы. Чтобы пользователь мог скачать не только адаптированный вариант, но и оригинал.
convert input.jpg -strip -resize 1000x1000 -quality 90 output.jpg
Это ужас! Eсть masondry, значит время плиток прошло.
В этом случаеconvert input.jpg -resize 1000x -quality 90 -auto-orient -gravity center output.jpg
- 1000 по длине, ширина авто
-auto-orient
— разворот картинки на основе EXIF данных-gravity center
— все манипуляции относительно центра
Так же пример для превью:
если исходник 800х600 к примеру, то после
convert input.jpg -resize "400x225^" -quality 90 -gravity center -crop 400x225+0+0 +repage output.jpg
получаем 400х225, притом, что 800х600 будет уменьшена до 400х300 и затем по центру вписана в кадр 400х225 (то бишь обрежет сверху и снизу, но оставит правильную геометрию).raveland
10.05.2015 01:19Вот ещё полезные на мой взгляд параметры:
-background white
белый фон вместо прозрачного слоя, который превращается в черный в jpg-flatten
склеить слои, например у psd или tiff-compress none
выключить компрессию в некоторых форматах, например miff+profile \"*\"
убрать лишнюю информацию (но в случае с -thumbnail оно делается автоматически)-interlace ...
включить или отключить постепенный показ изображения по мере загрузки-unsharp
правильные настройки сделают изображение получше
В случае большого количества манипуляций и разных размеров, разумно будет подготовить промежуточный размер.
Можно еще определять цветовой профиль изображения и, например, CMYK преобразовывать в sRGB.
Alexufo
13.05.2015 11:29Ну и что что есть Masondry. Он тормозит неимоверно.) Вот прям при загрузке подвисает.
nikitasius
13.05.2015 22:17В смысле он тормозит? Вы пишите без конкретики.
А конкретика: masondry ждет подгрузки всех изображений, которые с ним обвязаны в галерее, и только после этого показывает картинки.
У меня на нем пара самописных галерей с дизайном из демок, которые есть в гугле. Так если вы правильно ужали превьюшки и сервер у вас не находится в китае (а вы в европе), то на галереях в 50 картинок ни у кого проблем нету. Что до мобильных устройств — старый айпад работает без проблем на 357 картинках (15Мб).
Наконец, бесшовная догрузка реализуется на ajax, ну или по старинке кнопочки по страницам и никто не отменял использовать альтернативу.
marshinov
08.05.2015 22:44+1по поводу структуры хранения: ab/cd/ef/90/blah-blah.jpg это хорошо, но генерировать такие папки, особенно глубокой вложенности рандомом идея — так себе: вы будете сжирать inod'ы и важно, чтобы ваш алгоритм создания папок был действительно равномерно распределен, иначе в одних папках будет «пусто», а вдругих — «густо». Для многих проектов имеет смысл создавать на верхнем уровне папку вида yyyy-mm-dd, чтобы сразу было понятно где «древние» картинки, а где — нет. Так проще организовывать инкрементальный бекапы.
Если у вас не просто файла-помойка, то следует все-таки загружать картинки в разные папки, скажем avatars, products и т.д., иначе сложно потом найти концы.
Миниатюры лучше создавать по требованию и кешировать в файловой системе. Практика показывает, что новые размеры могут потребоваться довольно часто — поменялся дизайн, сетка стала другой, упс...., нужны новые размеры и теперь надо 2 недели создавать новые сайзы. По требованию же поменял один хелпер, «прогрел» сайт и переключил на новый дизайн. Можно создать новые миниатюры только на «свежие» картинки, а старенькие пусть создаются только по требованию для тех, кто листает на 134ую страницу каталога.uazure
13.05.2015 18:14А мне не совсем ясно, для чего нужна такая структура папок, какая задача решается?
Неужли доступ к файлу по заранее известному имени (+путь) как-то зависит от количества файлов в директории? Для каких ФС такое характерно? Хотелось бы ликвидировать свою безграмотность в этом вопросе.kamaikin
13.05.2015 18:22Ну если совсем в двух словах…
Если рассматривать очень упрощенно, то весь жесткий диск сервера разбит на небольшие разделы, которые пронумерованы. Каждый файл занимает некоторое количество этих небольших разделов. И чем больше файл, тем больше разделов он занимает.
Контроллер жесткого диска превращает понятную нам запись адреса файла ”/usr/var/www/file.bin” в понятную диску команду вернуть файл начинающийся с позиции 12345 и заканчивающийся в позиции 34567.
Вся информация о том, с какой по какую позицию читать, находится в соответствующих каталогах, и чем больше в каждом каталоге файлов, тем больше движений необходимо сделать головке винчестера для получения служебной информации о местоположении искомого файла. И соответственно потратить больше времени. Поэтому оптимальное количество файлов в каталоге достаточно четко определено. Появление SSD дисков, вносит некоторые коррективы в эти рассуждения, сильно увеличивая скорость поиска, и соответственно возможное количество файлов в каталогеuazure
22.05.2015 14:35В википедии про ext2 пишут:
Атрибуты файлов хранятся не в каталогах, как это сделано в ряде простых файловых систем, а в специальных таблицах. В результате каталог имеет очень простую структуру, состоящую всего из двух частей: номера индексного дескриптора и имени файла.
Думаю это справедливо и для многих других современных файловых систем. Может там есть еще какой-то ньюанс? То что листинг директорий с множеством файлов может приводить к тормозам — это ясно, но я не сталквивался с тем, что большое количество файлов в одной директории замедляет прямой доступ к этим файлам по известному полному имени
kamaikin
22.05.2015 18:37Ну полное имя не скажет контроллеру жесткого диска, в каком секторе лежит первый байт файла…
uazure
22.05.2015 21:17Полное имя файла каким-то образом драйвером фс преобразуется в начальный и конечный байт блочного устройства. Разве не файловая система хранит информацию о «блоках»? Да, эта инфа тоже где-то записывается на блочное устройство, в каких-то там интервалах байт. И эта информация хорошо кешируется. А уж как блочное устройство будет доставать файл — это уже могут быть разные реализации.
kamaikin
25.05.2015 10:01Для кого то и секунды на доступ к файлу достаточно, а кто то строит многоуровневое дерево, что бы 0.1 милисекунды добиться… все относительно…
И понятия «много файлов», «большая нагрузка» у каждого свои…
Если Вы с такой проблемой не сталкивались, то это не значит, что все всегда — «ОК».
questor
08.05.2015 23:56Подбор показателя сжатия может уменьшить размер исходного файла в несколько раз без заметного ухудшения качества. Логика такая: чем ниже качество — тем легче файл. Обычно используют показатель качества от 80 до 90.
Такие jpeg-файлы, сжатые gd с параметром 80...90 не нравятся сервису google page speed insights.
Ты им хоть 90, хоть 80 поставь — всё равно сервис будет говорить, что можно ещё уменьшить картинку без потери качества. И даже на 70ти, когда уже появляются различимые глазом артефакты — всё равно будет считать изображения неоптимальными и снимать баллы.
При этом изображения, которые предлагает гугл (там есть линк «скачать оптмизированные изображения») действительно и хорошо оптимизированы и потеря качеством человека незаметна. Как они это делают автоматически — не знаю, но либо я что-то делаю не так, либо gd'шная библиотека мало подходит для оптимизации (и как тогда автоматизировать их — непонятно).
PS Кому интересно — эксперимент проводился чем-то вроде такого:
<?php $tmp_name = $_SERVER["DOCUMENT_ROOT"].'/test1/img001.jpg'; $new_name = $_SERVER["DOCUMENT_ROOT"].'/test1/img001x90.jpg'; $params = getimagesize($tmp_name); $new_width = $params['0']; $new_height = $params['1']; $old_img = imagecreatefromjpeg($tmp_name); $new_img = imagecreatetruecolor($new_width, $new_height) ; imagecopyresampled ($new_img, $old_img, 0, 0, 0, 0, $new_width, $new_height, $params['0'], $params['1']) ; imagejpeg($new_img, $new_name, 90); ?>
т.е. просто пересохранялась картинка без изменения размеров (можно и imagecopyresampled выкинуть — при этом файлы точно такие же получаются).
Всякие сайты по оптимизации картинок знаю.
Если у кого есть рабочий вариант, как нужно правильно оптимизировать под page speed insights — поделитесь. Совет же «сжать gd до 80..90» я воспринимаю как неправильный ответ.Blumfontein
09.05.2015 08:03+2Дело в том, что в файле картинки кроме собственно самой картинки еще содержится куча всякой мета-информации и порой она занимает до 20-30% размера всего файла. GD с этим никак не работает, насколько мне известно. Необходимо картинку дополнительно обрабатывать специальными утилитами типа JpegTran.
Paskal
09.05.2015 00:08+1После этого можно показывать фотку прямо с Амазона
Вредные советы на Хабре. Если вы отдаёте что-либо из S3, вы платите за исходящий трафик (около $9 за 100Гб), и не можете ограничить отдачу — если я захочу двадцать миллионов раз скачать картинку с котиком на полтора мегабайта из вашей S3 корзины, мне никто не помешает. Всегда ставьте S3 за своим сервером, если хотите исключить риск удивиться счёту за услуги в начале нового месяца.mikhailov
17.05.2015 02:14Да, кэшируйший прокси перед S3 — правильный подход, если EC2 micro в том же регионе, то расходы ниже не только прямые, но и косвенные, такие как ограничение API запросов в секунду, возможность использовать HTTP 1.1 без шифрования
Rathil
09.05.2015 12:17+1Не помню с какой версии, но через convert тоже можно уже создавать webp. Раньше ставил гугловское приложение для этих целей, сейчас просто использую уже установленный ИмеджМеджик.
Timrael
10.05.2015 19:34Хочу посоветовать использовать еще ImageOptim для оптимизации картинок и фоток. Он применяет кучи известных алгоритмов для сжатия. Единственное будьте острожны с png оптимизаторами, некоторые из них занимают 20+ сек на картинку.
AlekVeritov
13.05.2015 12:03Это позволит избежать ситуации с тысячами файлов в одной папке (это тормозит работу файловой системы и вашу собственную).
А на каком основании делается вывод, что наличие тысяч файлов в одной папке тормозит работу фс?
По этому поводу есть немаловажный нюанс: в ext3, например, есть ограничение в 32К вложенных папок, а вот на количество файлов нет.kamaikin
14.05.2015 10:26Вспомните пожалуйста, что такое каталог с точки зрения файловой системы…
AlekVeritov
14.05.2015 11:25Полагаю, что каталог для ФС — это файл, который грубо говоря содержит в себе список файлов, «принадлежащих» ему. И с этой точки зрения в зависимости от ФС более длинный путь как раз будет медленнее, т.к. может просматриваться цепочка каталогов для определения уникального имени файла.
Просветите, пожалуйста, если я ошибаюсь.kamaikin
14.05.2015 15:21В общем Вы правы, но есть некоторые нюансы. В файловой системе под хранение информации о каталоге (список файлов) отводится определенное место. За точность цифр уже поручится не могу (давно этим занимался) но в NTFS это три сектора диска. то есть 16 килобайт.
Если мы кидаем больше файлов, чем влезает в эти 16 килобайт то головке винчестера приходится делать лишние движения по диску (на SSD просто поиск в большем списке, что не критично а вот на HDD критично очень.) для того, что бы собрать весь список, при этом пока весь список не будет прочитан с диска, местоположение файла который ищется на диске не будет получено, даже если он в списке первый.
Вот и получается, что первые три блока считываются за один проход головки ибо лежат в одном месте. А потом головка начинает дергатся в поисках продолжения. В общем, чем больше файлов в каталоге, тем больше движений головки диска… А по времени, поиск в двух вложенных каталогах занимает столько же времени как и поиск в одном каталоге где не 1000 а 1001 файл (цифры условные)
Как то так…
В каждом конкретном случае, да может быть закинуть в каталог больше файлов может быть выгоднее чем плодить поддиректории, но если мы не знаем сколько файлов может быть в каталоге, то выгоднее всетаки углубить путь но не выходить за какое то разумное количество. в 1000-1500 файлов в одном каталоге.neolink
14.05.2015 15:38+2каталог это по сути спискок inode вложенных файлов/каталогово и то чтобы обратиться к файлу по имени нужно их тупо перебрать, так вот вместо поиска по списку из миллиона элементов, можно искать в 256, что как бы быстрее, сравните:
поиск в списке 1 000 000 элементов, разбиваем это на aa/aa (равномерно 16 файлов в каталоге), нужно перебрать 256 + 256 + 16 = 528 элементов
также вы дружно забываете про кеш файловой системы в ram.
под линукс есть dir_index он выполняет индексацию inode через хеш таблицу по имени, что несколько убирает острую необходимость такой структурыkamaikin
14.05.2015 16:01+1каталог это по сути спискок inode вложенных файлов/каталогово и то чтобы обратиться к файлу по имени нужно их тупо перебрать, так вот вместо поиска по списку из миллиона элементов, можно искать в 256, что как бы быстрее, сравните:
поиск в списке 1 000 000 элементов, разбиваем это на aa/aa (равномерно 16 файлов в каталоге), нужно перебрать 256 + 256 + 16 = 528 элементов
Спасибо! Вы намного короче описали то, что я расписал выше!
В моей практике встречалась ситуация когда 6 терабайт в основном картинок (примерно по 1.5 мегабайта в среднем) было уложено в 4 каталога. В этом случае со всеми кешами и оптимизациями доступ к одному файлу все равно был около 5 секунд!!! На zfs если мне память не отшибло…mikhailov
17.05.2015 13:58Размер файлового кэша в памяти зависит от количества файлов в директории, который периодически можно чистить /bin/sync; echo 2 > /proc/sys/vm/drop_caches
uaoleg
13.05.2015 20:45Не совсем очевидно, почему оптимальная длинна имени папки — 2 символа?
Также интересно, какая оптимальная вложенность?
mikhailov
17.05.2015 01:57Вопрос аплоада изображений интересный и редко решаемый эффективно, обычно это multipart/form-data без проверки аутентификации перед загрузкой, это играет роль при регулярной загрузке файлов большого размера. Бэкэнд нагружается разбором содержимого и склеиванием данных, что в большинстве случаев избыточно и ресурсоемко. В случае с мобильным или Ajax-аплоадом можно обойтись без RFC 1867, приведу решение, которое мы применяем в продакшне больше года: coderwall.com/p/swgfvw/nginx-direct-file-upload-without-passing-them-through-backend
Torvald3d
Эта картинка вводит в ступор. Если увеличить размер — уменьшится качество, если увеличить качество — уменьшится размер. Круто, конечно, но как то не правдоподобно.
Еще хотелось бы узнать на счет одинаковых изображений. Если с форматами со сжатием без потерь все ясно — одинаковые файлы можно удалять, а хранить только один, то как быть с форматами со сжатием с потерями? В этом случае с виду одинаковые картинки на самом деле будут разными. Есть ли вообще смысл удалять дубликаты? Например, произошло какое-то глобальное событие — разные пользователи начинают загружать на сервис миллиард одинаковых фото этого события, как быть?
jMas
Думать в сторону библиотек создающих хэш по опорным точкам изображения?
neolink
загружать их, просто загрузить будет дешевле и правильнее любых не строких дедубликаций, если я изменил тона на фото это не значит что после загрузки я должен увидеть чужой вариант фотографии. + ошибки в таких алгоритмах.
В лучшем случае можно делать дедубликаю по хешу содержимого файла, она ещё и универсальная
kamaikin
md5 хеш от содержимого файла может помочь решить проблему… Можно отработать и расхождение файлов в принципе… Варианты решениия при необходимости есть.
Подробное описание решения — Статья
nikitasius
Я кстати проверял что быстрее, md5 или sha1, на мелких файлах разницы нету, но sha1 на 8 символов длинее.
На больших файлам sha1 как ни странно быстрее. xeon 1270v3
Alexufo
а пережатие фотографий? Наличие разных тегов? Мне кажется это надежнее habrahabr.ru/post/120562 и быстрее всего
Википедия, кстати умеет ловить дубли.
kamaikin
Пробовал. Идет приличная нагрузка на базу данных (я делал похожим образом) Сравнение делал через базу данных.
Попробуйте найти похожие SQL запросом в базе с парой милионов фоток… довольно ресурсоемко…
И любой алгоритм ошибается. Будет не приятно если при загрузки фото любимой бабушки сайт откажется грузить потому, что похоже на фото чьей то собачки)))) (такое было)
Alexufo
ресурсоемко, если нет особой разнцы. А какой тип таблиц? Но ведь отпечатки пальцев так и ищут. Лимит до 2 сек. с базами в сотню лямов.
Возможно проще раз в месяц прогой десктопной искать дубли. Ежели цель — место.
kamaikin
Ой вот про отпечатки пальцев не надо)))) Их вообще то по дактилоскопической формуле ищут. В компьютерных системах формула намного сложнее, чем для ручного поиска, но общий принцип остается тот же. Никто не сравнивает две картинки с отпечатками… Не смотрите детективы… они редко показывают, что и как действительно работает. Вы же не верите, что сравнительный анализ ДНК делается в оптическом микроскопе, как это показано в сериале «След» например?
Alexufo
Да детективы я не смотрю. Ищут отпечатки то все равно в бд потипу оракла и никуда от хешей они не уходят. Просто другие запросы и организация хранения в силу особенностей типа данных. 2 сек на сто лямовые бд это запросы текущего рынка. Типа США и Индии. Ну канеш перегнул чутка) Как раз недавно проводился конкурс и наши там показали прекрасные результаты.
habrahabr.ru/post/250725
akubintsev
Как показала практика md5-хеши по файлам изображений достаточно часто дают ложные коллизии. Приблизительно на 1.5 млн картинок было около 20 тысяч случаев.
kamaikin
Что странно… там вроде бы вероятность коллизии два в двестипятдесятшестой степени…
akubintsev
Да, это тоже меня удивило, но факт остался фактом. Разгребал последствия этого, когда пришёл работать в один крупный интернет-магазин.
neolink
а можете привести 2 осмысленные фотографии которые дали коллизии?
akubintsev
Сейчас я там уже не работаю, но из специфики можно было выделить только то, что преимущественно проблемы возникали с превью-картинками. Размер порядка 100х100px, формат JPEG.
S_Nil
Искусственно созданные
natmchugh.blogspot.com/2014/11/three-way-md5-collision.html
neolink
да, такое можно сделать специально, но получить даже 1 случай коллизии мд5 на обычных 1 500 000 файлов с разным контентом нереально
neolink
1.3% коллизий, это даже для crc32 на такой выборке дофига (1.5кк / 2 ^ 32 = 0.03%)
а 1.5кк значений это 4 * 10 ^-33 от всех возможных md5, что как бы намекает