Персистентная оперативна пам'ять

Сьогодні — розповідь про одну з ключових концепцій ОС Фантом. Втім, сама концепція, звичайно, існувала і до Фантома — фактично, у Танненбаума в кінці книги, там, де він дозволяє собі фантазувати, проглядаються обриси майже всіх особливостей Фантома, так що, в цілому, підхід досить очевидна для тих, хто хоча би задумується про майбутнє систем взагалі.

Персистентная оперативка — дуже проста і дуже непроста річ.

В цілому, все просто: уявіть собі, що вміст оперативної пам'яті зникає. Ніколи. Наприклад, при вимиканні комп'ютера. Або, наприклад, при… зникнення комп'ютера. «І душі померлих програм носяться над водою.». :)

Ну, дійсно неважливо: якщо ми змогли врятувати стан комп'ютера перед відключенням, то можна відновити цей стан в іншому. Таке ж. Взагалі такому ж? Прямо до мікросхеми? А якщо в ньому відеокарта інша — вже не можна?

Можна, тому що ми говоримо не про те, щоб заперсистить, зберегти стан комп'ютера, а тільки його оперативну пам'ять. Але тоді в цьому немає користі, скаже уважний читач — вже хоча б регістри треба б зберегти? Інакше відновлення тільки пам'яті не дозволить програмі працювати як якщо б нічого не відбувалося.

А завдання — саме така. Забезпечити програмі середу, в якій зупинка ОС і зупинка комп'ютера для програми виглядали виключно як натискання на кнопку «пауза» при перегляді фільму. Під час паузи «за програмою» можна навіть комп'ютер поміняти, але треба якось забезпечити ситуацію, в якій для продовження роботи програми буде абсолютно прозорим.

Це недосяжно, якщо вимога доводити до абсолюту. Стан хардвера зберегти і повністю відновити не можна. Але й не треба. Програмою не потрібна відеокарта, їй потрібен той же API і збережена картинка на екрані, а це — можна.

Що вимальовується: зберегти стан тільки оперативки — мало, а всього комп'ютера — нереально.

Інженерна кмітливість говорить нам, що треба специфікувати для програми деяку середу, якій по-перше, достатньо для самої програми, а по-друге, в рамках такого середовища повинно бути можливо виконати збереження консистентного стану програми і всього, що вона «бачить».

Легко бачити, що такий середовищем є специфікація операційної системи. Ну — не будь. Хорошою операційної системи. Системи, яка досить якісно приховує від програми деталі апаратури (і взагалі тлінність навколишнього світу).

Отже, взагалі-то, каже треба не про персистентной (віртуальної) пам'яті, а про персистентной середовищі виконання = персистентной ОС. Власне, це і є проект ОС Фантом, але сьогодні я принципово обмежуся, все ж, питанням тільки оперативки, інакше статтю не вийде дописати до ранку.

Отже, ми розуміємо, що персистентная пам'ять оточена іншими персистентными сервісами, і поки відкладаємо вбік.

Ясна так само і мета війни. Зрозуміла? Ні?

Мета — спростити життя програміста до непристойності. Позбавити його від роботи за серіалізації стейта програми. І від обмежень, які він на себе накладає, проектуючи внутрішнє подання даних в програмі, тримаючи в думці, що все це рано чи пізно доведеться втискати в прокрустове ложе потоку байт, яким є файл.

Ну — ось простий приклад: habrahabr.ru/company/2gis/blog/198564

Замість того, щоб воювати з ФС, можна просто забути про неї як про страшний сон. Очевидно, що це викликає масу питань про обмін даними, але, взагалі-то, зізнаємося собі, що обмін теж давно вже відбувається не через файли, а через REST/SOAP/whatever, і теж не в форматі серіалізації дерева в байт-стрім, а у вигляді запитів об'єктів чи «гілок» дерева об'єктів. Що, очевидно, відповідає зовсім не файлової» семантику, а тому поданню, яке сподручно для самої програми.

Добре, мета зрозуміла. Тепер засіб. Як же записати пам'ять на диск?

Ну, write( fd, (void *)0, get_mem_size() ), вірно? :)

Звичайно, немає. З багатьох причин. Та тому, що в пам'яті можуть бути «дірки» — не відображені нікуди області, доступ до яких заборонений. Та тому, що зовсім нема чого записувати те, що не змінювалося. Та той же код — навіщо? Та й, головне, тому, що це дико дорого.

І вже зовсім не важливо, що програму під час запису доведеться зупинити. А ось це вже нікуди не годиться взагалі.

Справа тут ось в чому. Якщо ми хочемо (а ми хочемо, щоб прикладна програма нам довіряла і правда не намагалася для спокою все-таки записатися в файл (а це вбиває всю ідею взагалі), треба гарантувати, немає ГАРАНТУВАТИ, що ми її обов'язково збережемо. Може бути, не зовсім в останньому стані (це не так важливо — вона повторить частина обчислень), але в цілісному і не позавчорашньому.

Тобто — стан програми (трохи пізніше ми з'ясуємо, що це стан всіх програм взагалі) не можна зберігати по-старому — перед вимиканням комп'ютера або ctrl-s, це треба робити постійно. Або, як мінімум, досить регулярно. І нерідко.

Навряд чи користувач, а тим більше — керований комп'ютером технологічний процес буде задоволений сполученням «зберігаю оперативну пам'ять» на хвилинку-другу.

Треба навчитися зберігати стан у фоновому режимі, потихеньку, прямо «під» працюючою програмою.

Але тоді воно буде неконсистентным! Ми зберегли ліву половину стану програми, а коли почали зберігати праву, програма вже напрацювала щось новеньке — половини «не зростуться» при рестарті. Програма додасть в ліву половину об'єкт, поставить на нього посилання з правої половини, а в «фотографії» стану виявиться, що посилання є, а об'єкта — немає.

Збережений стан має бути строго, абсолютно, консистентным. Але робити його треба послідовно.

Можна?

Можна.

Є безліч евристик, які дозволяють здешевити і полегшити такий процес, але в основі лежить звичайний COW, copy on write.

Якщо перебільшувати до межі, то фотографування стану зводиться до миттєвого перемикання всієї пам'яті в read only — це єдина (і вкрай недорога) операція, яку потрібно зробити атомарно. (Заздалегідь обмовимося, що перед нею потрібно загнати програми у стан, який повністю представлено в пам'яті. А не в регістрах процесора. Що теж нескладно і недорого).

Це, власне, «точка фотографування».

Далі процес набуває відому медитативність і може бути виконаний без виривання волосся з природних западин організму, спокійно і з розстановкою. Сторінки пам'яті можна спокійно записувати на диск одна за одною. А що ж програма? Вона, звичайно, не буде чекати і спробує в якусь сторінку пам'яті таки записати що-то. Така сторінка розділяється на пару — стара, незмінна копія встає в чергу на запис на диск (ближче до початку), а нова використовується і модифікується програмою. Коли запис на диск закінчиться, старі копії будуть знищені.

Як я вже говорив, це тільки чернетка. Є маса деталей. (Бажаючі підірвати мозок можуть заглянути в код прямо зараз.)

Очевидна оптимізація — записувати тільки diff-и. З минулого разу змінилося дуже не всі.

Настільки ж очевидна, але більш спірна і вимагає евристик оптимізація — щось записати до точки фотографування (і переключити в r/o), сподіваючись, що воно не зміниться. Тоді можна буде просто використовувати готовий записаний блок на диску, не повторюючи дискової операції для цієї сторінки пам'яті.

Зрозуміло, що робоче безліч програми (точніше, його не read only частина) потенційно подвоїться за час запису снапшота: якщо нам не пощастить, то поки ми будемо записувати стан, програма «перетрогает», перепишуть всі свої сторінки і всім їм доведеться виділити другу фізичну сторінку оперативної пам'яті. Тобто при невезіння витрати оперативки подвояться під час снапшота. Реально ситуація завжди м'якше, але «попит» на оперативку під час снапшота неминуче зростає. Щоб його задовольнити, не зупиняючи програми через брак оперативки, добре б перед снапшотом трохи підготуватися, позаписывать на диск сторінки, які змінилися — тоді у них можна буде відібрати фізичну сторінку пам'яті, якщо вона терміново потрібно в іншому місці. Знову ж таки, уважний читач побачить, що вище вже сказано про позаписывать на диск превентивно, але в інших цілях.

Превентивна запис покращує і інший показник. Латентність снапшота — час між «фотографування» і закінченням запису фотографії на диск.

Відзначу, що все це на сьогодні цілком реалізовано і працює в ядрі ОС.

У цьому місці поставимо крапку з комою. Через деякий час я постараюся написати статтю, яка зв'язує попередню тему — примітиви синхронізації — і цю. Тобто написати про проблеми реалізації примітивів синхронізації в персистентной пам'яті.

І це вже буде стаття про те, що досі як слід не зроблено. Тобто, в істотній мірі вона буде складатися з питань. :)

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.