Нода нищеброда


Введение

Доброго времени суток, Голос.

Исходя из более менее свежих материалов по настройке 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):

Снимок экрана от 2018-05-15 23-57-34.png

Стреляем серебрянными пулями

Для начала объясню несколько моментов, которые позволяют таки влезть в столь скромные ресурсы (детальное описание основных используемых технологий было приведено в прошлом посте):

  1. Оперативную память прокачаем с помощью zRam. В среде Steem этот модуль ядра уже давно используют многие делегаты (там, к слову, для комфортной работы full-ноды в начале года перестало хватать 256ГБ ОЗУ, а сервера с 512ГБ стоят как крыло от самолета)
  2. Положим всю систему на ZFS, что позволит изрядно сэкономить на размерах самого блокчейна без значительной потери в производительности. В качестве компрессии возьмем показывающую неплохие результаты LZ4.
    Снимок экрана от 2018-05-15 23-37-01.png

    Swap также разместим в ZFS, но с минимальным сжатием LZE. Вместо этого можно использовать похожую на zRam технологию zSwap, но у нас всё будет в едином стиле.

  3. Включим опцию сборки Голоса LOW_MEMORY_NODE, дабы высвободить еще немного ОЗУ. Это вроде как best practice для нод делегатов, если верить официальной доке
  4. Хранить shared-memory будем в tmpfs (так советуют делать старожилы) из-за большого количества обращений с ним (у нас система на SSD, но даже это уже давно не панацея, да и помним про циклы перезаписи)
  5. Запретим на этапе реплея лазить в кэш файлу данных блокчейна block_log, тем самым оставим место в ОЗУ и swap исключительно под shm с помощью dd флага nocache.

Установка и настройка системы

У Hetzner есть удобный rescue-режим, в котором можно сконфигурировать будущую систему и произвести первоначальную настройку железа (виртуального, в данном случае). К сожалению, их автоматический скрипт-инсталлятор installimage не умеет в zfs, поэтому установим ОС на обычный раздел, а потом перенесем (в момент оформления заявки на виртуалку выбираем любую операционную систему, всё равно потом будем ставить через rescue).

  1. Грузимся в rescue из консоли управления, входим по SSH.
    hetzner rescue motd
    Если при входе видим нечто похожее - мы там, где нужно
  2. Запускаем скрипт installimage, выбираем Ubuntu 16.04 minimal (тут не принципально, полагаю к примеру свежий 18.04 релиз умеет во все наши хитрости не хуже, просто я консервативен в выборе ОС) и попадаем в настройки.
  3. В файле конфигурации указываем, что система должна будет располагаться на 4ГБ разделе, а остальное пусть займет /home, потом удалим (настройка эта располагается ближе к концу файла):
    Снимок экрана от 2018-05-17 11-21-35.png
  4. Выходим из конфигуратора, ждем установки и перезагружаемся в свежеустановленную систему.
  5. Размонтируем /home, он нам больше не нужен (удаляем его из автозагрузки с помощью редактирования файла /etc/fstab)

    umount /home 
    
    sed -i '/\/home/s/^/#/' /etc/fstab
  6. Устанавливаем необходимые для работы zfs компоненты
    apt-get update && apt-get install zfs-dkms zfs-initramfs
  7. Создаем пул на разделе, который недавно был /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
  8. Делаем файл подкачки, добавляем его в автозагрузку

    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
  9. Создаем в пуле контейнер под системный раздел, делаем его загружаемым и указываем точку монтирования (не пугаемся варнингам)

    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
  10. Сохраняем наш конфиг
    zpool export rpool
  11. Создаем временную точку монтирования и подключаем туда наш контейнер для переноса операционной системы
    mkdir /mnt/rpool
    zpool import -R /mnt/rpool/ rpool
  12. Копируем всё в контейнер
    rsync -a --one-file-system / /mnt/rpool/
  13. Заходим в окружение портированной системы и исправляем системную конфигурацию для корректной загрузки с 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
  14. После выхода из окружения размонтируем всё, сохраняем настройки пула и перезагружаемся в новую систему на zfs
    cd .. && umount /mnt/rpool/{dev,proc,run,sys} && zpool export rpool && shutdown -r now
  15. После загрузки системы проверяем, что мы уже на 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
  16. Ставим и настраиваем zram

    apt-get update && apt-get install zram-config
    
    sed -i 's|/ 2 /|/ 1 /|g' /usr/bin/init-zram-swapping
    
    systemctl restart zram-config
  17. Снова убеждаемся, что у нас получилось
    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
  18. Ставим докер (исключительно по желанию) и другие недостающие приложения
    apt-get install docker.io screen git
  19. Качаем актуальный на сегодня билд голоса
    git clone https://github.com/GolosChain/golos.git && cd golos && git checkout v0.17.2
  20. В 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

  21. Создаем рабочий каталог для конфига нашей ноды и файла блокчейна
    mkdir -p /home/golosnode0.17.2/blockchain
  22. Копируем config.ini и переделываем под себя (отключаем ненужные логи, указываем активный и публичный ключи делегата, если нужно - конфиги майнеров)
    cp share/golosd/config/config_witness.ini /home/golosnode0.17.2/
  23. Чтобы не ждать, пока блокчейн стянется с других p2p-нод, качаем откуда-нибудь готовый файл block_log (есть конечно https://download.golos.io/blockchain.tar.bz2, но его потом нужно разархивировать, а это тот еще геморрой с нашим-то минимализмом). Если взять готовый неоткуда - не беда, придется подождать его синхронизации из сети
  24. Увеличиваем shared-memory до максимально возможного. У нас 12ГБ ram+swap, делаем 11 (в config.ini с недавних пор указывать ничего не надо, там инкрементально с 2ГБ растёт объем, стоит только проверить, что директива смотрит по верному пути (shared-file-dir = /dev/shm)
    mount -o remount,size=11264M /dev/shm
  25. Запускаем сборку ноды в докере (тут кому как больше нравится, я им пользуюсь чуть ли не впервые, до этого всегда ручками собирал) и идём пить чай/кофе/другие напитки
    docker build -t xandros/golos -f Dockerfile .
  26. Заходим в сессию screen и запускаем небольшой костыль, чтобы файл block_log не кэшировался
    cd /home/golosnode0.17.2/ && while : ; do  dd if=blockchain/block_log iflag=nocache count=0; sleep 60; done
  27. Если ошибок в процессе сборки не было - запускаем контейнер на реплей
    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
  28. Мониторим работу и ждем окончания реплея
    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

Посткриптум

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

Resource Monitor
График нагрузки из панели хостера

При написании использовались опубликованные ранее материалы следующих авторов: @t3ran13, @vik, @vvk. Выражаю им свою благодарность.


Текст подготовлен в редакторе OnePlace.media. Если Вы хотите поддержать проект, голосуйте за делегата oneplace по ссылке или любым другим удобным способом

oneplace witness

Comments 22


для стабильной и комфортной работы делегата необходим сервер с минимум 6ГБ ОЗУ.

Не правильно) для работы достаточно 1гб, а вот чб сбилдить, сделать реплей или синх быстро, тотбольше

У меня с 1 гб отлично работает)

17.05.2018 10:06
0

Да, действительно. Немного некорректно написано. Имелось ввиду в том числе для сборки и реплеев. Прошу прощения за такую формулировку

17.05.2018 10:08
0

Хранить shared-memory будем в tmpfs (так советуют делать старожилы) из-за большого количества обращений с ним (у нас система на SSD, но даже это уже давно не панацея, да и помним про циклы перезаписи)

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

Правда хранение вне тмпфс не спасает от сбоев, хотя тутуже везение

Самое главное это спасение от забывчивости)

17.05.2018 10:13
0

Реплей на диске длится в разы (если не на порядок) дольше. В памяти час-полтора и нода оживает. Делегаты из глубины списка форбс за это время потеряют от силы 1 блок. Ну а уж китам, я думаю, можно разориться на вторую виртуалку в 5$ ценой ;-)

Энивей, внизу поста есть некий дисклеймер. Каждый выбирает сам

17.05.2018 10:27
0

Чб блоки не пропускать можно в витнес апдейт отправить технический паблик кей

А так да, вы правы, если чисто для разворачивания разово, то поможет

Какие локации серверов есть, кстати у них?

17.05.2018 13:37
0

hz locations
Германия и Финляндия

17.05.2018 13:40
0

11 пункт пофикси

А так пост отличный)

17.05.2018 10:17
0

Исчез mkdir? Сожрали теги маркдауна. Я в него сутки как пытаюсь ))

И да, спасибо ;-)

17.05.2018 12:35
0

Какие шансы поднять ноду на винде 8? А то у меня мощности на домашнем сервере лишние есть

17.05.2018 13:01
0

Теоретически docker под винду вроде тоже был, практически - почему бы и не попробовать при наличии свободного времени))

upd: можно еще hyper-v нарулить и в виртуалку хоть черта запихать

17.05.2018 13:33
0

Если докер поставишь то проблем не будет

17.05.2018 14:00
0

Я уже писал в чате, я --replay не использую. Я запускаю golosd -d /var/lib/golosd --replay-blockchain прямо в контейнере, грубо так, паралелльно работающей ноде. Дожидаюсь когда начнется реплей. Перестартую контейнер и все - реплей автоматически запускается.

Не нада удалять и снова создавать контейнер

17.05.2018 15:56
0

Речь про эту магию?
Магия внутри докера
Метод имеет право на жизнь, я так понял прикол в закоррапчивании shm, что приводит к автореплею при старте

17.05.2018 16:44
0

Да, оно. Зато не надо ждать полного реплея, что бы потом еще не забыть, пересоздать контейнер

17.05.2018 18:11
0

Интересный опыт. А что за хак с sed -i 's|/ 2 /|/ 1 /|g' /usr/bin/init-zram-swapping, зачем оно нужно?

18.05.2018 06:56
0

По дефолту zram делает блочное устройство в половину величины ОЗУ. Но со сжатием lzo файл индекса спокойно жмется более, чем в 2 раза. Поэтому можно делать zram по размеру памяти. Хак честно стыренный со Стима, но на Голосе всё аналогично:

# du -hs shared_memory.bin 
1.8G    shared_memory.bin
# du -hs --apparent-size shared_memory.bin 
4.3G    shared_memory.bin
18.05.2018 08:50
0

Класний пост.

18.05.2018 12:50
0

Ничего не понял, значит мне это и не нужно )))

10.07.2018 13:49
0