КОРОВЫЕ коровы! Узнайте о механизме копирования при записи

Redis .NET HTTPS Linux

предисловие

Только лысина может стать сильнее

Читая «Проектирование и реализация Redis» о расширении хеш-таблицы, я нашел этот отрывок:

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

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

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

1. Копирование при записи под Linux

Прежде чем объяснять механизм копирования при записи в Linux, мы должны сначала узнать две функции:fork()иexec(). должен быть в курсеexec()это не конкретная функция, этособирательное название набора функций, который включаетexecl(),execlp(),execv(),execle(),execve(),execvp().

1.1 Простота использования с вилкой

Сначала давайте посмотрим наfork()Какая, черт возьми, функция:

fork is an operation whereby a process creates a copy of itself.

fork находится в Unix-подобных операционных системахсоздать процессосновной метод. вилка используется длясоздать дочерний процесс(эквивалент копии текущего процесса).

  • Новый процесс должен быть получен путем копирования самого себя из старого процесса, который является форком!

Если вы столкнулись с Linux, мы будем знать, что под LinuxПроцесс init — отец всех процессов(эквивалентно объекту Object в Java)

  • Все процессы Linux разветвляются (vfork) через процесс инициализации или подпроцесс инициализации.

Давайте проиллюстрируем вилку на примере:


#include <unistd.h>  
#include <stdio.h>  
 
int main ()   
{   
    pid_t fpid; //fpid表示fork函数返回的值  
    int count=0;
	
	// 调用fork,创建出子进程  
    fpid=fork();

	// 所以下面的代码有两个进程执行!
    if (fpid < 0)   
        printf("创建进程失败!/n");   
    else if (fpid == 0) {  
        printf("我是子进程,由父进程fork出来/n");   
        count++;  
    }  
    else {  
        printf("我是父进程/n");   
        count++;  
    }  
    printf("统计结果是: %d/n",count);  
    return 0;  
}  

В результате получается:


我是子进程,由父进程fork出来

统计结果是: 1

我是父进程

统计结果是: 1

объяснять:

  • fork вызывается как функция. Эта функция будет иметьвернуться дважды,будетPID дочернего процесса возвращается родительскому процессу, а 0 возвращается дочернему процессу.. (Если он меньше 0, значит, создание дочернего процесса не удалось).
  • Опять же: текущий процесс вызываетfork(), создаст дочерний процесс, точно такой же, как текущий процесс (за исключением pid), поэтому дочерний процесс также будет выполняться.fork()код после.

так:

  • Когда родительский процесс выполняет блок кода if,fpid变量Значением является pid дочернего процесса.
  • Когда дочерний процесс выполняет блок кода if,fpid变量значение равно 0

1.2 Давайте еще раз посмотрим на функцию exec()

Из вышеизложенного мы уже знаем, что fork создаст дочерний процесс.Дочерний процесс является копией родительского процесса.

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

  • Когда выполняется серия функций exec, ониНапрямую заменить адресное пространство текущего процесса.

Нарисую картинку для понимания:

exec函数的作用

Использованная литература:

1.3 Оглядываясь назад на COW под Linux

fork() создаст дочерний процесс, точно такой же, как родительский процесс (за исключением pid).

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

父进程的数据拷贝到子进程中

Однако по нашему опыту: часто дочерние процессы будут выполнятьсяexec()делать то, чего вы хотите достичь.

  • Таким образом, если вы следуете описанному выше подходу, бесполезно копировать прошлые данные при создании дочернего процесса (поскольку дочерний процесс выполняетexec(), исходные данные будут очищены)

Поскольку данные, копируемые в дочерний процесс, часто оказываются недействительными, существует технология Copy On Write, принцип которой также очень прост:

  • Дочерний процесс, созданный fork,Общая память с родительским процессом. То есть, если дочерний процессЕсли в области памяти не выполняется операция записи, данные в области памяти не будут скопированы в дочерний процесс., так что скорость создания дочерних процессов очень быстрая! (Никакого копирования, прямая ссылка на физическое пространство родительского процесса).
  • и если после возврата функции fork дочерний процесспервый разexec новый исполняемый образ, тогда он не будет тратить время и память.

Другое выражение:

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

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

Если это не для exec, ядро ​​выделит соответствующее физическое пространство для сегмента данных и сегмента стека дочернего процесса (пока что они имеют собственное пространство процесса и не влияют друг на друга), и сегмент кода продолжается. разделить физическое пространство родительского процесса (два кода точно такие же).

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

Технология копирования при записиПринцип реализации:

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

Технология копирования при записивыгодачто это?

  • технология COW можетуменьшатьпри выделении и дублировании больших объемов ресурсовМгновенная задержка.
  • Технология COW снижаетненужное выделение ресурсов. Например, при разветвлении процесса не нужно копировать все страницы, а родительский процессНи сегмент кода, ни сегмент данных только для чтения не могут быть изменены, поэтому нет необходимости копировать.

Технология копирования при записинедостатокчто это?

  • Если и родительский, и дочерний процессы должны продолжать писать после fork(),Тогда будет много ошибок пейджинга (страница ненормальное прерывание страница-ошибка), так что это не стоит потери.

Несколько слов, чтобы обобщить технологию копирования при записи в Linux:

  • Дочерний процесс из fork разделяет физическое пространство родительского процесса, когда родительский и дочерний процессыКогда есть операция записи в память, страница постоянной памяти прерывается,Скопируйте страницу памяти сработавшего исключения(Остальные страницы по-прежнему используются совместно с родительским процессом).
  • Реализация функции дочернего процесса из fork такая же, как и у родительского процесса. При необходимости воспользуемсяexec()Замените текущий образ процесса новым файлом процесса, чтобы завершить функцию, которую вы хотите достичь.

Использованная литература:

Во-вторых, объясните COW Redis

Исходя из вышеприведенного фундамента, мы уже должны понимать такую ​​технологию, как COW.

Позвольте мне рассказать о моем понимании отрывка из «Проектирование и реализация Redis»:

  • Когда Redis сохраняется, если используется команда BGSAVE или BGREWRITEAOF, RedisСоздайте дочерний процесс для чтения данных и записи их на диск..
  • В целом в Redis по-прежнему больше операций чтения. Если во время существования дочернего процесса происходит большое количество операций записи, может возникнутьМного ошибок пейджинга (страница прерывает ошибку страницы), что будет стоить много производительности при репликации.
  • пока вНа этапе перефразирования операции записи неизбежны.из. Итак, после того, как Redis разветвит дочерний процесс,Увеличьте порог коэффициента загрузки, сведите к минимуму операции записи, избегайте ненужных операций записи в память и максимально экономьте память.

Использованная литература:

3. COW файловой системы

Давайте посмотрим, что означает COW в файловой системе:

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

  • Например: чтобы изменить содержимое блока данных A, сначала прочитайте A и запишите его в блок B. Если в это время питание отключено, содержимое оригинального A все еще там!

Использованная литература:

Наконец

Наконец, давайте рассмотрим идею копирования при записи (выдержка из Википедии):

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

По крайней мере, из этой статьи мы можем сделать вывод:

  • Linux значительно улучшился благодаря технологии Copy On Write.Снижение накладных расходов на вилку.
  • Файловая система в определенной степени гарантируется технологией Copy On Write.целостность данных.

На самом деле в Java тоже есть технология Copy On Write.

Java中的COW

Эта часть останется в следующей статье, так что следите за обновлениями~

Если у вас есть лучший способ понять или в статье есть ошибки, пожалуйста, не стесняйтесь оставлять сообщение в области комментариев, чтобы мы могли учиться друг у друга~~~

Использованная литература:

ОдинПридерживайтесь общедоступной учетной записи оригинальной технологии Java: Java3y, приветствую всех, чтобы обратить внимание

Все 3 года оригинальные статьи: