voidlizard.online
116 subscribers
160 photos
6 videos
5 files
105 links
Haskell, распределённые системы.

Разработка P2P CAS hbs2 и приложений для него

Распределенный git aka hbs2-git

hbs2.net

Прочее https://t.me/genedrd47r (мото, EUC, скайдайвинг, дайвинг)
Download Telegram
в лиспах, получается, можно паттерн-матчингом паттерн-матчить паттерн-матчинг
0.25 Как-то работает. Если RPC затыкается, его передергивает rpc watchdog. откуда берутся затыки вопрос интересный, но возникают они достаточно редко что бы я мог их поймать — вероятно, под нагрузкой будут чаще, а значит, надо создать эту нагрузку. Возможно, все операции конвейров - а hbs2-peer построен вокруг конвейров — фикс. нум потоков воркеров разгребают задачи IO () из очереди - затыкаются, например, туда попадает операция, которая чего-то бесконечно ждёт и блокирует один поток конвейра, а их там не так много. Вопрос интересный, как расследовать непонятно. Например, на виртуалке непрерывный uptime 228271, на линуксом боксе - 151150, на ноуте оно передергивается с каждым открытием-закрытием крышки. Вообще говоря, кажется полезно сделать принудительный рестарт по длительному IDLE. Так же надо подумать, может быть стоит при блокировке конвейра просто или отстреливать самую старую задачу, или задачи ограничить по времени — например, не давать тому, что сидит в конвейре выполняться больше ну, секунды там.

Openwrt прожёвывается и клонируется, как бы цель переделок для 0.25 достигнута. Первоначальный экспорт openwrt занимает около 15 минут, но это в основном потому, что стоит максимальная компрессия. Можно еще лучше, если поставить больше размеры сегментов.

Что дальше. Ну, первое надо бы сделать нормальный сторейдж, вопрос назрел. Сразу упадёт количество сисколлов на записанный-прочитанный мегабайт, и всё станет быстрее и может быть, часть блокировок уйдет.

После этого уже будет осмысленно делать FUSE файловую систему для hbs2-sync. В принципе её делать можно и сейчас, было бы кому.

По сети провёл эксперименты, второй протокол скачивания блоков (BlockGetAllChunks)

data BlockChunksProto e = BlockGetAllChunks (Hash HbSync) ChunkSize
| BlockGetChunks (Hash HbSync) ChunkSize Word32 Word32
| BlockNoChunks
| BlockChunk ChunkNum ByteString
| BlockLost


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

Но для UDP надо опять прикручивать CC, который живет в скачивании. Если его вынести в транспорт — то в транспорте появятся служебные пакеты (ack/nack) и он перестанет быть прозрачным. А может и нет, если в качестве ack/nack использовать пинг, ориентироваться на rtt пинга и снижать скорость. Тогда транспорт получается с обратной связью и очередью, но кстати, это ок.
У эрланга, что ли, был отдельный хип с gc на каждый процесс? Это они мудро придумали. Например, там наверное можно посмотреть, кто сколько жрёт.
Текущее по новому сторейджу - индекс в виде страничной хэштаблицы, где на каждой странице - хэштаблица по очередному компоненту криптографического ключа. короче, это не дисковый куку хэш и не копия rocksdb - там мутно, я что-то не смог по коду разобраться, что они делают - ну и не совсем git pack index, хотя похоже на всё, и всё это между собой похоже. В общем, на тестах получается - где-то на 7.5% быстрее на запись, чем sqlite в пустую таблицу (одной транзакцией), в 450 раз быстрее на чтение. На 1M ключей, ключ размером 32 байта, значение - 8 байт. Алгоритм хэширования максимально простой - вычисляем число бакетов на страницу, в каждом бакете N записей, для первого компонента ключа (64 бита) - вычисляем бакет, размещаем, если не можем - пишем в "остатки", пытаемся разместить следующие. Потом для остатков заводим новую страницу, потом для остатков - новую страницу и т.п. Количество бакетов берётся, как степень двойки, но думаю, лучше брать фибоначчи. В общем-то намного проще, чем у rocksdb получилось.
Теперь надо думать, как быть с новым сторейджем: 1) писать блоки прямо тупо в эти хэштаблицы 2) писать сначала в плоские логи, а потом их индексировать. Если вариант 2) - то там еще: 2.1) писать в один лог 2.2) писать в разные, но их время от времени мержить, типа, что бы совсем мелких не было, но и что бы слишком большие не становились. пока непонятно, как лучше
Ну что, поехали дизайнить новый сторейдж с учётом всех недостатков текущего. Что мы знаем / чего нам не хватает / что хочется
Пересобрал с отладочной информацией, прочитал про средства отладки на маке (много, но все какие-то не такие), ждёшь зацливания — а оно не зацикливается уже 12 часов. Btw, я научился понимать, что на маке зациклилось — он становится тёплым. Просто щупаешь, и если теплое — переключаешь KVM на мак. Напоминает, когда я учился водить на старом опеле — определял воткнутую передачу по запаху. Пахнет палёным — значит, третья. Не пахнет — значит, первая.
текущий стаутс по новому сторейджу
Собственно, для rocksdb есть на самом деле относительно вменяемые биндинги сейчас, без той дичи, что была когда-то со сборкой. Но есть гипотеза, что имея небольшой набор относительно простых примитивов — можно собрать себе СУБД под свои нужды. git же не стал прикручивать sqlite или rocksdb - хотя по сути то, что у гите и есть иммутабельная субд - pack файлы + индекс в виде хэштаблицы. Интересно, что примитивы-то получаются очень простые, а работать с сырой замапленной памятью совсем просто и вроде как, это всё работает не хуже, чем "настоящие системы". Ну посмотрим, конечно. Удивительно, что вещи, которые сначала кажутся сложными — на деле оказываются совсем не сложными (дисковые хэштаблицы, например. столько времени не мог к ним подойти)
Интересное: даже самый всратый метод записи работает не сильно-то хуже, чем моднейший. иногда всратый получается быстрее: например у меня на AMD-боксе слабый nvme, но больше ядер - и тупое написать в n потоков пачки мелких файлов — работает побыстрее, чем "правильный" способ записи (append-only лог в один поток).

Кстати согласно тестам (fio, dd), писание в несколько потоков ничего практически не даёт - ну т.е прирост есть, но не настолько большой, что бы ради него усложнять.

Ну т.е оно пишется примерно с максимальной скоростью, на которую способен диск что так, что сяк. Сложно ухудшить.

Но всё таки на нормальном диске разница таки есть, но маленькая:

[dmz@expert:~/w/hbs2]$ time hbs2 store ~/Videos/GX010021.MP4
AmAFa69anzN9hsUvprsjxAZFrngaVhrPUXUbxFV78hqC

real 0m2,223s
user 0m3,455s
sys 0m0,957s

[dmz@expert:~/w/hbs2]$ time ./test-cq-storage test:ncq:raw:merkle:write ~/tmp/ncq1/ ~/Videos/GX010021.MP4
[debug] currentFileName /home/dmz/tmp/ncq1/0/current.data
stored in 3.334689417 0.959003
AmAFa69anzN9hsUvprsjxAZFrngaVhrPUXUbxFV78hqC
[debug] WIP: ncqFixCurrent
[debug] ncqFixIndexes
[debug] WIP: ncqStorageLoadIndexes
[debug] RUNNING STORAGE!

real 0m2,077s
user 0m2,811s
sys 0m1,464s


А вот с чтением ситуация уже другая
Про сторейджи (микробенчмарки по ссылке)

https://hbs2.net/tree/Fih9vUk6BjJFRuenCAsZUS5M8kD2UZHRPfNGKZGbQghf

видно, что sqlite (btree) не так уж плох на небольшом объеме подобных данных (хэши), но с какого-то момента начинается уже заметная деградация. А ведь это он в самом благоприятном режиме — все записи пакетом одной транзакцией и отсутствие конкурентных чтений в процессе.

На чтение ~ в 20 раз хуже. На запись сначала не хуже, но начиная с миллиона записей уже хуже. Первый тест — текущая схема "git like storage" - т.е на каждый блок запрашиваем один файл. Там, конечно, еще проезд через unix socket по RPC, но он очень мало занимает. Итого в 10 раз хуже sqlite, который в 20 раз хуже ncq (новый самодельный сторейдж).

Ну, ок. Новый сторейдж уже почти тут. Осталось сделать компакции (наверное), удаление (за один проезд с компакцией) + миграцию (собственно, она уже тут: time cat all | ./test-cq-storage test:ncq:raw:write-some ~/tmp/ncq1 ), на 50G займет минут десять, если не делать фоновую (обсуждаемо).
Вот так и врачи ножницы в человеке забывают при операции
При всех своих достоинствах — stm опасная фигня. Своим наличием провоцирует её использовать, что, в свою очередь, чревато продолжительными неприятными приключениями. Особенно, когда привыкаешь, что всё просто работает, а потом сочетание retry и очередей. Было б круче, конечно, если бы был вариант рантайма наподобие эрлангового. С отдельным хипом и gc на процесс, а еще лучше - с возможностями выбрать разные аллокаторы (или хотя бы разные параметры gc) на процесс
я просто к тому, что в эрланге нихрена нет, а всё работает. может, в этом и есть сермяжная правда
удаление из иммутабельного сторейджа
В разработке долгоживущих серверов и embedded программ очень много общего.

Настолько много, что это, кажется, одна и та же задача, только для серверов добавляется аспект большого количества данных / RAM / disk.

В embedded невреден аппаратный вочдог, который работает независимо от mcu, какая-нибудь байда, которая по истечению таймаута ресетит mcu если ей это явно не отменили. типа детонатор "мёртвая рука".

В хаскельном сервере вот вскрылся интересный нюанс — если у нас приключилось что-то внутри stm, то залипнет так, что никакой написанный на хаскелле же внутренний вочдог не поможет — клинит намертво всё, при том, что далеко не все ядра, например загружены. Максимум одно. Это так-то довольно логично, но что с этим делать не очень понятно. Нужно разработать какую-то дисциплину, которой придерживаться, но она влияет на вообще все аспекты.

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

На хаскелле можно его эмулировать, но это надо прямо всю волю в кулак собрать, и писать не как пишется, а как надо (а хрен его знает, как надо).

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

Некоторые называют такую пускалку "systemd", но я хочу

1) пускать в консолях / tmux-ах и смотреть разноцветные логи, а не journalctl этот ваш

2) не исключаю миграцию (свою) на платформы, где нет systemd

3) так или иначе большой проблемы сделать такую запускалку не вижу, хотя на си будет неизящно.

буду думать, короче
В начале этого всего я не хотел делать по возможности TCP, думал (где-то с 2018 - 2019), что можно обойтись без него. Потому, что считал, что TCP это большой геморрой, связанный с управлением ЖЦ соединений, особенно в P2P системе. Теперь, по прошествии лет, могу сказать, что на самом деле TCP это большой геморрой, связанный с управлением ЖЦ соединений, особенно в P2P системе.
И конечно, могу сказать, что цикл REPL в трое суток это лучше, чем REPL вида (поставил GPS трекер на автобус - отпустил автобус - автобус пропал с радаров из-за бага - ездишь на машине по тамбовской области и ищешь автобус, что бы посмотреть, что с трекером) — но всё равно напрягает.
В соседних чатах продолжают жаловаться на ущемления со стороны гитхаба, и атаку клоунов ботов на опенсорсные репозитории, где (видимо написанные на js) краулеры AI кладут опенсорсную инфраструктуру, вроде sr.ht

Не то, что бы P2P подход решал этот вопрос полностью, но он точно решил бы его как в моменте, так и в перспективе — т.е если отключить HTTP для получения деревьев, то ботописатели будут вынуждены пользоваться фреймворком, который балансирует нагрузку по пирам.

Кроме того, везде, где возможно спроектировано так, что бы основную нагрузку нёс запрашивающий.

Занятно, что текущая ситуация с AI ботами отличается от поисковиков двумя вещами:

1) поисковики удушили свой собственный поиск по исходникам (т.к. он не в их интересах)

2) криворукость нынешних ботов, которые просто кладут на соблюдение всяких приличий (robots.txt)
Удаление из нового сторейджа сделал, работает быстро, потому что удаление это добавление. удивительно, сколько вылазит сразу неочевидного, например "добавили удалили добавили удалили добавили..." - короче это CRDT со счётчиком удалений + несколько оптимизаций в моменте (которые мешают жить потом). Теперь вот думаю, как сделать компакцию этого всего, да так, что бы онлайн работало, да автоматом запускалось, да кукухой не поехать, да файловые дескрипторы бы не вытекли и в корку бы не падало ( mmap-нутые файлы в хаскелле умеют/могут)