Почему это важно?


На современных web сайтах объем картинок может составлять от 30% до 70% всего размера страницы. Например, объем изображений на Хабре обычно составляет несколько мегабайт.

размер фоток на странице

Большинство изображений в Web'e — это фотографии. Профильные фото в соц. сетях, альбом с телефона, профессиональные снимки и т.п. Правильная стратегия и инструменты для работы с фотографиями позволят сделать сайт быстрым для посетителей.


Формат для фотографий


Основной формат для хранения фотографий в Web'e — это JPEG. Однако иногда следует использовать и другие форматы.

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 на сервере.
  • Удалить все метаданные. Иногда объем такой инфы может составлять больше половины веса самого изображения.
  • Провести оптимизацию для уменьшения размера файлов. Это ускорит загрузку у посетителя.


image

Для этого существует ряд инструментов.

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)


Часто нужно иметь возможность показывать небольшие версии фотографий (например, миниатюра профильной фотки).
thumbnail фотки

Для этого необходимо генерировать нужные размеры при загрузке:

convert file.jpg -resize 50x50 file.s.jpg
convert file.jpg -resize 250x250 file.m.jpg


Тогда у каждого изображения будет соответствующая миниатюра.

Более удобный подход — генерировать превью на лету с помощью, например, Nginx image_filter модуля.

Поддержка Webp


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

image

Для каждой фотографии нужно сгенерировать webp версию:

cwebp file.jpg -o file.jpg.webp


Теперь необходимо отдать соответствующую версию картинки в зависимости от поддержки этого формата браузером:

server {
	...
	location ~* ^/.+\.(jpg|jpeg)$ {
	  if ($http_accept ~* "webp")    {
	      rewrite (.+) $1.webp;
	  }
	}
...
}


Облака


Облачные технологии развиваются и дешевеют. Если у вас нет специфических задач по обработке фоток, лучше присмотреться к варианту использования внешнего сервиса для их хранения и отдачи.

image

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)


  1. Torvald3d
    08.05.2015 14:48
    +10

    image
    Эта картинка вводит в ступор. Если увеличить размер — уменьшится качество, если увеличить качество — уменьшится размер. Круто, конечно, но как то не правдоподобно.
    Еще хотелось бы узнать на счет одинаковых изображений. Если с форматами со сжатием без потерь все ясно — одинаковые файлы можно удалять, а хранить только один, то как быть с форматами со сжатием с потерями? В этом случае с виду одинаковые картинки на самом деле будут разными. Есть ли вообще смысл удалять дубликаты? Например, произошло какое-то глобальное событие — разные пользователи начинают загружать на сервис миллиард одинаковых фото этого события, как быть?


    1. jMas
      08.05.2015 15:37

    1. neolink
      08.05.2015 16:12

      загружать их, просто загрузить будет дешевле и правильнее любых не строких дедубликаций, если я изменил тона на фото это не значит что после загрузки я должен увидеть чужой вариант фотографии. + ошибки в таких алгоритмах.
      В лучшем случае можно делать дедубликаю по хешу содержимого файла, она ещё и универсальная


    1. kamaikin
      08.05.2015 17:05

      md5 хеш от содержимого файла может помочь решить проблему… Можно отработать и расхождение файлов в принципе… Варианты решениия при необходимости есть.
      Подробное описание решения — Статья


      1. nikitasius
        08.05.2015 20:25
        +2

        Я кстати проверял что быстрее, md5 или sha1, на мелких файлах разницы нету, но sha1 на 8 символов длинее.
        На больших файлам sha1 как ни странно быстрее. xeon 1270v3


      1. Alexufo
        12.05.2015 01:47

        а пережатие фотографий? Наличие разных тегов? Мне кажется это надежнее habrahabr.ru/post/120562 и быстрее всего

        Википедия, кстати умеет ловить дубли.


        1. kamaikin
          12.05.2015 10:03

          Пробовал. Идет приличная нагрузка на базу данных (я делал похожим образом) Сравнение делал через базу данных.
          Попробуйте найти похожие SQL запросом в базе с парой милионов фоток… довольно ресурсоемко…
          И любой алгоритм ошибается. Будет не приятно если при загрузки фото любимой бабушки сайт откажется грузить потому, что похоже на фото чьей то собачки)))) (такое было)


          1. Alexufo
            13.05.2015 02:43

            ресурсоемко, если нет особой разнцы. А какой тип таблиц? Но ведь отпечатки пальцев так и ищут. Лимит до 2 сек. с базами в сотню лямов.

            Возможно проще раз в месяц прогой десктопной искать дубли. Ежели цель — место.


            1. kamaikin
              13.05.2015 10:32

              Ой вот про отпечатки пальцев не надо)))) Их вообще то по дактилоскопической формуле ищут. В компьютерных системах формула намного сложнее, чем для ручного поиска, но общий принцип остается тот же. Никто не сравнивает две картинки с отпечатками… Не смотрите детективы… они редко показывают, что и как действительно работает. Вы же не верите, что сравнительный анализ ДНК делается в оптическом микроскопе, как это показано в сериале «След» например?


              1. Alexufo
                13.05.2015 11:20

                Да детективы я не смотрю. Ищут отпечатки то все равно в бд потипу оракла и никуда от хешей они не уходят. Просто другие запросы и организация хранения в силу особенностей типа данных. 2 сек на сто лямовые бд это запросы текущего рынка. Типа США и Индии. Ну канеш перегнул чутка) Как раз недавно проводился конкурс и наши там показали прекрасные результаты.
                habrahabr.ru/post/250725


      1. akubintsev
        12.05.2015 11:15

        Как показала практика md5-хеши по файлам изображений достаточно часто дают ложные коллизии. Приблизительно на 1.5 млн картинок было около 20 тысяч случаев.


        1. kamaikin
          12.05.2015 11:30

          Что странно… там вроде бы вероятность коллизии два в двестипятдесятшестой степени…


          1. akubintsev
            12.05.2015 12:29

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


            1. neolink
              12.05.2015 12:51

              а можете привести 2 осмысленные фотографии которые дали коллизии?


              1. akubintsev
                12.05.2015 18:49

                Сейчас я там уже не работаю, но из специфики можно было выделить только то, что преимущественно проблемы возникали с превью-картинками. Размер порядка 100х100px, формат JPEG.


              1. S_Nil
                13.05.2015 08:39

                Искусственно созданные
                natmchugh.blogspot.com/2014/11/three-way-md5-collision.html


                1. neolink
                  13.05.2015 10:58

                  да, такое можно сделать специально, но получить даже 1 случай коллизии мд5 на обычных 1 500 000 файлов с разным контентом нереально


        1. neolink
          12.05.2015 13:04

          1.3% коллизий, это даже для crc32 на такой выборке дофига (1.5кк / 2 ^ 32 = 0.03%)
          а 1.5кк значений это 4 * 10 ^-33 от всех возможных md5, что как бы намекает


  1. Iktash
    08.05.2015 16:17

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


    1. edogs
      08.05.2015 16:24
      +3

      Облачные решения для «обычного использования» весьма дороги получаются.
      Мы в результате поигравшись в облака (где каждый раз считаешь сколько обойдется закачать/скачать данные или не дай бог посещаемость повалит внезапная от конкурентов), пришли к выводу, что дешевый сервер в германии за 40 евро с 4 ТБ места и 30Тб траффика на 200мбитном порте во-первых обойдется конкретно дешевле, а во-вторых спать будешь спокойнее… да и сам сайт на нем же можно захостить.


      1. sunnybear
        08.05.2015 16:45
        -2

        в принципе, да. Пока стоимость привлечения клиентов на востоке за Москвой не станет слишком высокой с серверами в Германии. Тогда нужен будет уже CDN по России


      1. raveland
        09.05.2015 16:11

        А что с самой простой отказоустойчивостью?


        1. edogs
          09.05.2015 22:19

          Отказоустойчивостью в каком именно плане?
          С железом/софтом? У облаков не так уж редко случаются проблемы, у амазона тоже эпик фэил был, у многих более мелких облаков данные несколько раз пропадали.
          Отказоустойчивость к ддос атакам? На облачном провайдере при этом влетаешь на такие деньги за ресурсы, что думаешь «ну его на фиг лучше бы упало».
          В случае своего сервера у тебя по крайней мере есть доступ к твоей железке через kvm, а не пассивно ждешь пока «что-то кто-то откуда-то восстановит».
          С нашей точки зрения по отказоустойчивости для «обычного использования» (опять же), сервер и облако примерно паритетны. Возможные проблемы разные, по разному решаются, но размер проблем в целом сравним.


          1. raveland
            09.05.2015 23:46

            Ну я конкретно интересовался как решаете проблему выхода из строя вашего сервера. Сервис продолжает работать?


            1. edogs
              11.05.2015 22:27

              В случае «обычного сайта» считаем вполне достаточным регулярные бакапы вдс-ки (вдс-ки на своем сервере, сайты уже на вдс-ках) на независимый бакап-сервер (чисто файловый или сайто-файловый готовый к работе), откуда сайт может быть развернут в рабочее состояние за время от 15 минут до пары часов (в зависимости от сценария).


  1. edogs
    08.05.2015 16:25
    +2

    substr(md5(microtime()), mt_rand(0, 30), 2)
    Как бы это развидеть:)


    1. neolink
      08.05.2015 16:29
      +2

      ну, а что в этом уж такого плохого?
      «критикуя — предлагай!»


      1. gnomeby
        08.05.2015 16:42
        +1

        преобразуйте microtime в строку, и возьмите последние 2 символа, получится тот же эффект.


        1. neolink
          08.05.2015 17:08

          вообще-то нет, в первом же приближении, microtime это [0-9] а md5 [0-9a-f], то есть для 2х символов в вашем случае будет 100 вариантов, а в исходном коде 256
          ну и хеш функция против Н микросекунд это немного разные уровни энтропии


          1. gnomeby
            08.05.2015 17:56
            +1

            Не придирайтесь, возьмите time заместо и три символа с конца будет вам и шире и равномерно.


      1. spuf
        08.05.2015 16:52
        +1

        $name = md5($photo) . '.jpg';
        $dir = substr($name, 0, 2) . '/' . substr($name, 2, 2);
        

        Будет: 02/c4/02c425157ecd32f259548b33402ff6d3.jpg


        1. neolink
          08.05.2015 17:01
          -1

          смысл этих уровней, чтобы файлы распределялись по ним как-можно равномернее, всякие «безымянный.jpg» и т.п. будут портить общую картину


          1. 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);
            


            В вашем случае:
            substr(md5(microtime()), mt_rand(0, 30), 2)
            
            MD5 и так дает равномерное распределение символов, совершенно излишне брать его подстроку в случайной позиции.


            1. neolink
              08.05.2015 18:23

              про случайную в принципе да особого смысла в этом нет, но на «развидеть» явно не тянет


              1. maximw
                08.05.2015 18:25

                Простите, отвечал вам, но случай, конечно, не ваш, а автора поста. Перепутал.


        1. neolink
          08.05.2015 17:14
          -1

          хотя если вы имели ввиду $photo из статьи, то реализация tmp_name лежит на операционке, да там банально может не быть 4х символов, или у вас может получится несколько больше уровней например 1236, или несколько меньше (вот пример значения tmp_name: /tmp/php/php1h4j1o), в общем вместо контролируемого поведения мы получаем platform specific


      1. edogs
        08.05.2015 18:27
        +1

        ну, а что в этом уж такого плохого?
        «критикуя — предлагай!»
        Избыточен и сходу непонятен. В нем видится куда более глубокий смысл чем есть.
        С учетом того, что «не больше 1000 файлов», mt_rand(1,999); был бы вполне достаточно, плюс было бы сразу понятно что код делает.


        1. Halfi
          12.05.2015 12:24

          Не понимаю, как между собой связан «mt_rand(1,999);» с фразой «не больше 1000 файлов»? Этот ранд никак не ограничит количество файлов в одной папке, а энтропия очень мала, чтобы выйти за рамки «1000 файлов в папке», достаточно всего 998 в квадрате файлов.


  1. spuf
    08.05.2015 16:45
    -3

    Ни слова про то, что надо держать HiDPI/Retina версии.


    1. akubintsev
      09.05.2015 22:51
      +2

      Не понятно, за что минусы. Человек дело говорит. У статьи название ведь не «о WebP».


  1. cy-ernado
    08.05.2015 17:10

    У webp мало перспектив относительно увеличения его популярности, разве только при полной доминации blink-браузеров (да и то вряд ли).
    Просто по политическим причинам. Mozilla принципиально не хочет webp, не обращая внимание на огромное количество запросов и уже реализованную функциональность, предложенную в патчах. Apple получает выгоду от многих закрытых патентов.

    Когда сам разбирался в этой теме, было очень грустно, что формат не хотят поддерживать.


    1. uazure
      08.05.2015 20:54
      +1

      А что мозилла проигрывает от того, что в фф будет webp? Или что выигрывает от его отсутствия?


      1. cy-ernado
        14.05.2015 15:02

        Ничего не проигрывает, ничего не выигрывает. Просто не хотят, оправдываясь кто чем может.

        Подробности можно найти тут:
        bugzilla.mozilla.org/show_bug.cgi?id=600919
        bugzilla.mozilla.org/show_bug.cgi?id=856375


    1. Rathil
      09.05.2015 12:11
      +1

      Не согласен. Давно его уже использую и, почти так, как описано в статье, за счётом небольших нюансов.
      На счёт поддержки, на хромиуме уже достаточно много браузеров и он занимает большую долю браузерного рынка. Даже экономя трафик на них — уже есть выигрыш, как минимум для самих пользователей, которые платят за трафик.
      К слову, Опера-турбо, именно так и оптимизирует изображения, пережимая все в вебп.


      1. Timrael
        10.05.2015 19:35

        Аналогично, на 60%+ юзеров можно нехило экономить трафика. Давно уже используем в проде.


      1. cy-ernado
        14.05.2015 15:00

        Я к тому, что дальше хромиума и его производных WebP не пойдет с высокой вероятностью.
        Использовать формат имеет смысл даже при 30% поддержке у пользователей, слишком уж он вкусный.
        С вами я полностью согласен :)


    1. dr1v3
      13.05.2015 10:43

      Когда-то Mozilla и h.264 наотрез отказывались поддерживать.


  1. lexore
    08.05.2015 18:49
    +1

    Храните терабайты и не парьтесь.
    Только не забывайте оплачивать счета.
    Облако полезно, когда неизвестно, насколько выстрелит.
    Потом выгоднее переводить на железный сервер.
    Можно перейти с s3 на что-то похожее, например на swift, минимальными правками кода.


  1. x88
    08.05.2015 20:18

    Если трафик большой, S3 будет отдавать довольно медленно, так что практически обязательно придется подключать CDN


    1. Rathil
      09.05.2015 12:13

      CDN + S3 того же Амазона выходит дешевле и практичней, чем просто S3


      1. golotyuk
        18.05.2015 13:07

        Cloudfront стоит $120, а S3 — $90 за терабайт. Получается дороже. На для оптимизации можно использовать гибридные схемы.


        1. Rathil
          18.05.2015 14:23

          aws.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

          Это если брать в расчет обмен трафиком только по Европе и Штатам.


  1. 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 (то бишь обрежет сверху и снизу, но оставит правильную геометрию).


    1. raveland
      10.05.2015 01:19

      Вот ещё полезные на мой взгляд параметры:

      • -background white
        белый фон вместо прозрачного слоя, который превращается в черный в jpg
      • -flatten
        склеить слои, например у psd или tiff
      • -compress none
        выключить компрессию в некоторых форматах, например miff
      • +profile \"*\"
        убрать лишнюю информацию (но в случае с -thumbnail оно делается автоматически)
      • -interlace ...
        включить или отключить постепенный показ изображения по мере загрузки
      • -unsharp
        правильные настройки сделают изображение получше

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


    1. Alexufo
      13.05.2015 11:29

      Ну и что что есть Masondry. Он тормозит неимоверно.) Вот прям при загрузке подвисает.


      1. nikitasius
        13.05.2015 22:17

        В смысле он тормозит? Вы пишите без конкретики.
        А конкретика: masondry ждет подгрузки всех изображений, которые с ним обвязаны в галерее, и только после этого показывает картинки.
        У меня на нем пара самописных галерей с дизайном из демок, которые есть в гугле. Так если вы правильно ужали превьюшки и сервер у вас не находится в китае (а вы в европе), то на галереях в 50 картинок ни у кого проблем нету. Что до мобильных устройств — старый айпад работает без проблем на 357 картинках (15Мб).
        Наконец, бесшовная догрузка реализуется на ajax, ну или по старинке кнопочки по страницам и никто не отменял использовать альтернативу.


  1. marshinov
    08.05.2015 22:44
    +1

    по поводу структуры хранения: ab/cd/ef/90/blah-blah.jpg это хорошо, но генерировать такие папки, особенно глубокой вложенности рандомом идея — так себе: вы будете сжирать  inod'ы и важно, чтобы ваш алгоритм создания папок был действительно равномерно распределен, иначе в одних папках будет «пусто», а вдругих — «густо». Для многих проектов имеет смысл создавать на верхнем уровне папку вида yyyy-mm-dd, чтобы сразу было понятно где «древние» картинки, а где — нет. Так проще организовывать инкрементальный бекапы.

    Если у вас не просто файла-помойка, то следует все-таки загружать картинки в разные папки, скажем avatars, products и т.д., иначе сложно потом найти концы.

    Миниатюры лучше создавать по требованию и кешировать в файловой системе. Практика показывает, что новые размеры могут потребоваться довольно часто — поменялся дизайн, сетка стала другой, упс...., нужны новые размеры и теперь надо 2 недели создавать новые сайзы. По требованию же поменял один хелпер, «прогрел» сайт и переключил на новый дизайн. Можно создать новые миниатюры только на «свежие» картинки, а старенькие пусть создаются только по требованию для тех, кто листает на 134ую страницу каталога.


    1. uazure
      13.05.2015 18:14

      А мне не совсем ясно, для чего нужна такая структура папок, какая задача решается?
      Неужли доступ к файлу по заранее известному имени (+путь) как-то зависит от количества файлов в директории? Для каких ФС такое характерно? Хотелось бы ликвидировать свою безграмотность в этом вопросе.


      1. kamaikin
        13.05.2015 18:22

        Ну если совсем в двух словах…
        Если рассматривать очень упрощенно, то весь жесткий диск сервера разбит на небольшие разделы, которые пронумерованы. Каждый файл занимает некоторое количество этих небольших разделов. И чем больше файл, тем больше разделов он занимает.

        Контроллер жесткого диска превращает понятную нам запись адреса файла ”/usr/var/www/file.bin” в понятную диску команду вернуть файл начинающийся с позиции 12345 и заканчивающийся в позиции 34567.

        Вся информация о том, с какой по какую позицию читать, находится в соответствующих каталогах, и чем больше в каждом каталоге файлов, тем больше движений необходимо сделать головке винчестера для получения служебной информации о местоположении искомого файла. И соответственно потратить больше времени. Поэтому оптимальное количество файлов в каталоге достаточно четко определено. Появление SSD дисков, вносит некоторые коррективы в эти рассуждения, сильно увеличивая скорость поиска, и соответственно возможное количество файлов в каталоге


        1. uazure
          22.05.2015 14:35

          В википедии про ext2 пишут:

          Атрибуты файлов хранятся не в каталогах, как это сделано в ряде простых файловых систем, а в специальных таблицах. В результате каталог имеет очень простую структуру, состоящую всего из двух частей: номера индексного дескриптора и имени файла.

          Думаю это справедливо и для многих других современных файловых систем. Может там есть еще какой-то ньюанс? То что листинг директорий с множеством файлов может приводить к тормозам — это ясно, но я не сталквивался с тем, что большое количество файлов в одной директории замедляет прямой доступ к этим файлам по известному полному имени


          1. kamaikin
            22.05.2015 18:37

            Ну полное имя не скажет контроллеру жесткого диска, в каком секторе лежит первый байт файла…


            1. uazure
              22.05.2015 21:17

              Полное имя файла каким-то образом драйвером фс преобразуется в начальный и конечный байт блочного устройства. Разве не файловая система хранит информацию о «блоках»? Да, эта инфа тоже где-то записывается на блочное устройство, в каких-то там интервалах байт. И эта информация хорошо кешируется. А уж как блочное устройство будет доставать файл — это уже могут быть разные реализации.


              1. kamaikin
                25.05.2015 10:01

                Для кого то и секунды на доступ к файлу достаточно, а кто то строит многоуровневое дерево, что бы 0.1 милисекунды добиться… все относительно…
                И понятия «много файлов», «большая нагрузка» у каждого свои…
                Если Вы с такой проблемой не сталкивались, то это не значит, что все всегда — «ОК».


  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» я воспринимаю как неправильный ответ.


    1. Blumfontein
      09.05.2015 08:03
      +2

      Дело в том, что в файле картинки кроме собственно самой картинки еще содержится куча всякой мета-информации и порой она занимает до 20-30% размера всего файла. GD с этим никак не работает, насколько мне известно. Необходимо картинку дополнительно обрабатывать специальными утилитами типа JpegTran.


      1. sunnybear
        09.05.2015 14:30
        +1

        + надстройкой над jpegtran — jpegrescan. Тогда GSI ничего не говорит


  1. Paskal
    09.05.2015 00:08
    +1

    После этого можно показывать фотку прямо с Амазона

    Вредные советы на Хабре. Если вы отдаёте что-либо из S3, вы платите за исходящий трафик (около $9 за 100Гб), и не можете ограничить отдачу — если я захочу двадцать миллионов раз скачать картинку с котиком на полтора мегабайта из вашей S3 корзины, мне никто не помешает. Всегда ставьте S3 за своим сервером, если хотите исключить риск удивиться счёту за услуги в начале нового месяца.


    1. zoonman
      10.05.2015 07:01

      А еще лучше сценарий, когда картинки отдает CDN, например Cloudflare.


    1. mikhailov
      17.05.2015 02:14

      Да, кэшируйший прокси перед S3 — правильный подход, если EC2 micro в том же регионе, то расходы ниже не только прямые, но и косвенные, такие как ограничение API запросов в секунду, возможность использовать HTTP 1.1 без шифрования


  1. Rathil
    09.05.2015 12:17
    +1

    Не помню с какой версии, но через convert тоже можно уже создавать webp. Раньше ставил гугловское приложение для этих целей, сейчас просто использую уже установленный ИмеджМеджик.



  1. Timrael
    10.05.2015 19:34

    Хочу посоветовать использовать еще ImageOptim для оптимизации картинок и фоток. Он применяет кучи известных алгоритмов для сжатия. Единственное будьте острожны с png оптимизаторами, некоторые из них занимают 20+ сек на картинку.


  1. AlekVeritov
    13.05.2015 12:03

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

    А на каком основании делается вывод, что наличие тысяч файлов в одной папке тормозит работу фс?
    По этому поводу есть немаловажный нюанс: в ext3, например, есть ограничение в 32К вложенных папок, а вот на количество файлов нет.


    1. kamaikin
      14.05.2015 10:26

      Вспомните пожалуйста, что такое каталог с точки зрения файловой системы…


      1. AlekVeritov
        14.05.2015 11:25

        Полагаю, что каталог для ФС — это файл, который грубо говоря содержит в себе список файлов, «принадлежащих» ему. И с этой точки зрения в зависимости от ФС более длинный путь как раз будет медленнее, т.к. может просматриваться цепочка каталогов для определения уникального имени файла.
        Просветите, пожалуйста, если я ошибаюсь.


        1. kamaikin
          14.05.2015 15:21

          В общем Вы правы, но есть некоторые нюансы. В файловой системе под хранение информации о каталоге (список файлов) отводится определенное место. За точность цифр уже поручится не могу (давно этим занимался) но в NTFS это три сектора диска. то есть 16 килобайт.
          Если мы кидаем больше файлов, чем влезает в эти 16 килобайт то головке винчестера приходится делать лишние движения по диску (на SSD просто поиск в большем списке, что не критично а вот на HDD критично очень.) для того, что бы собрать весь список, при этом пока весь список не будет прочитан с диска, местоположение файла который ищется на диске не будет получено, даже если он в списке первый.
          Вот и получается, что первые три блока считываются за один проход головки ибо лежат в одном месте. А потом головка начинает дергатся в поисках продолжения. В общем, чем больше файлов в каталоге, тем больше движений головки диска… А по времени, поиск в двух вложенных каталогах занимает столько же времени как и поиск в одном каталоге где не 1000 а 1001 файл (цифры условные)
          Как то так…
          В каждом конкретном случае, да может быть закинуть в каталог больше файлов может быть выгоднее чем плодить поддиректории, но если мы не знаем сколько файлов может быть в каталоге, то выгоднее всетаки углубить путь но не выходить за какое то разумное количество. в 1000-1500 файлов в одном каталоге.


          1. neolink
            14.05.2015 15:38
            +2

            каталог это по сути спискок inode вложенных файлов/каталогово и то чтобы обратиться к файлу по имени нужно их тупо перебрать, так вот вместо поиска по списку из миллиона элементов, можно искать в 256, что как бы быстрее, сравните:
            поиск в списке 1 000 000 элементов, разбиваем это на aa/aa (равномерно 16 файлов в каталоге), нужно перебрать 256 + 256 + 16 = 528 элементов
            также вы дружно забываете про кеш файловой системы в ram.
            под линукс есть dir_index он выполняет индексацию inode через хеш таблицу по имени, что несколько убирает острую необходимость такой структуры


            1. 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 если мне память не отшибло…


              1. mikhailov
                17.05.2015 13:58

                Размер файлового кэша в памяти зависит от количества файлов в директории, который периодически можно чистить /bin/sync; echo 2 > /proc/sys/vm/drop_caches


  1. uaoleg
    13.05.2015 20:45

    Не совсем очевидно, почему оптимальная длинна имени папки — 2 символа?
    Также интересно, какая оптимальная вложенность?


  1. 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