В последнее время достаточно часто меня охватывает чувство, что когда-то со мной уже что-то похожее происходило. Это состояние носит название "дежавю" и в одном небезызвестном фильме (кстати, одном из самых мной любимых) свидетельствовало о сбое в матрице. Сейчас постараюсь объяснить.

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

Сколько помню себя в профессии, так было всегда. Фортран на мейнфреймах (ЕС-1022, ЕС-1045/1046) сменился PL/1, затем мейнфреймы остались позади, появились СМ и ДВК с РАФОС (клоном RT-11), на которых я программировал на Pascal. Еще немного времени прошло, и вот уже на столе стоит ЕС-1840 с клоном CP/M-86, по-моему, он назывался М86, точно не помню, но помню, что команды можно было набирать и по-русски (например, кат) и по-английски (тот же dir). Затем, на тех же компах, появился Альфа-ДОС, к счастью, его прообраз (MS-DOS) не заставил себя долго ждать. И вот уже вовсю стал использоваться компилятор Microsoft C (тут можно глянуть доки, причем, учтите - у нас этого богатства не было и в помине), затем появляются продукты от Borland - Turbo Pascal (я начинал с версии 3.0) и, конечно же, Turbo C (вот тут я успел на первую версию). Позже мы стали работать под Windows 3.1, хотя, казалось, еще совсем недавно не понимали, зачем вот это вот все надо (правда, тогда была версия 2, еще "плоская"). C и Pascal все еще удерживали пальму первенства, но первый постепенно был заменен C++, а второй сначала эволюционировал в Object Pascal, а затем и в Delphi. Windows тоже эволюционировал - NT 4.0, Windows 95/98 (как ни странно, но именно в этой последовательности - сначала NT), затем XP, и, наконец, значительно позже - Windows 7... Сейчас везде, кроме виртуалок - Windows 10 (upgrade с Windows 8/8.1). Но тут, хотя бы, была некоторая преемственность. А, да, еще надо упомянуть переход с desktop-ной БД Paradox (мы использовали ее во многом благодаря существованию библиотеки Paradox Engine) на серверную SQL БД Oracle (начинал с версии 7.3). Потом были еще .Net и C#, и, наконец, Java (начинал с  1.4). И вот теперь Linux (как пользователь) и контейнеризация (Docker).

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

Итак, нудное вступление, пожалуй, закончено, перейду к сути. Я пытаюсь самостоятельно хостить сервисы, которые считаю важными и полезными. Мощного "железа" у меня нет, на текущий момент сервером работает ноутбук с i3 процессором и 8 Гигабайтами памяти, на нем установлен Windows 10, не ругайте меня за это, так сложилось. На этом, с позволения сказать, сервере созданы три виртуалки (используется VirtualBox), на которых установлены Debian (в моем случае, до сих пор Jessie) с Docker, а сами сервисы подняты в соответствующих контейнерах. Ресурсы виртуалкам выделены не ахти какие, особенно по памяти, так как основная ОС (Windows 10) тоже хочет кушать.

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

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

Как kswapd загружает процессор

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

И именно тут меня настигло дежавю, так сильно эта ситуация напоминала ругаемую сторонниками Linux Windows - там тоже время от времени может выявиться какой-нибудь странный процесс, который, ни с того ни с сего, возьмет и отъест всю мощь CPU. Но в Windows, за долгие годы, я к этому привык и даже знаю, что и в каком случае надо делать. А тут я новичок, тут знания надо нарабатывать. Да и потом, Linux, вроде, должен был быть лишен такого рода заморочек, разве нет? 😜

Первый вопрос, который требует ответа: что такое этот процесс, насколько верна моя догадка, что он связан со swap-ом? Надо сказать, что найти описание процесса kswapd оказалось не так-то просто. Большинство предлагаемых ответов на запрос к Google сразу ведут на статьи о проблемах с этим процессом и путях их решения, и да, в основном - это проблема с высокой нагрузкой на CPU. В выборке, все же, нашлось краткое описание этого демона, а так же более подробное описание самой задачи, для решения которой и предназначен kswapd.

Если подытожить то, что удалось почитать, то получается, что этот процесс стартует во время запуска системы и большую часть времени проводит в "спячке". Информация о том, чем и когда этот демон "пробуждается" немного противиречива: в одних источниках указывается, что "просыпается" он по таймеру, в других - что его "дергает" распределитель физических страниц памяти (physical page allocator). В любом случае, если количество свободных страниц физической памяти меньше определенного порога (этим параметром можно управлять), то процесс начинает сохранять наименее используемые страницы во вторичной памяти, обычно, на диск. На самом деле, алгоритм работы сложнее, например, используются кэши swap-а, ну и все в таком роде, но самое главное, все должно работать без тех самых сторонних эффектов, которые происходят у меня, и которые описывают многочисленные пострадавшие в своих вопросах/комментариях в интернете.

Почему мы имеем то, что имеем, для меня остается пока тайной. В треде по похожей проблеме в Ubuntu писали, что во всем виновата ошибка в коде ядра, и что в новых версиях ситуация должна быть исправлена. Но! Запись эта старая, а есть вопросы, заданные уже для более современных версий. Так что, тайна не раскрыта. Но, что интересно, есть рабочее решение.

Лучше всего, на мой взгляд, как разобраться с проблемой описано вот по этой ссылке: A solution for kswapd0 going haywire on #Linux. Надо сказать, что мне пока довелось пару раз опробовать только вторую часть - сиюминутную очистку pagecache:

echo 1 > /proc/sys/vm/drop_caches
Очистка pagecache

Выполнять эту команду следует из под суперпользователя (речь про root-а, естественно), или же воспользоваться такой модификацией:

echo 1 | sudo tee /proc/sys/vm/drop_caches
Очистка pagecache при помощи sudo

если пользователю системы, под которым вы работаете, разрешено пользоваться командой sudo. Так вот, я работал под root-ом и все замечательно разрешилось!

Но все же, что это за волшебные манипуляции? Вот выдержка из документации, касающаяся данной команды:

drop_caches‌‌‌‌

Writing to this will cause the kernel to drop clean caches, as well as reclaimable slab objects like dentries and inodes.  Once dropped, their memory becomes free.

‌‌‌‌To free pagecache:
‌‌echo 1 > /proc/sys/vm/drop_caches

‌‌‌‌To free reclaimable slab objects (includes dentries and inodes):
‌‌echo 2 > /proc/sys/vm/drop_caches‌‌‌‌

To free slab objects and pagecache:
echo 3 > /proc/sys/vm/drop_caches

‌‌‌‌This is a non-destructive operation and will not free any dirty objects. To increase the number of objects freed by this operation, the user may run `sync' prior to writing to /proc/sys/vm/drop_caches.  This will minimize the number of dirty objects on the system and create more candidates to be dropped.

‌This file is not a means to control the growth of the various kernel caches (inodes, dentries, pagecache, etc...)  These objects are automatically reclaimed by the kernel when memory is needed elsewhere on the system.

‌‌Use of this file can cause performance problems.  Since it discards cached objects, it may cost a significant amount of I/O and CPU to recreate the dropped objects, especially if they were under heavy use.  Because of this, use outside of a testing or debugging environment is not recommended.

‌‌‌‌You may see informational messages in your kernel log when this file is used

:‌‌cat (1234): drop_caches: 3

‌‌‌‌These are informational only.  They do not mean that anything is wrong with your system.  To disable them, echo 4 (bit 2) into drop_caches.

Если излагать вкратце, то эта команда позволяет очистить всевозможные кэши и, таким образом, освободить память, которой так не хватает системе. Какие кэши должны быть очищены определяется записываемым значением. Надо также отметить, что важен сам факт записи данных в файл /proc/sys/vm/drop_caches - запись данных вызывает немедленную реакцию системы, но, в дальнейшем, записанное значение не влияет на ее работу.

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

Как я уже писал выше, запись в файл /proc/sys/vm/drop_caches вызывает немедленную реакцию системы, после которой, лично у меня, kswapd переставал "грузить" систему. Есть утверждение, что если выполнить следующую команду под root-ом:

echo vm.swappiness=0 >> /etc/sysctl.conf
Добавление строки в файл

или, если работать под пользователем, которому разрешено использовать sudo:

echo vm.swappiness=0 | sudo tee -a /etc/sysctl.conf
Добавление строки в файл с использованием sudo

или же просто отредактировать файл /etc/sysctl.conf каким-нибудь редактором (например, nano), добавив строку vm.swappiness=0 (как вы уже, наверное, догадались, редактор тоже надо вызывать из под root-а или при помощи sudo), то можно будет избавиться от описываемой мною проблемы на постоянной, так сказать, основе. Естественно, после того, как в файл /etc/sysctl.conf одним из вышеприведенным способом будут внесены нужные изменения, систему следует перезагрузить, ну или выполнить команду:

sysctl -p
Обновление параметров

для обновления параметров без перезагрузки. Конечно, из под root-а, или при помощи sudo.

На самом деле, пока я разбирался с этой задачкой, я научился некоторым новым приемам и узнал много нового. О некоторых вновь приобретенных знаниях я, скорее всего, расскажу чуть позже, когда все немного утрясется и уложится. А пока - все...