Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
при этом они изолированы от основного потока через две сериализованные очереди (очередь ожидающих обработки заданий и очередь выполненных заданий).А что если их на динамических ринг-буферах переписать (возможно чанками), я имею ввиду очереди задач, т.е. ngx_thread_task_post, ngx_thread_pool_cycle и иже с ними.
у нас там все равно уже лок естьТот другой всем локам-лок:
sendfile(). В этом отношении подход Мортона чуть более универсален, хотя менее эффективен и порождает маловероятный на практике, но всё же существующий race-condition между вызовом fincore() и соответвующим read() или sendfile(). С другой стороны fincore() нам не поможет при записи. При определенных условиях write() блокируется и хорошо бы об этом узнать заранее, чтобы отправить соответвующий таск в пул.Не могу поверить, что в самом популярном сервере поддержка пула потоков для длительных операций появилась только в 2015 году. При том, что паттерн Proactor известен науке по меньшей мере с 90-х.Не очень понял, какая логическая связь между двумя процитированными предложениями. Мне кажется её нет, но отвечу. Не было необходимости, да и сейчас в большинстве случаев включать пул потоков нет необходимости. Для большинства типичных задач он не нужен. И даже в тех случаях, когда он нужен, есть и другие варианты решения проблемы.
Забавно, что автор винит ОС в том, что нет возможности узнать, какие данные закешированы, а какие нет.И файловую систему пишите сами, и tcp-стек, и т.д. по списку. Как только вы начинаете кэшировать данные сами, то натыкаетесь на необходимость копировать огромные объемы данных из ядра в пользовательское пространство и обратно. Такой системный вызов, как
Кешируйте сами — делов-то!
sendfile() был создан специально для того, чтобы этим не заниматься. Вы наверное не сталкивались, когда производительность начинает упираться в память и приходится делать всё возможное, чтобы уменьшать количество копирований.Именно так работает, например, video download сервер известной социальной сети. То, что закешировано в памяти, он отдаёт сразу из потока-селектора. А за тем, чего в кеше нет, обращается асинхронно из отдельного пула. В результате один сервер отдаёт наружу до 40 Гбит/с, причём сам сервер написан даже не на C, а на «тормозной» Java.Безусловно есть разные подходы к решению задачи. Каждый подход имеет свои плюсы и минусы. Инженеры из известной социальной сети выбрали такой подход и мы не знаем всех факторов, которые повлияли на их решение, поэтому я не возьмусь, например, давать оценки.
sendfile. Я ж не зря ссылку на презентацию дал — там всё наглядно рассказано и показано. Создаёте один большой файл в /dev/shm, мапите в адресное пространство процесса. Работаете как с обычной памятью, разбиваете на блоки, вытесняемые по принципу LRU. А в сеть отдаёте блоки через sendfile, минуя user space./proc/sys/vm.sendfile? В нашем же случае мы без лишних копирований отправляем данные из того же кеша, заменив только sendfile на SSL_write. Конечно, 40 Гбит/с тут уже не будет, но 25 Гбит шифрованного трафика тоже немало./dev/shm плохо. Не хотите так делать — не надо, кто-нибудь другой сделает. Я ж не принуждаю, а просто делюсь положительным опытом.При этом столкнулись с проблемой вытеснения данных из кэша, до того, как отработает sendfile() и никак эту проблему не решили.Решили тривиальным reference counter'ом.
И ещё ни разу не видел, чтобы при наличии свободных страниц ядро начинало бы свопить если не преодолен рубеж swappiness.А я, вот, видел, как при
swappiness=0 Linux вместо освобождения page cache иногда начинает свопить полезную память. В тоже время со свопом кеша из /dev/shm проблем нет. Тем более, что кеш этот — одна непрерывная область, которая легко лочится через mlock. Так что метафора про «тыкву» неуместна.В свою очередь с за'map'ленными в память файлами есть серьезная проблема. Сейчас если у нас происходит ошибка чтения с дискаС какого диска? Мы мапим файл из tmpfs, он целиком в памяти.
Если мы будем копировать с диска в /dev/shm, то будет дополнительная работаСерьёзно? Если данные востребованы, и мы хотим их закешировать в памяти, как это можно сделать проще, не делая
read?приходится пробовать различные подходы, работать с вендорами жестких дисков, оптимизировать прошивку, драйвера, различные подсистемы ядра и сетевой стек, изобретать новый алгоритм для congestion control в TCPВот, как раз про всё это вас было бы очень интересно послушать :)
По-моему, вы сейчас пытаетесь на ходу придумать оправдания, почему кеширование в /dev/shm плохо. Не хотите так делать — не надо, кто-нибудь другой сделает. Я ж не принуждаю, а просто делюсь положительным опытом.У меня свое мнение на этот счет и свой опыт, поэтому я привожу аргументы в пользу того, что не стоит один положительный опыт обощать в качестве универсального решения.
Тем более, что кеш этот — одна непрерывная область, которая легко лочится через mlock. Так что метафора про «тыкву» неуместна.
С какого диска? Мы мапим файл из tmpfs, он целиком в памяти.И при этом файл пустой.
Серьёзно? Если данные востребованы, и мы хотим их закешировать в памяти, как это можно сделать проще, не делая read?Всё верно, изобретая промежуточный слой в виде tmpfs, вы вынуждены делать сперва read() и копировать в него данные.
Вот, как раз про всё это вас было бы очень интересно послушать :)Я ссылку и дал ниже на пару докладов Глеба Смирнова, который непосредственно работает с Netflix-ом и может гораздо больше и лучше меня об этом рассказывать.
$ uname -a
Linux 3.10.0-229.1.2.el7.x86_64 #1 SMP x86_64 GNU/Linux
$ nginx -V
nginx version: nginx/1.8.0
built by gcc 4.8.2 20140120 (Red Hat 4.8.2-16) (GCC)
...
--with-file-aio
--with-file-aio не имеет отношения к тредам, она про файловое AIO в ядре. NGINX должен быть собран с опцией --with-threads. В нашем репозитории на данный момент с ней собирается только mainline версия пакетов и для тех дистрибутивов, где glibc не слишком старый и в нём есть поддержка eventfd(). Попробуйте поставить 1.9.2.А именно воссоздадим наиболее тяжелые условия, заставив NGINX выполнять смесь блокирующих и неблокирующих чтений, когда проблема блокировок на обращениях к диску проявит себя в полной мере.Вы через строчку читаете?
И пока дисковая подсистема делает свою работу как может, обслуживая наш “паразитный” трафик с первой машины, NGINX использует оставшиеся ресурсы процессора и пропускную способность сети, чтобы обслужить второго клиента из памяти.
Я так и не понял, кто следит за тем, чтобы эти вот эти небольшие данные всегда лежали в памяти и не вымавались оттуда, несмотря на огромный фоновый disk load?Этим занимается операционная система. Если к данным регулярно обращаются, то они всегда всплывают наверх очереди в кэше страниц и не успевают из него вымываться. Пулы потоков тут не причем.
Можно ли например на location с сотнями тысяч картинок включить aio threads, а для location со статическими файлами дизайна сайта, которые всегда должны быть в памяти и отдаваться максимально быстро, не включать aio threads, не теряя в этом случае скорость на помещение задания в очередь?Можно.
Всё так. Смысла особого нет.
Подумал ещё и понял, что смысл всё-таки есть. Если sendfile() подолгу блокируется, то может возникнуть ситуация, когда все потоки из пула потоков окажутся заняты такими долгими вызовами, а в очереди на обработку будут накапливаться запросы от других клиентов. Чтобы все они как-то ротировались, сменяя друг друга, а не отваливались по таймауту, и может пригодится sendfile_max_chunks
Пулы потоков: ускоряем NGINX в 9 и более раз