Нода нищеброда
Введение
Доброго времени суток, Голос.
Исходя из более менее свежих материалов по настройке witness-ноды блокчейна Golos, для стабильной и комфортной работы делегата необходим сервер с минимум 6ГБ ОЗУ (речь про сборку/реплей, уже готовая нода входит на 1ГБ ОЗУ - в комментариях @t3ran13 подтверждает этот факт). Такие редко попадаются, обычно у хостеров при нарезке мощностей речь идёт о степенях двойки. Выходит, нужно смотреть в сторону 8ГБ. Но мы не ищем легких путей, попробуем сэкономить, всё уместить в 4ГБ и не ждать второго пришествия, глядя на уныло текущий реплей. На диске на текущий момент блокчейн с последним блоком в районе 16500000 занимает в районе 16ГБ, плюс индексы, плюс shared_memory файл. Добавив ко всему этому безобразию размер самой операционной системы легко вываливаемся за 20ГБ.
du -hs --apparent-size /home/golosnode0.17.2/blockchain/*
16G /home/golosnode0.17.2/blockchain/block_log
127M /home/golosnode0.17.2/blockchain/block_log.index
Тут отдельно стоит отметить, что блокчейны крайне прожорливы, и актуальные данные по требуемым техническим характеристикам весьма быстро устаревают. Стоит учитывать этот момент и всегда брать с запасом. Закладывая эти соображения тоже, мы и будем пытаться сегодня сэкономить на ноде делегата.
Сразу оговорюсь, мы не будем использовать для сборки/реплея и других операций домашние ПК, ноутбуки соседей по даче и какие-то еще дополнительные мощности. Задача - собрать живой конфиг для уверенной работы голой ноды делегата без всего лишнего.
Выбор железа
Для начала находим более-менее вменяемый хостинг по соотношению цена-качество. Для этого можно воспользоваться сервисами вроде VDS.menu (не реклама) или просто спросить у знакомых веб-мастеров.
Я давно использую Hetzner, его же предлагает вышеупомянутый подборщик. На нем и остановимся. Пробуем влезть в мощности конфигурации CX21 (2 CPU, 4 GB RAM, 40 GB SSD, 20 TB TRAFFIC):
Стреляем серебрянными пулями
Для начала объясню несколько моментов, которые позволяют таки влезть в столь скромные ресурсы (детальное описание основных используемых технологий было приведено в прошлом посте):
- Оперативную память прокачаем с помощью zRam. В среде Steem этот модуль ядра уже давно используют многие делегаты (там, к слову, для комфортной работы full-ноды в начале года перестало хватать 256ГБ ОЗУ, а сервера с 512ГБ стоят как крыло от самолета)
- Положим всю систему на ZFS, что позволит изрядно сэкономить на размерах самого блокчейна без значительной потери в производительности. В качестве компрессии возьмем показывающую неплохие результаты LZ4.
Swap также разместим в ZFS, но с минимальным сжатием LZE. Вместо этого можно использовать похожую на zRam технологию zSwap, но у нас всё будет в едином стиле. - Включим опцию сборки Голоса LOW_MEMORY_NODE, дабы высвободить еще немного ОЗУ. Это вроде как best practice для нод делегатов, если верить официальной доке
- Хранить shared-memory будем в tmpfs (так советуют делать старожилы) из-за большого количества обращений с ним (у нас система на SSD, но даже это уже давно не панацея, да и помним про циклы перезаписи)
- Запретим на этапе реплея лазить в кэш файлу данных блокчейна block_log, тем самым оставим место в ОЗУ и swap исключительно под shm с помощью dd флага nocache.
Установка и настройка системы
У Hetzner есть удобный rescue-режим, в котором можно сконфигурировать будущую систему и произвести первоначальную настройку железа (виртуального, в данном случае). К сожалению, их автоматический скрипт-инсталлятор installimage не умеет в zfs, поэтому установим ОС на обычный раздел, а потом перенесем (в момент оформления заявки на виртуалку выбираем любую операционную систему, всё равно потом будем ставить через rescue).
Грузимся в rescue из консоли управления, входим по SSH.
Если при входе видим нечто похожее - мы там, где нужноЗапускаем скрипт
installimage
, выбираем Ubuntu 16.04 minimal (тут не принципально, полагаю к примеру свежий 18.04 релиз умеет во все наши хитрости не хуже, просто я консервативен в выборе ОС) и попадаем в настройки.В файле конфигурации указываем, что система должна будет располагаться на 4ГБ разделе, а остальное пусть займет /home, потом удалим (настройка эта располагается ближе к концу файла):
Выходим из конфигуратора, ждем установки и перезагружаемся в свежеустановленную систему.
Размонтируем /home, он нам больше не нужен (удаляем его из автозагрузки с помощью редактирования файла /etc/fstab)
umount /home sed -i '/\/home/s/^/#/' /etc/fstab
Устанавливаем необходимые для работы zfs компоненты
apt-get update && apt-get install zfs-dkms zfs-initramfs
Создаем пул на разделе, который недавно был /home, проверяем успешность создания
zpool create -o ashift=12 -O atime=off -O canmount=off -O compression=lz4 -O normalization=formD rpool -f /dev/sda2 zpool status pool: rpool state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM rpool ONLINE 0 0 0 sda2 ONLINE 0 0 0 errors: No known data errors
Делаем файл подкачки, добавляем его в автозагрузку
zfs create -V 4G -b $(getconf PAGESIZE) -o compression=zle -o logbias=throughput -o sync=always -o primarycache=metadata -o secondarycache=none -o com.sun:auto-snapshot=false rpool/swap mkswap /dev/zvol/rpool/swap Setting up swapspace version 1, size = 4 GiB (4294963200 bytes) no label, UUID=41be4f36-fbea-4e31-a736-3f17a7a14646 echo "/dev/zvol/rpool/swap none swap defaults 0 0" | tee -a /etc/fstab
Создаем в пуле контейнер под системный раздел, делаем его загружаемым и указываем точку монтирования (не пугаемся варнингам)
zfs create rpool/root zfs set compression=lz4 rpool/root zfs set mountpoint=/ rpool/root cannot mount '/': directory is not empty property may be set but unable to remount filesystem
Сохраняем наш конфиг
zpool export rpool
Создаем временную точку монтирования и подключаем туда наш контейнер для переноса операционной системы
mkdir /mnt/rpool zpool import -R /mnt/rpool/ rpool
Копируем всё в контейнер
rsync -a --one-file-system / /mnt/rpool/
Заходим в окружение портированной системы и исправляем системную конфигурацию для корректной загрузки с ZFS
cd /mnt/rpool/ && mount --bind /dev dev && mount --bind /proc proc && mount --bind /sys sys && mount --bind /run run && chroot . / # export ZPOOL_VDEV_NAME_PATH=YES && update-grub && grub-install /dev/sda Generating grub configuration file ... Found linux image: /boot/vmlinuz-4.13.0-36-generic Found initrd image: /boot/initrd.img-4.13.0-36-generic done Installing for i386-pc platform. Installation finished. No error reported. / # exit
После выхода из окружения размонтируем всё, сохраняем настройки пула и перезагружаемся в новую систему на zfs
cd .. && umount /mnt/rpool/{dev,proc,run,sys} && zpool export rpool && shutdown -r now
После загрузки системы проверяем, что мы уже на zfs
df -h Filesystem Size Used Avail Use% Mounted on udev 1.9G 0 1.9G 0% /dev tmpfs 385M 8.0M 377M 3% /run rpool/root 29G 957M 28G 4% / tmpfs 1.9G 0 1.9G 0% /dev/shm tmpfs 5.0M 0 5.0M 0% /run/lock tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup tmpfs 385M 0 385M 0% /run/user/0 free -m total used free shared buff/cache available Mem: 3849 125 3641 7 82 3541 Swap: 4095 0 4095
Ставим и настраиваем zram
apt-get update && apt-get install zram-config sed -i 's|/ 2 /|/ 1 /|g' /usr/bin/init-zram-swapping systemctl restart zram-config
Снова убеждаемся, что у нас получилось
free -h total used free shared buff/cache available Mem: 3.8G 614M 3.0G 8.1M 159M 2.9G Swap: 7.8G 0B 7.8G
Ставим докер (исключительно по желанию) и другие недостающие приложения
apt-get install docker.io screen git
Качаем актуальный на сегодня билд голоса
git clone https://github.com/GolosChain/golos.git && cd golos && git checkout v0.17.2
В Dockerfile указываем необходимые нам параметры сборки, например так
RUN
cd /usr/local/src/golos &&
git submodule update --init --recursive &&
mkdir build &&
cd build &&
cmake
-DCMAKE_BUILD_TYPE=Release
-DLOW_MEMORY_NODE=TRUE
..
&&
make -j$(nproc) &&
make install &&
rm -rf /usr/local/src/golosСоздаем рабочий каталог для конфига нашей ноды и файла блокчейна
mkdir -p /home/golosnode0.17.2/blockchain
Копируем config.ini и переделываем под себя (отключаем ненужные логи, указываем активный и публичный ключи делегата, если нужно - конфиги майнеров)
cp share/golosd/config/config_witness.ini /home/golosnode0.17.2/
Чтобы не ждать, пока блокчейн стянется с других p2p-нод, качаем откуда-нибудь готовый файл block_log (есть конечно https://download.golos.io/blockchain.tar.bz2, но его потом нужно разархивировать, а это тот еще геморрой с нашим-то минимализмом). Если взять готовый неоткуда - не беда, придется подождать его синхронизации из сети
Увеличиваем shared-memory до максимально возможного. У нас 12ГБ ram+swap, делаем 11 (в config.ini с недавних пор указывать ничего не надо, там инкрементально с 2ГБ растёт объем, стоит только проверить, что директива смотрит по верному пути (shared-file-dir = /dev/shm)
mount -o remount,size=11264M /dev/shm
Запускаем сборку ноды в докере (тут кому как больше нравится, я им пользуюсь чуть ли не впервые, до этого всегда ручками собирал) и идём пить чай/кофе/другие напитки
docker build -t xandros/golos -f Dockerfile .
Заходим в сессию screen и запускаем небольшой костыль, чтобы файл block_log не кэшировался
cd /home/golosnode0.17.2/ && while : ; do dd if=blockchain/block_log iflag=nocache count=0; sleep 60; done
Если ошибок в процессе сборки не было - запускаем контейнер на реплей
docker run -d -p 4243:4243 -v /home/golosnode0.17.2/config.ini:/etc/golosd/config.ini -v /home/golosnode0.17.2/blockchain/:/var/lib/golosd/blockchain/ -v /dev/shm:/dev/shm -e STEEMD_EXTRA_OPTS="--replay" --name "xgolos" xandros/golos
Мониторим работу и ждем окончания реплея
docker logs --tail=100 -f xgolos
У меня ~16450000 блоков закончили индексирование примерно через час
2107749ms th_0 database.cpp:207 reindex ] Done reindexing, elapsed time: 3583.34902099999999336 sec
2107751ms th_0 plugin.cpp:333 plugin_startup ] Started on blockchain with 16512369 blocks
После успешного реплея рекомендую стопнуть контейнер (когда он начнет получать транзакции в штатном режиме)
docker stop xgolos && docker rm xgolos
Затем удалить опцию "--replay" и перезапустить его заново
docker run -d -p 4243:4243 -v /home/golosnode0.17.2/config.ini:/etc/golosd/config.ini -v /home/golosnode0.17.2/blockchain/:/var/lib/golosd/blockchain/ -v /dev/shm:/dev/shm --name "xgolos" xandros/golos
Посткриптум
Данный опыт носит исключительно исследовательский характер, показывает возможность разворачивания ноды на сервере представленной конфигурации и никоим образом не призывает держать свои основные ноды в таких спартанских условиях. Вероятно кому-то будут полезны лишь некоторые моменты из вышеизложенного, кто-то же может попробовать воспроизвести подобное у себя в песочнице.
График нагрузки из панели хостера
При написании использовались опубликованные ранее материалы следующих авторов: @t3ran13, @vik, @vvk. Выражаю им свою благодарность.
Текст подготовлен в редакторе OnePlace.media. Если Вы хотите поддержать проект, голосуйте за делегата oneplace по ссылке или любым другим удобным способом