Отдача файлов c помощью Nginx

Thank you for reading this post, don't forget to subscribe!

Nginx часто исполь­зу­ет­ся толь­ко для отда­чи фай­лов. Напри­мер, фай­ло­вый хостинг. На что сле­ду­ет обра­тить вни­ма­ние для опти­маль­ной настрой­ки Nginx под отда­чу круп­ных файлов?

Чуть подроб­нее о харак­те­ри­сти­ках нашей задачи:

  • Нуж­но парал­лель­но отда­вать мно­го файлов
  • Боль­шин­ство фай­лов круп­ные (более 5 Мб)
  • Мы отда­ем пото­ко­вое видео и нам необ­хо­ди­мо обес­пе­чить ком­форт­ный просмотр
  • Мы отда­ем зву­ко­вые фай­лы и необ­хо­ди­мо обес­пе­чить ком­форт­ное прослушивание

Что сле­ду­ет настроить?

sendfile

Как обыч­но рабо­та­ет Web сер­вер, при пере­да­че файла:

  1. откры­ва­ет­ся исход­ный файл (на диске)
  2. откры­ва­ет­ся файл назна­че­ния (сете­вое соединение)
  3. чита­ет­ся блок дан­ных, копи­ру­ет­ся в буфер и пере­да­ет­ся по назна­че­нию, пока не достиг­нут конец файла
  4. закры­ва­ют­ся оба файла

Это озна­ча­ет, что про­ис­хо­дит допол­ни­тель­ное копи­ро­ва­ние, кото­рое вынуж­ден делать Web сер­вер. В этом слу­чае сер­вер дела­ет систем­ные вызо­вы read и write. Систем­ный вызов sendfile слу­жит как раз для того, что­бы избе­жать излиш­не­го копи­ро­ва­ния и обес­пе­чить пря­мую пере­да­чу фай­ла. Вклю­чай­те эту опцию (все­гда):

tcp_nopush

Дирек­ти­ва раз­ре­ша­ет или запре­ща­ет исполь­зо­вать опции TCP_NOPUSH во FreeBSD или TCP_CORK в Linux. "tcp_nopush on" полез­но для sendfile(), nginx в этом слу­чае выво­дит дан­ные пол­ны­ми паке­та­ми. После того, как весь запрос обра­бо­тан, TCP_CORK/TCP_NOPUSH выклю­ча­ет­ся, что при­во­дит в сбро­су послед­не­го непол­но­го пакета.

tcp_nodelay

Дирек­ти­ва раз­ре­ша­ет или запре­ща­ет исполь­зо­вать опцию TCP_NODELAY (при пере­хо­де соеди­не­ния в состо­я­ние keep-alive). Перед пере­хо­дом соеди­не­ния в keepalive nginx выво­дит дан­ные вызо­ва­ми writev() доста­точ­но боль­ши­ми пор­ци­я­ми для запол­не­ния паке­та ("postpone_output 1460"), поэто­му дан­ные долж­ны ухо­дить без задер­жек и TCP_NODELAY не нужен. А вот с послед­ним непол­ным паке­том может слу­чит­ся неболь­шая задерж­ка, если соеди­не­ние не закры­ва­ет­ся. Для это­го и нуж­но вклю­чить TCP_NODELAY:

directio

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

# Фай­лы более 10Мб Nginx будет читать с дис­ка минуя опе­ра­ци­он­ный кеш

expires

Посколь­ку мы име­ем дело со ста­ти­че­ски­ми фай­ла­ми, и есть веро­ят­ность того, что один и тот же поль­зо­ва­тель смо­жет несколь­ко раз запро­сить один и тот же файл, сле­ду­ет вклю­чить кли­ент­ское кеши­ро­ва­ние. Это дости­га­ет­ся уста­нов­кой опции "expires max", кото­рая отпра­вит бра­у­зе­ру нуж­ные заголовки:

limit_rate

Это доста­точ­но важ­ная опция. Она поз­во­ля­ет огра­ни­чить ско­рость отда­чи фай­лов. В том слу­чае, если Вы отда­е­те пото­ко­вое видео, либо музы­ку, Вам сле­ду­ет уста­но­вить огра­ни­че­ния на ско­рость отда­чи. Это поз­во­лит сэко­но­мить канал и обслу­жить боль­ше клиентов:

# Огра­ни­чи­ва­ем ско­рость отда­чи до 196Кб/с

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

В Nginx так­же есть воз­мож­ность уста­но­вить порог отда­чи, после кото­рой огра­ни­че­ние вой­дет в силу. Так­же име­ет смысл для пото­ко­во­го медиа (в этом слу­чае пер­вая ука­зан­ная часть будет отда­вать­ся без ограничений):

# Огра­ни­че­ние ско­ро­сти отда­чи будет накла­ды­вать­ся после 1Мб

Фай­лы, кото­рые запра­ши­ва­ют­ся очень часто име­ет смысл кеши­ро­вать в памяти.