Примечания к чтению: нулевое копирование и некоторые расширения

Linux

Содержание в основном относится к двум колонкам Geek Time, и я, кстати, просто делаю заметки для себя.
Ни Пэнфэй «Практика оптимизации производительности Linux», раздел 02, 03
Тао Хуэй «Настройка производительности системы должна знать и знать», Раздел 04

Это один из наиболее часто задаваемых вопросов на собеседовании, и он, вероятно, является продолжением Кафки, и ранее он подробно не резюмировался. Меня уже спрашивали многие читатели и коллеги, и мой ответ не был хорошим, поскольку в то время мое понимание было расплывчатым. Теперь, в эти несколько дней, я могу читать много контента от других авторов. После прочтения некоторого связанного контента я вернусь и упомяну его сейчас. Следует учитывать, что я лучше понимаю это.

Как бы вы реализовали передачу файлов?

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


Обычно вы выберете самый прямой метод: после нахождения пути к файлу на диске из сетевого запроса, если файл относительно большой, предположим, 320 МБ, вы можете выделить в памяти буфер 32 КБ, а затем разделить файл на 10 000 Каждая копия имеет размер всего 32 КБ Таким образом, 32 КБ считываются с начала файла в буфер, а затем 32 КБ отправляются клиенту через сетевой API. Затем повторите 10 000 раз, пока не будет отправлен весь файл. Как показано ниже:




Однако производительность этой схемы невелика, в основном по двум причинам.

Во-первых, он прошел не менее 40 000 раз.Переключение контекста между пользовательским режимом и режимом ядра. так какДля каждого обработанного сообщения размером 32 КБ требуется один вызов чтения и один вызов записи.,Каждыйсистемный вызовВы должны сначала переключиться из пользовательского режима в режим ядра, а затем переключиться из режима ядра обратно в пользовательский режим после того, как ядро ​​завершит задачу.. Видно, что на каждые обработанные 32 КБ приходится 4 переключения контекста, а после 10 000 повторений — 40 000 переключений.

этосистемный вызовсодержание, мы можем объединить следующие дополнительные три "переключатель контекста" понять,переключатель контекстаСуществует три типа процессов, потоков и прерываний.

Дополнение: Переключение контекста процесса

По уровню привилегий LinuxРабочее пространство процесса разделено на пространство ядра и пространство пользователя., соответственно, соответствующие следующему рисунку,Кольцо 0 и кольцо 3 уровня привилегий ЦП. Пространство ядра (кольцо 0) имеет самые высокие привилегии и может напрямую обращаться ко всем ресурсам, в то время как пространство пользователя (кольцо 3) может получать доступ только к ограниченным ресурсам,Аппаратные устройства, такие как память, не могут быть доступны напрямую и должны бытьсистемный вызовзастрял в ядре, чтобы получить доступ к этим привилегированным ресурсам.

С другой точки зрения, процесс может выполняться как в пространстве пользователя, так и в пространстве ядра.Когда процесс запускается в пользовательском пространстве, это называется пользовательским состоянием процесса, а когда он попадает в пространство ядра, это называется состоянием ядра процесса.. Для перехода из пользовательского режима в режим ядра требуетсясистемный вызовЧто нужно сделать. Например, когда мы просматриваем содержимое файла, нам нужно несколько системных вызовов для завершения: сначала вызовите open(), чтобы открыть файл, затем вызовите read(), чтобы прочитать содержимое файла, и вызовите write(), чтобы записать содержимое. в стандартный вывод и, наконец, вызовите close(), чтобы закрыть файл.

Так как же процесс системного вызова переключает контекст процессора? Давайте разберемся еще с двумя понятиями:

  1. регистры процессора,ДаНебольшая, но чрезвычайно быстрая память, встроенная в ЦП.

  2. счетчик команд, используется дляСохраняет местоположение инструкции, выполняемой ЦП,или позиция следующей инструкции для выполнения. они все процессорныеПеред запуском любой задачи необходимые зависимости, поэтому его еще называютКонтекст ЦП.

Зная, что такое контекст ЦП, я думаю, вам будет легко понять переключение контекста ЦП.Переключение контекста ЦП, то есть сначала сохранить контекст ЦП (то есть регистры ЦП и счетчик программ) предыдущей задачи, а затем загрузитьновое заданиеКонтекст этих регистров и программный счетчик, и, наконец, переход к новому местоположению, на которое указывает программный счетчик, и запуск новой задачи. и этиСохраненный контекст будет сохранен в ядре системы и загружен снова, когда задача будет перепланирована для выполнения. Это гарантирует, что исходное состояние задачи не будет затронуто, так что задача будет выполняться непрерывно..

назадсистемный вызовК проблеме исходного регистра ЦППозиция команды в пользовательском режиме должна быть сохранена в первую очередь. Затем, чтобы выполнить код режима ядра, регистры ЦП должныОбновите новое расположение инструкций режима ядра. Последнее — перейти в режим ядра, чтобы запустить задачу ядра.После завершения системного вызова регистры ЦП должныВосстановить исходное сохраненное состояние пользователя, а затем переключитесь в пространство пользователя, чтобы продолжить выполнение процесса. Следовательно, в процессе системного вызова фактически происходит два переключения контекста процессора.

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

  1. Переключение контекста процесса, которое относится к переключению спереключаться с одного процесса на другойбегать.

  2. системный вызовв процессевсегда один и тот же процессБег.

Итак, в чем разница между переключением контекста процесса и системным вызовом? Во-первых, вы должны знать,Процессы управляются и планируются ядром, а переключение процессов может происходить только в режиме ядра.. Таким образом, контекст процесса включает в себя не только ресурсы пространства пользователя, такие как виртуальная память, стеки и глобальные переменные, но также и состояние пространства ядра, например стеки и регистры ядра. Следовательно, переключение контекста процесса — это на один шаг больше, чем системный вызов: перед сохранением состояния ядра текущего процесса и регистров ЦП,Сначала необходимо сохранить виртуальную память и стек процесса, после загрузки состояния ядра следующего процесса также необходимо обновить виртуальную память и пользовательский стек процесса.

Процесс сохранения и восстановления контекстов не является «бесплатным» и требует, чтобы ядро ​​работало на ЦП для его завершения.


Каждое переключение контекста занимает от десятков наносекунд до микросекунд процессорного времени. Это время довольно значительное, особенно в случае большого количества переключений контекста процесса, легко заставить ЦП тратить много времени на сохранение и восстановление таких ресурсов, как регистры, стеки ядра и виртуальная память, что сильно сокращает реальное время работы, время обработки. Linux управляет отношениями отображения между виртуальной и физической памятью через TLB (трансляционный резервный буфер). При обновлении виртуальной памяти необходимо также обновить TLB, и доступ к памяти также будет медленнее. Особенно в многопроцессорных системах, где кеш совместно используется несколькими процессорами, очистка кеша повлияет не только на процесс текущего процессора, но и на процессы других процессоров, которые совместно используют кеш.

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

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

Примерно так понимаются виртуальные адреса и физические адреса.Каждый процесс имеет свое собственное независимое пространство памяти 4G, и пространство памяти каждого процесса имеет аналогичную структуру. Когда новый процесс устанавливается, он устанавливает свое собственное пространство памяти.Данные, код и т. д. этого процесса копируются с диска в его собственное пространство процесса.Какие данные где находятся, записывается task_struct в таблице управления процессом , и он будет иметь связанный список, который записывает выделение пространства памяти, какие адреса имеют данные, какие адреса не имеют данных, какие адреса доступны для чтения, а какие могут быть записаны, все это может быть записано через этот связанный список. Пространство памяти, выделенное каждому процессу, сопоставляется с соответствующим дисковым пространством.

Но у компьютера явно не так много памяти (нужно n*4G для n процессов). Кроме того, для создания процесса необходимо скопировать файлы программы с диска в память, соответствующую процессу, для случая нескольких процессов, соответствующих одной программе, эта операция вообще не требуется.

Таким образом, объем памяти 4G для каждого процесса составляет всего лишьпространство виртуальной памяти,КаждыйЧтобы получить доступ к адресу в пространстве памяти, вам необходимо преобразовать адрес в фактический адрес физической памяти..Все процессы используют одну и ту же физическую память, каждый процесс обрабатывает только себяв настоящее время требуетсяПространство виртуальной памяти отображается и хранится в физической памяти. Процессу необходимо знать, какие адреса памяти находятся в физической памяти, а какие нет в физической памяти и где в физической памяти.таблица страницзаписать. Каждая запись в таблице страниц делится на две части, первая часть записываетнаходится ли эта страница в физической памяти, вторая часть записываетадрес страницы физической памяти(если имеется). Когда процесс обращается к виртуальному адресу и просматривает таблицу страниц, если он обнаруживает, что соответствующие данные отсутствуют в физической памяти, возникает исключение ошибки страницы. Процесс обработки исключения ошибки страницы заключается в копировании данных, требуемых процессом, с диска в физическую память.

Узнав о потенциальных проблемах с производительностью при переключении контекста процесса, давайте рассмотрим, когда следует переключать контексты процесса. Очевидно, что переключение контекста необходимо только тогда, когда процесс запланирован. Linux поддерживает очередь готовности для каждого ЦП, сортирует активные процессы (то есть процессы, которые выполняются и ожидают ЦП) в соответствии с приоритетом и временем ожидания ЦП, а затем выбирает процесс, который больше всего нуждается в ЦП, то есть процесс с наивысшим приоритетом и дождаться запуска процесса с наибольшим временем процессора.

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

Во-первых, чтобы убедиться, что все процессы могут получитьсправедливое планирование, процессорное время делится на кванты времени, этиЗатем временной интервал назначается каждому процессу по очереди.. Таким образом, когда квант времени процесса исчерпан, он будет приостановлен системой и переключится на другие процессы, ожидающие запуска ЦП.
Во-вторых, процессНедостаточно системных ресурсов(Например, при нехватке памяти) он не может работать, пока ресурсы не будут удовлетворены.В это время процесс также будет приостановлен, и система запланирует запуск других процессов.
В-третьих, когда процесс проходит метод снаКогда вы приостанавливаете себя, естественно перенесут.
В-четвертых, когдапроцесс с более высоким приоритетомПри запуске, чтобы обеспечить выполнение процесса с высоким приоритетом, текущий процесс будет приостановлен и запущен процессом с высоким приоритетом.
последнее случаетсяаппаратное прерываниеКогда ЦП прерывается, процесс в ЦП будет приостановлен, и вместо этого будет выполняться подпрограмма обслуживания прерывания в ядре.

переключение контекста потока


Самая большая разница между потоком и процессом заключается в том, чтоПоток — это основная единица планирования, а процесс — это основная единица владения ресурсами.. Грубо говоря, так называемое планирование задач в ядре на самом делеОбъект планирования — поток; а процесс просто отдает потокПредоставляет такие ресурсы, как виртуальная память и глобальные переменные.. Итак, для потоков и процессов мы можем понять это так:

  1. Когда процесс имеет только один поток, можно считать, что процесс равен потоку.
  2. Когда процесс имеет несколько потоков, эти потоки совместно используют одни и те же ресурсы, такие как виртуальная память и глобальные переменные. Эти ресурсы не нужно изменять во время переключения контекста.
  3. Кроме того, у потоков также есть свои приватные данные, такие как стеки и регистры, которые также необходимо сохранять при переключении контекста.


Таким образом, переключение контекста потоков фактически можно разделить на два случая:

Во-первых, два потока до и после принадлежат разным процессам. В настоящее время, поскольку ресурсы не используются совместно, процесс переключения аналогичен процессу переключения контекста.

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

переключение контекста прерывания

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


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

Точно так же, поскольку прерывания прерывают планирование и выполнение обычных процессов, большинство обработчиков прерываний являются короткими и лаконичными, чтобы выполнение завершалось как можно быстрее. Кроме того, как и переключение контекста процесса, переключение контекста прерывания также потребляет ресурсы ЦП. Слишком большое количество переключений будет потреблять много ресурсов ЦП, что серьезно снизит общую производительность системы.

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

Назад к нулевому копированию


В нашем только что сценарии на каждые обработанные 32 КБ приходится 4 переключения контекста, а после 10 000 повторений — 40 000 переключений. Стоимость переключения контекста немалая.Хотя переключение занимает от десятков наносекунд до нескольких микросекунд, большое количество одновременных служб увеличит потребление такого времени. Во-вторых, это решение сделало 40 000 копий памяти, а количество байтов, скопированных в файл размером 320 МБ, также увеличилось в четыре раза до 1280 МБ. Очевидно, что слишком много копий памяти без необходимости потребляют ресурсы ЦП и снижают производительность системы по параллельной обработке. Итак, чтобы повысить производительность передачи файлов, вам нужно начать сУменьшить частоту переключения контекста и количество копий памятиНачните с двух направлений.

Как нулевое копирование повышает производительность передачи файлов?


Опять же, почему вам нужно переключать контекст при чтении файла на диске? Это потому что,Чтение диска или управление сетевой картой осуществляется ядром операционной системы..Ядро отвечает за управление всеми процессами в системе., у него самые высокие привилегии, а рабочая среда совершенно отличается от пользовательского процесса. Всякий раз, когда наш код выполняет системный вызов, такой как чтение или запись, должны произойти 2 переключения контекста:Сначала переключитесь из пользовательского режима в режим ядра, когда ядро ​​завершит выполнение задачи, переключитесь обратно в пользовательский режим и передайте его коду процесса для выполнения.. Поэтому, если вы хотите уменьшить количество переключений контекста, вы должны уменьшить количество системных вызовов. Решение состоит в том, чтобы объединить два системных вызова чтения и записи в один и завершить обмен данными между диском и сетевой картой в ядре.


Во-вторых, мы должны подумать, как уменьшить количество копий памяти. 4 копии памяти за такт, 2 из которых необходимы для физического устройства, в том числе:Скопируйте содержимое диска в память, а память скопируйте на сетевую карту. Но остальные 2 действия копирования, связанные с пользовательским буфером, не нужны, потому что в сценарии с отправкой дискового файла в сеть нет причин для существования пользовательского буфера. Если ядро ​​читает файл,Скопируйте содержимое PageCache непосредственно в буфер сокета., а затем уведомить процесс после отправки сетевой карты, поэтому есть только 2 переключения контекста и 3 копии памяти.



Если сетевая карта поддерживает технологию SG-DMA (The Scatter-Gather Direct Memory Access), то копию буфера сокета можно удалить, чтобы всего осталось 2 копии памяти. В процессе передачи данных DMA требуется, чтобы исходный физический адрес и целевой физический адрес были последовательными. Однако последовательные адреса памяти не обязательно являются последовательными физически, поэтому передачи DMA делятся на несколько завершений. Если прерывание вызвано после передачи блока физически непрерывных данных, хост выполнит следующий блок физически непрерывной передачи данных. Метод DMA Scatter-gather отличается тем, что он использует связанный список для описания физически прерывистого пространства хранения, а затем сообщает мастеру DMA первый адрес связанного списка. После передачи части физически непрерывных данных мастер DMA не должен инициировать прерывание, а передает следующую порцию физически непрерывных данных согласно связанному списку, а затем инициирует прерывание до тех пор, пока передача не будет завершена.

По сути, это технология нулевого копирования. Это новая функция, предоставляемая операционной системой, которая принимает как файловый дескриптор, так и TCP-сокет в качестве входных параметров, так чтоПри выполнении копия памяти может быть полностью завершена в состоянии ядра, что не только уменьшает количество копий памяти, но и уменьшает количество переключений контекста.. Более того, после того, как нулевое копирование отменит пользовательский буфер, это не только уменьшит потребление пользовательской памяти, но иМаксимально использовать память в буфере сокета, косвенно уменьшая количество системных вызовов., что дает возможность значительно сократить количество переключений контекста.


Можно вспомнить, что для передачи файла размером 320 МБ, когда не использовалась нулевая копия, в пользовательском буфере было выделено 32 КБ памяти, а для передачи файл был разбит на 10 000 копий, но откуда взялись 32 КБ? Почему не 32 МБ или 32 байта? Это связано с тем, что при отсутствии нулевого копирования нам нужно максимальное использование памяти.Если пользовательский буфер слишком велик, он не может скопировать сообщение вбуфер сокета(здесь размер сокета ограничен); если пользовательский буфер слишком мал, это вызовет слишком много системных вызовов чтения/записи.


Тогда почему пользовательский буфер не такого размера, как буфер сокета? Это потому что,Свободное пространство буфера сокета динамически изменяется, который используется как для скользящих окон TCP, так и для буферов приложений, а также зависит от общей системной памяти. Особенно в сети с длинным жиром диапазон его вариаций особенно велик.


Нулевое копирование освобождает нас от необходимости заботиться о размере буфера сокета. Например, при вызове метода отправки с нулевым копированиемЕсли возможно, установите количество отправленных байтов равным общему количеству неотправленных байтов файла., например 320 МБ, возможно, размер буфера сокета в это время составляет 1,4 МБ, тогда клиенту будет отправлено 1,4 МБ за один раз вместо 32 КБ. Это означает, что для 1 нулевой копии размером 1,4 МБ имеется только 2 переключения контекста, в то время как без нулевой копии и пользовательского буфера размером 32 КБ происходит 176 (4 * 1,4 МБ/32 КБ) переключений контекста.


Исходя из вышеизложенного, для передачи файла размером 320 МБ, упомянутого в начале статьи, при размере буфера сокета около 1,4 МБ требуется всего более 400 переключений контекста и более 400 копий памяти, а объем скопированных данных составляет всего 640 МБ.Таким образом, не только сократится задержка запроса, но и будет потребляться меньше ресурсов ЦП для обработки каждого запроса, что позволит поддерживать большее количество одновременных запросов.


Кроме того, Zero Copy использует технологию PageCache.

PageCache, дисковый кеш


Оглядываясь на вышесказанное, вы обнаружите, что при чтении файла файл диска сначала копируется в PageCache, а затем копируется в процесс. Зачем это делать? Есть две причины.


Поскольку диск намного медленнее, чем память, мы должны найти способДиск для чтения-записи заменяется памятью для чтения-записи., такие как копирование данных с диска в память, вы можете заменить считываемый диск на считываемую память. Однако объем памяти намного меньше диска, и лишь малая часть данных на диске предназначена для копирования в память. Как правило, данные, к которым только что был осуществлен доступ, имеют высокую вероятность повторного доступа в течение короткого периода времени. Кэшировать данные, к которым недавно обращались, с помощью PageCache, когда места малоУдаление кешей, к которым не обращались в течение длительного времени(т. е. алгоритм LRU).При чтении с диска сначала ищите PageCache, если данныевозвращаться напрямую, что значительно повышает производительность чтения диска.


А при чтении данных с диска нужно сначала найти местонахождение данных, для механического диска это повернуть головку к сектору, где находятся данные, а затем начать последовательное чтение данных. Среди них вращение головы занимает много времени.Чтобы уменьшить его влияние, PageCache используетчитать впередФункции. То есть, хотя метод чтения считывает только байты 0-32 КБ, ядро ​​будетпосле этого32-64 КБ также читаются в PageCache, после чего 32 КБ читаются дешево. Если процесс считывает PageCache до того, как будет удалено 32-64 КБ, преимущества будут очень большими. Это обязательно произойдет в сценарии передачи файлов в этой лекции.


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


В частности, впередавать большие файлыкогда. Например, если вам нужно передать много гигабайтных файлов, ядро ​​будет загружать их в PageCache всякий раз, когда пользователь обращается к этим большим файлам, и эти большие файлы быстро заполняют ограниченный PageCache. Однако из-за размера файлаВероятность повторного доступа к определенной части файла на самом деле очень мала.. Это приводит к 2 проблемам: во-первых, поскольку PageCache долгое время занят большими файлами,Горячие маленькие файлы не в полной мере используют PageCache, они читаются медленнее; во-вторых,Большие файлы в PageCache не пользуются преимуществами кэширования, но их копирование в PageCache более одного раза требует ресурсов ЦП.. Поэтому в сценариях с высокой степенью параллелизма, чтобы предотвратить заполнение PageCache большими файлами, он больше не будет влиять на маленькие файлы.Большие файлы не должны использовать PageCache и, следовательно, не должны обрабатываться с использованием методов нулевого копирования.Если я возьму просмотр фильма в качестве примера, если я хочу посмотреть только первые 10 минут, мне придется скачать весь фильм, что, очевидно, является потерей. При обработке больших файлов в сценариях с высоким параллелизмом вместо технологии нулевого копирования следует использовать асинхронный ввод-вывод и прямой ввод-вывод.

Асинхронный ввод-вывод + прямой ввод-вывод


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





Асинхронный ввод-вывод (асинхронный ввод-вывод может обрабатывать как сетевой ввод-вывод, так и дисковый ввод-вывод, здесь мы фокусируемся только на дисковом вводе-выводе) может решить проблему блокировки. Он делит операцию чтения на две части, первая половинаИнициировать запрос на чтение к ядру, но немедленно вернуться, не дожидаясь, пока данные будут на месте, после чего процесс может одновременно обрабатывать другие задачи.. когдаПосле того, как ядро ​​скопирует данные с диска в буфер процесса, процесс получит уведомление от ядра и затем обработает данные., что является второй половиной асинхронного ввода-вывода. Как показано ниже:





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


Сценариев приложения для прямого ввода-вывода не так много, но есть два основных: Во-первых, в приложении уже реализовано кэширование дисковых файлов, что не требует повторного кэширования PageCache, что вызовет дополнительное потребление производительности. Например, базы данных, такие как MySQL, используют прямой ввод-вывод, во-вторых, большие файлы передаются в условиях высокой параллелизма.Как мы упоминали выше, большие файлы трудно попасть в кеш PageCache, что приводит к дополнительным копиям в памяти, а также сжимает использование PageCache для небольшие файлы требуют памяти, поэтому в это время следует использовать прямой ввод-вывод.


Недостатком прямого ввода-вывода является то, что он не может пользоваться преимуществами PageCache, то есть ядро ​​(алгоритм планирования ввода-вывода) будет пытаться кэшировать как можно больше последовательных операций ввода-вывода в PageCache и, наконец, сливаться в более крупный ввод-вывод и отправлять его в диска, что может сократить поиск на диске.Кроме того, ядро ​​​​также предварительно прочитает последующий ввод-вывод и поместит его в PageCache, чтобы уменьшить дисковые операции. Он не может этого сделать

резюме

Чрезмерное копирование памяти и переключение контекста могут снизить производительность при передаче файлов на основе пользовательских буферов. технология нулевого копированияв ядреЗавершение копирования памяти естественным образом уменьшает количество копий памяти. это через системный вызовСочетает чтение с диска и отправку по сетидве операции,Уменьшенное переключение контекстачастота. В частности, поскольку копирование выполняется в ядре, оно можетМаксимальное использование буферов сокетовсвободного пространства, тем самым увеличив один разсистемный вызовОбъем данных, обрабатываемых в системе, еще больше снижает количество переключений контекста.

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

Советы: На самом деле, если вы используете твердотельный накопитель, такой как SSD (без вращения головки), PageCache не окажет большого влияния.Подробности см. в статье SSD в моей предыдущей статье.

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

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