предисловие
Три слова «нулевая копия» наверняка слышали многие из вас.Эта технология используется в различных компонентах с открытым исходным кодом, таких как kafka, RocketMQ, Netty, nginx и других фреймворках с открытым исходным кодом. Итак, сегодня я хочу поделиться с вами некоторыми знаниями о нулевом копировании.
передача данных в компьютер
Прежде чем представить нулевое копирование, я хочу поговорить о том, как данные передаются в компьютерной системе. При разработке системы передачи данных, ради написания этой части, я пожертвовал принципом компьютерной композиции, который я вытирал много лет:
Ранняя стадия:
Разбросанные соединения, серийная работа, программные запросы. На этом этапе ЦП выступает в роли няни и должен считывать данные с интерфейса ввода-вывода, а затем отправлять их в основную память.
Конкретный процесс этого этапа:- CPU активно запускает устройство ввода/вывода
- Затем ЦП продолжает спрашивать старое железо устройства ввода-вывода, готовы ли вы.Обратите внимание, что это всегда спрашивает.
- Если устройство ввода-вывода сообщает ЦП: я готов. CPU считывает данные с интерфейса ввода/вывода.
- Затем ЦП продолжает передавать эти данные в основную память, как курьер.
Этот неэффективный процесс передачи данных занимает ЦП, а ЦП не может выполнять другие более значимые действия.
Интерфейсный модуль и каскад прямого доступа к памяти
Эту часть мы также обсудим позже.
интерфейсный модуль
В структуре фон Неймана каждый компонент имеет отдельное соединение, которое является не только первым, но и затрудняет расширение устройств ввода-вывода.Ранний этап выше — это система, которая называется децентрализованным соединением. Расширение устройства ввода-вывода требует подключения большого количества проводов. Поэтому вводится метод подключения к шине, и несколько устройств подключаются к одной и той же группе шин для формирования общего канала передачи между устройствами.
Это также структура обмена данными наших домашних компьютеров или некоторых небольших калькуляторов.В этом режиме обмен данными принимает метод прерывания программы.Выше мы знаем, что после того, как мы запускаем устройство ввода-вывода, мы спрашиваем, готово ли устройство ввода-вывода.Если этот этап удален, прерывание программы очень хорошо.Исполнилось наше давнее желание:
- CPU активно запускает устройство ввода/вывода.
- После запуска ЦП нет необходимости снова запрашивать ввод-вывод, и он начинает делать другие вещи, похожие на асинхронность.
- После того, как ввод-вывод готов, сообщите ЦП, что я готов, через прерывание шины.
- ЦП считывает данные и передает их в оперативную память.
DMA
Хотя вышеописанный метод улучшает коэффициент использования ЦП, ЦП все еще занят во время прерывания.Для дальнейшего решения проблемы занятости ЦП вводится метод DMA.В методе DMA основная память и устройство ввода/вывода Существует канал передачи данных, поэтому при обмене данными между оперативной памятью и устройствами ввода-вывода нет необходимости снова прерывать ЦП.
Вообще говоря, нам нужно обратить внимание только на DMA и прерывания.Ниже приведены некоторые из них, подходящие для больших компьютеров.Вот краткое введение:
сцена с канальной структурой
В небольших компьютерах DMA можно использовать для реализации обмена данными между высокоскоростными устройствами ввода-вывода и хостом, однако в больших и средних компьютерах существует множество конфигураций ввода-вывода, и передача данных является тривиальной. DMA используется, будет ряд проблем.
- Каждое устройство ввода-вывода конфигурируется с выделенным интерфейсом DMA, что не только увеличивает стоимость оборудования, но и решает проблему конфликтов доступа DMA и ЦП, что очень усложняет управление.
- Процессору необходимо управлять многочисленными DMA-интерфейсами, что также влияет на эффективность работы.
Поэтому вводится канал.Канал используется для управления устройством ввода/вывода и компонентами, которые обмениваются информацией между основной памятью и устройством ввода/вывода.Его можно рассматривать как процессор со специальными функциями. Это выделенный процессор, подчиненный ЦП, который не принимает непосредственного участия в управлении, поэтому использование ресурсов ЦП улучшается.
Этапы с обработчиками ввода/вывода
Система ввода-вывода развилась до четвертой стадии, появился процессор ввода-вывода. Процессор ввода-вывода, также известный как периферийный процессор, работает независимо от хоста и может не только выполнять управление вводом-выводом, которое должно выполняться каналом ввода-вывода, но также выполнять обработку формата, исправление ошибок и другие операции. операции. Система вывода с процессором ввода-вывода имеет более высокую степень параллелизма с работой ЦП, что означает, что система ввода-вывода имеет большую независимость от хоста.
резюме
Мы видим, что целью эволюции передачи данных было снижение использования ЦП и улучшение использования ресурсов ЦП.
копия данных
Давайте сначала представим наши сегодняшние потребности.На диске есть файл, и теперь его нужно передать по сети. Если да, то что делать? Я считаю, что благодаря некоторым из приведенных выше вступлений у вас должны появиться некоторые идеи.
традиционная копия
Если мы реализуем его в коде Java, у нас будет следующая реализация: Ссылка на псевдокод выглядит следующим образом:
public static void main(String[] args) {
Socket socket = null;
File file = new File("test.file");
byte[] b = new byte[(int) file.length()];
try {
InputStream in = new FileInputStream(file);
readFully(in, b);
socket.getOutputStream().write(b);
} catch (Exception e) {
}
}
private static boolean readFully(InputStream in, byte[] b) {
int size = b.length;
int offset = 0;
int len;
for (; size > 0;) {
try {
len = in.read(b, offset, size);
if (len == -1) {
return false;
}
offset += len;
size -= len;
} catch (Exception ex) {
return false;
}
}
return true;
}
Это наш традиционный метод копирования.Конкретная схема потока данных выглядит следующим образом, PS: Здесь не рассматривается, что данные в куче нужно копировать в прямую память при передаче данных в Java.
Видно, что нашему менеджеру нужно пройти четыре этапа, 2 DMA, 2 прерывания ЦП, всего четыре копии, четыре переключения контекста, и он будет занимать два ЦП.
- ЦП отправляет инструкции DMA устройства ввода-вывода, а DMA передает данные с нашего диска в буфер ядра в пространстве ядра.
- Второй этап запускает прерывание ЦП, и ЦП начинает копировать данные из буфера ядра в кеш нашего приложения.
- ЦП копирует данные из кеша приложения в буфер сокета в ядре.
- DMA копирует данные из буфера сокета в буфер сетевой карты.
Достоинства: низкая стоимость разработки, подходит для некоторых невысоких требований к производительности, например некоторых систем управления, думаю должно хватить
Недостатки: несколько переключений контекста, использование нескольких процессоров и низкая производительность.
sendFile реализует нулевое копирование
Как насчет нулевой копии выше? Позиционирование в вики: обычно относится к тому, что когда компьютер отправляет файл по сети, ему не нужно копировать содержимое файла в пространство пользователя (User Space) и напрямую передает его в сеть в пространстве ядра ( пространство ядра).
В java NIO FileChannal.transferTo() реализует sendFile операционной системы, мы можем выполнить вышеуказанные требования с помощью следующего псевдокода:
public static void main(String[] args) {
SocketChannel socketChannel = SocketChannel.open();
FileChannel fileChannel = new FileInputStream("test").getChannel();
fileChannel.transferTo(0,fileChannel.size(),socketChannel);
}
Мы заменили наш сокет и fileInputStream выше каналом в java.nio, тем самым завершив нашу нулевую копию.
Вышеупомянутый конкретный процесс выглядит следующим образом:
- Когда вызывается sendfie(), ЦП отправляет инструкцию, называемую DMA, для копирования данных с диска в буфер ядра.
- После завершения копирования DMA выдается запрос на прерывание, а ЦП копируется и копируется в буфер сокета. Вызов sendFile завершается и возвращается. 3. DMA копирует буфер сокета в буфер сетевой карты.
Вы можете видеть, что мы вообще не копировали данные в кеш нашего приложения, поэтому этот подход является нулевым копированием. Тем не менее, этот метод по-прежнему очень болезненный, хотя он сводится всего к трем копиям данных, он по-прежнему требует от ЦП прерывания копирования данных. Зачем? Потому что DMA должен знать адрес памяти, прежде чем я смогу отправить данные. Поэтому в ядро Linux 2.4 были внесены улучшения, и соответствующая информация описания данных (адрес памяти, смещение) в буфере ядра записывается в соответствующий буфер сокета. В итоге формируется следующий процесс:
Таким образом, ЦП не участвует в копировании всего процесса, поэтому эффективность является наилучшей.
Подобные коды есть в Netty, RocketMQ и kafka в сторонних фреймворках с открытым исходным кодом, если интересно, можете поискать самостоятельно.
сопоставление mmap
Мы упомянули о реализации нулевого копирования выше, но мы можем только отправить данные пользователю в неповрежденном виде и не можем использовать их сами. Поэтому Linux предоставляет специальный способ доступа к дисковым файлам, который может связать определенное адресное пространство в памяти с дисковым файлом, который мы хотим указать, чтобы преобразовать наш доступ к этой памяти в доступ к дисковым файлам. Отображение. Мы используем эту технологию, чтобы напрямую сопоставить файл с адресом памяти пользовательского режима, так что операция с файлом больше не является записью/чтением, а напрямую оперирует адресом памяти.
Полагаясь на MappedByteBuffer для сопоставления mmap в Java, конкретный MappedByteBuffer может обратиться к этой статье за подробностями:Woohoo.Краткое описание.com/afraid/send 90866 low cost….
Наконец
С тех пор тайна нулевого копирования также была раскрыта.Нулевое копирование предназначено только для уменьшения использования ЦП и позволяет ЦП выполнять более реальные бизнес-задачи. Благодаря этой статье вы можете увидеть, как Нетти делает нулевое копирование, я думаю, это произведет более глубокое впечатление.
Наконец, эта статья была включена в JGrowing, всеобъемлющий и отличный маршрут изучения Java, совместно созданный сообществом.Если вы хотите участвовать в обслуживании проектов с открытым исходным кодом, вы можете создать его вместе.Адрес github:GitHub.com/Java растет…Пожалуйста, дайте мне маленькую звезду.
Если вы считаете, что эта статья полезна для вас, или если у вас есть какие-либо вопросы и вы хотите предоставить бесплатный VIP-сервис 1 на 1, вы можете подписаться на мой официальный аккаунт Ваше внимание и пересылка - самая большая поддержка для меня, O(∩_∩)O :