⭕️ Anonymous Распредчан 23.10.2025 23:25 #70970
4 октября 2025 года было сказано приступить к проектированию распределённого чана.
Эта нить посвящена проблемам, обсуждению их и публикации новостей по данному проекту.
Распредчан - это кодовое название механизма синхронизации данных между держателями нод нашего чана.
Нода - ресурс, предоставляющий интерфейсы для server2server и server2client взаимодействий, где s2s - связь между нодами, а s2c - связь между нодой и интерфейсом, например между pissykaka и pissychan-front.
Какие проблемы мы хотим решить?
Независимое хранение постов без централизации оного в руках полутора анонов.
Распределённое хранение файлов.
Возможность каждой ноды принимать посты и файлы от s2c-коннектов для последующей синхронизации их с другими нодами, в том числе теми, что были оффлайн некоторое время.
Мы открыты к предложениям, обсуждению и критике данного проекта.
⭕️ Anonymous 24.10.2025 08:35 #70985
На данный момент мы заняты разработкой системы прав доступа нод.
Одно из предложений звучит так:
> Касательно прав нод у меня такое виденье.> Ноды могут обладать правами:Чтения досок, постов и файлов с других нод - думаю, всем нам проще и спокойнее будет обмениваться данными только с известными нодами.
⭕️ Anonymous 24.10.2025 08:36 #70986
Блядь, попердолил разметку.
Ну вы понели, где и что.
🔰 kugichka Верхнеуровневое видение списка эвентов. 24.10.2025 14:04 #70992
Есть: доски, треды/посты, файлы, паспорта
Эвенты доски:
создание доски
удаление доски
модификация метаданных доски (tag, имя, скрыто-статус, etc)
Так же следует отметить следующие кейсы:
когда одна из нод содержит исключительно свою доску, эта часть ноды (доска) перестаёт считаться частью сети, эвенты не фиксируются в кафке, а всевозможные коллизии разруливаются хостом ноды
сейчас доски имеют свой id в качестве идентификатора, и будет перекат в использование tag в качестве идентификатора
Эвенты постов:
создание поста
удаление поста (физическое, не модерация)
изменение метаданных поста (текст, медиа, updated_at)
перемещение оп-поста на другую доску
Эвенты файлов:
создание файла
изменение меты файла (при модерации например, чтобы вести на заглушку после удаления)
удаление файла (физическое опять же)
Эвенты паспортов:
создание паспорта
разделегирование паспорта (aka удаление)
Эвенты на будущее:
смена паблик ключа для подписей/идентификации ноды
🔰 kugichka 24.10.2025 14:05 #70993
Чуть попозже продолжу это конкретной схемой для кафки, с подсвечиванием важных нюансов.
🔰 kugichka 24.10.2025 20:20 #71002
⭕️ Anonymous 31.10.2025 00:15 #71198
А может синхронизировать явно выбранные доски, евенты же посылать всегда?
⭕️ Anonymous 02.11.2025 01:54 #71282
А можно да. А что ты подразумеваешь под «явным выбором»?
⭕️ Anonymous 02.11.2025 11:29 #71292
Типа, владельцы нод сами решают, какие посты и на какие доски они будут у себя сохранять. При старте ноды конфигурируешь - "обрабатывать евенты с досок такой-то и такой-то".
Написал я, и что-то призадумался. Модерация распределённой системы это прям жесть какая-то. Наверное, твой вариант лучше - изначально складировать как есть. В конце концов, владельцы-трясуны на своей ноде могут и премодерацию ввести - не показывать посты до тех пор, пока своей волею не разрешат.
Даже не знаю, что и лучше. Во втором варианте консьюмеры выходят чище и проще, что безусловно хорошо.
⭕️ Anonymous 03.11.2025 03:24 #71301
Тоже верно. Слушай, можно и первым, и вторым способами. Они всё равно заключаются в реализуемых механиках самой ноды, т.с. в её конфиге это живёт.
⭕️ Anonymous 03.11.2025 23:40 #71323
Что ж, я полуркал информацию о том, как можно выполнять верификацию подписи автора поста в распределённой модели.
Напоминаю, что я вижу проблему в таком кейсе:
Нода N1 выпустила новый паспорт K1.
Пользователь создал пост с подписью от K1.
N1 отправила евент о посте в кафку.
При попытке отправки евента о новом паспорте N1 упала, и евент не был зафиксирован.
N2 синхронизирует события с N1, в них содержится пост с подписью от K1, но у N2 нет K1 для верификации.
Что делать?????
Нейродаун подсказал мне весьма простое, как сказал бы Хома, решение в своей логичности - ставить на некоторое время такой пост в статус "Ожидает проверки подписи". Однажды список паспортов будет синхронизирован между участниками сети, и верификация пройдёт успешно.
В таком случае и городить цепочки сертификатов, равно как и менять текущую реализацию паспортов не следует. Следует лишь с каждым постом хранить и отправлять в евенте хеш его паспорта.
Сейчас используется алгоритм хеширования SHA256 - https://github.com/U-Me-Chan/umechan/blob/master/chan-api/src/Posts/Post/PasswordHash.php#L47C21-L47C21
ХЗ, мб это покажется недостаточным и можно его усложнить для успокоения в век дешёвых терафлопсов.
⭕️ Anonymous 03.11.2025 23:44 #71324
Ох, я ввёл в заблуждение.
Для паспорта используется SHA512. SHA256 используется для хеша пароля поста.
⭕️ Anonymous 04.11.2025 14:36 #71335
⭕️ Anonymous 04.11.2025 14:36 #71336
/s/сейчас да/сейчас два
⭕️ Anonymous 20.11.2025 15:43 #71770
@kugichka, ты предполагаешь, что события в кафке не удаляются никогда?
🔰 kugichka 21.11.2025 03:58 #71782
Не предполагаю, а щито?
⭕️ Anonymous 21.11.2025 08:14 #71784
А как новые ноды будут синкать старые посты?
⭕️ Anonymous 21.11.2025 08:27 #71785
Это хороший вопрос. Мне тут на работе архитектор микросервисов сказал, что юзать кафку для синхронизации данных ПОВЕРХ уже существующих -- самое то, а вот чтобы с нуля восстановить состояние -- кафку не юзают, типа она ваще не для этого. Из тех же рабочих кейсов: тимлид просто присылает дамп бд стейджа, ну или сам вытягиваешь если доступ есть. Это хуйня решение, но чисто технически самое простое.
Тот же чел посоветовал механизм запилить, типа, условный GET /db/all (с ключом ноды) и оно отдаёт всё что есть на текущий момент. При условии, конечно, что ты не всю базу отдаешь за раз, а по отдельным табличкам, при том с оффсетами-лимитами.
⭕️ Anonymous 21.11.2025 08:30 #71786
Хорошо, тогда вытекающий из этого вопрос - какое время жизни сегмента топика? Месяца точно должно хватить всем тем, кто падал надолго, я думаю.
⭕️ Anonymous 21.11.2025 18:05 #71804
Да, давай договоримся так, «месяца хватит всем», ящитаю.
⭕️ Anonymous 16.12.2025 05:18 #1765862322137210
Мне не нравится IPFS по многим причинам:
Большой транзитный трафик.
Невозможность инкрементальных бекапов штатными средствами.
Трудности с деплоем на публичных хостингах - BitTorrent обычно запрещён правилами.
Нет возможности организовать приватную сеть из коробки.
⭕️ Anonymous 16.12.2025 05:27 #1765862866083682
Вдогонку мне из-за этого не нравятся S3-подобные решения. Либо я что-то недоизучил, поправьте меня, пожалуйста.
⭕️ Anonymous 26.12.2025 00:48 #1766710102977458
Что ж. Лог мыслей.
Я развернул локально Kafka-ноду в режиме KRaft, пописял в тестовый топик сообщениями с помощью консольных скриптов продюсера и консьюмера, входящих в поставку образа apache/kafka с Dockerhub.
Пытался завести kafka-ui - не вышло, находящиеся в одной подсети контейнер кафки и кафка-юайя не видят, штоли, друг друга.
Полюркал насчёт библиотек для работы с Kafka в PHP - есть по сути лишь одна (актуальная), она требует отдельного PECL-модуля.
До этого я бегло ознакомился с помощью подкастов с внутренней кухней Kafka, хочу чуть глубже погрузиться в это - про патрицирование топиков, реплики(и как они нам не помогут), отключение автокоммита, как работать с оффсетом топика при чтении оттуда, права доступа.
Меня смущает schemaless топиков - надо бы узнать, есть ли возможность задавать строго.
Очень много настроек самой кафки, в которых я пока нифига не понимаю.
Настройки производительности - кафка это джява, а джява это жор памяти и процессорного времени. Плюс выявить, что мне нужно будет обложить алертами в Grafana.
⭕️ Anonymous 26.12.2025 01:19 #1766711966605713
...и я не могу его собрать, т.к. он требует в alpine linux librdkafka-dev, который гвоздями прибит к openssl, вместо которого у меня используется libressl-dev для решения проблемы сборки модуля memcached. Уф. Перекатывать образ на бубунту снова?
⭕️ Anonymous 26.12.2025 11:53 #1766750005523988
Сегодня выяснил, что для модуля memcached уже не надо libressl-dev, он собирается и без этого. Крутяк!!
⭕️ Anonymous 30.12.2025 07:53 #1767081231441257
@kugichka, почему мы свои инстансы кафки не можем объединить в единый кластер, например? Ты такую схему и предполагал?
Получается же три пути:
Единый кластер. Каждая нода потребляет и продюссирует в локальный инстанс кафки.
Каждая нода продюссирует сообщения в локальную кафку и потребляет из удалённой кафки.
Перед удалённой кафкой есть какое-то API? Не, бред какой-то же.
Расскажи свой взгляд.
🔰 kugichka 10.01.2026 16:20 #1768062026241065
Ну, вот второй варик и предлагал.
⭕️ Anonymous 13.01.2026 08:21 #1768292495026871
Значит, мне надо хорошенько разобраться с вопросами аутентификации консюмеров. Равно как я всё-таки хотел придумать что-то с реализацией валидации схемы евентов, только без централизованного хранилища. Мб, заводить топик под каждую новую версию евента тут выглядит разумно.
⭕️ Anonymous 24.01.2026 18:22 #1769278946216015
Как узнать, что у двух нод разошлись версии БД? Как впоследствии разрешать такие коллизии? Нода дожна как-то узнать, что у неё нет поста, который есть у другой ноды. А ещё должна как-то его получить.
⭕️ Anonymous 24.01.2026 19:24 #1769282673099122
Эти два дня я боролся с проблемой, присущей PHP. У меня не успевали некоторые события, если их несколько на запрос, складываться в Kafka. При этом, если я делал sleep(2) после выполнения операции отправки очереди сообщений в брокер, до всё доходило! Дрожащими руками полез в Сеть, и нашёл параметр socket.timeout.ms, который(неочевидно из названия) отвечает за время блокировки сокета брокером(?). Это время применяется к операции чтения расширением librdkafka из сокета, а также как часто основной тред расширения будет проверять, является ли сокет terminated. Посоветовавшись с некоторыми материалами Сети, нейродаунов и issues на гитхабе расширения, выяснил, что стандартное время установлено в 1000, а ежели его установить в меньшее по совету источников, то сообщения будут приходить во-вре-мя. Выглядит как рабочее колдунство; смущает.
Полюркал инфу про аутентификацию консумеров, интересует прежде всего SASL/PLAIN, т.к. он не требует многих телодвижений с java keystore и форматами сертификатов. Пока не осилил. Боюсь обосраться в этом моменте, а ведь мне торчать этой полуголой жопой как минимум для одного адреса в Сети.
Что ж, на данный момент я закончил реализацию механизма продюссирования евентов на большинство событий записи в БД чана, попробую теперь реализовать консумера, что будет потреблять сообщения на удаление постов из файлстора при удалении поста овнером чана или автором поста.
⭕️ Anonymous 02.02.2026 07:36 #1770017776401876
Разберём причины появления такого инцидента и пути решения.
Почему могут расходится БД pissykaka и epds?
В pissykaka приходит запрос на создание поста.
Pissykaka кладёт пост в БД, затем пытается отправить евент в брокер.
Брокер упал/не сделали flush/другое.
Теперь пост есть на pissykaka и нет в edps.
Самый глупый способ разрешения:
К chan.kugi.club приходит запрос на получение определённого поста.
Поста нет в epds.
chan.kugi.club отдаёт 404 с надписью "возможно, такого поста не было никогда либо он ещё не синхронизирован".
epds делает запрос к pissykaka по HTTP и вытягивает данные поста.
Сетевое взаимодействие, отсутствие гарантии доставки евента, неоднородные сообщения состояния.
Способ второй:
Каждый пост обладает статусом, который принимает такие значения: "Локальный", "Синхронизирован", "В процессе".
Если мы сохранили пост в БД, то затем некий сервис получает такие посты и отправляет евенты брокеру, обновляя затем статус поста. Получаем что-то вроде Outbox курильщика.
Много операций записи, отдельный сервис-продюсер.
Способ два с половиной, оутбокс с очередью.
Принимаем запрос, складываем его в in-memory очередь навроде memcached, redis, etc.
Сервис затем складывает их в БД и кафку.
Отдельный сервис, отсутствие гарантии сохранности поста при падении сервиса очереди.
Способ третий:
При обработке запроса на запись данных поста мы гарантируем, что отдадим 201 тогда и только тогда, когда пост будет сохранён в БД и будет отправлен евент в кафку. Если кафка упала - откатываем транзакцию в БД.
Много синхронных операций при отправке поста. Здесь мы гарантируем, что пост существует только тогда, когда он есть и в БД, и в кафке. Типа как в банках. Здесь надо нагрузочных тестов, гарантирующих обработку запроса не позже 500 мс, например.
Почему расходятся epds и pissykaka, version 2:
epds и chan.kugi.club с пару месяцев являются лидером.
pissykaka подняли
Надо как-то синхронизироваться, в кафка евенты уже протухли.
pissychan как-то должен узнать, кто лидер. (epds и pissykaka должны как-то решать, кто из них лидер и когда. Балансер? Роунд-робин? А мы федерацию делаем или мастер-слейв?)
epds и pissykaka должны иметь идентичный REST API для c2s-коннектов с pissychan и другими.
Бекендер вернётся с другими неприятными мыслями через некоторое время.
⭕️ Anonymous 02.02.2026 23:58 #1770076703417562
Оффсет сохраняется для конкретной партиции топика и consumer group_id! Ранее я считал, что оффсет привязан лишь к партиции - это не так. Следовательно, два потребителя могут читать из одного топика и одной партиции независимо сообщения, сохраняя оффсет в кафку manual путём, т.е., без автокоммита.
Я боялся, что в случае разрастания сети придётся либо отправлять сообщения в разные топики/партиции, увеличивая количество I/O операций на процесс обработки запроса создания поста, либо строить сеть по принципу тунеллирования - новая нода синхронизируется epds, тот синхронизируется с pissykaka для равномерного распределения подключений.
Но полученная инфа всё меняет. Я могу спокойно при обработке запроса использовать механизм распределённой транзакции:
Открыть транзакцию в СУБД.
Записать туда данные поста.
Отправить сообщение в Kafka.
Если при отправке в Kafka произошла ошибка - выполнить rollback у СУБД, отдать неуспешный ответ клиенту. Возможно, положить обработку сообщения в отдельный топик "на потом".
Если всё успешно - закрыть транзакцию в СУБД, отдать успешный ответ клиенту.
Совершенно необязательно. @Oxore может просто решить зависить всегда от стабильности pissykaka, как сейчас, и не имплементировать интерфейс к epds.
Ноды одноранговые. Не вижу смысла мутить тут выбор некоего лидера, переключать клиенты на него и прочая.
⭕️ Anonymous 11.02.2026 00:12 #1770768777726367
С грехом пополам и с помощью alice.yandex.ru я смог настроить механизм SASL/PLAIN для порта Kafka, который у меня будет принимать коннекты от внешних консумеров. SASL/SSL не хочу, надо будет либо выпускать самоподписанные сертификаты, либо готовить PEM-сертификат из моего публичного. Как решение, попробую проксировать соединение к Kafka с помощью Nginx в режиме stream proxy.
Починенные евенты скоро.
⭕️ Anonymous 11.02.2026 22:13 #1770848028824520
Что ж, практически всё готово - https://github.com/U-Me-Chan/umechan/issues/115#issuecomment-3887445575
Что касается ресинка, то мб можно заюзать буквально endpoint фида, добавив ему фильтр по айди поста либо дате создания, чтобы можно было получать пачки новых постов в случае потери событий.
А ещё можно завести отдельный топик, в который можно по необходимости проиграть события для требуемых постов.
Меня смущает тот факт, что если потерялся лишь пост B в цепочке A, B, C, то второй ноде придётся при ресинке запросить данные всех постов.
Проверять каждый раз, когда пост не найден в локальной БД, существует ли он во внешних нодах? Можно, желательно асинхронно.
Нейрофунгус предлагает периодически делать снапшоты, и отставшей ноде качать снапшот + ресинкать остаток. Тогда требуется стандартизировать формат снапшота. Можно, к примеру, заюзать формат схем распредача, а снапшот класть статическим JSON на сервере. Каждой ноде потребуется реализовать механизм, при котором он сможет потреблять события либо из снапшота, либо из брокера по одной схеме.
Как ресинкать паспорта? Их не так уж и много. Можно паспортам добавить время выпуска, и по аналогии с ресинком постов, запрашивать новых на метку времени.
Как ресинкать доски? Как и паспорта, например.
⭕️ Anonymous 11.02.2026 22:27 #1770848878386237
По поводу снапшотов — надо ещё тогда у каждой годы иметь их индекс: какой файл полный дамп, а какой лишь от 01.2026 до 02.2026 и т.п.
⭕️ Anonymous 11.02.2026 22:29 #1770848977977088
Тут-то проще, каждый снапшот именовать дата-временем создания, и нарезать их периодически, раз в неделю-день.
⭕️ Anonymous 11.02.2026 23:51 #1770853910552399
Алсо, добавил явную проверку связи с брокером, и если она отсутствует - приложение падает. Есть оче маленькая вероятность, что брокер успеет упасть между проверкой связи и отправкой евента, а также есть вероятность побольше, что брокер отклонит сообщение.
Всё это может происходить раз в полгода, и стоит ли городить лес? В конечном итоге мир несовершенен, и рассинхроны будут.
Что касается потери евента внутри цепочки A, B, C - так можно же юзать монотонно-возрастающее значение идентификатора евента, и хранить его между двумя нодами.
Нода 1 отправила евент 1, сохранила идентификатор.
Нода 2 получила евент 1, сохранила идентификатор.
Нода 1 не отправила евент 2, отправила евент 3.
Нода 2 получила евент 3, сравнила его со своим прошлым айди - ПОТЕРЯ.
??? Ресинк, проиграть событие заново, etc.
Данная схема, правда, исключает паралелльную обработку очереди евентов. Возможно, это критично.
⭕️ Anonymous 11.02.2026 23:53 #1770853999998089
Более того, она даже исключает параллельные потоки у одной ноды. Sad but true.
⭕️ Anonymous 12.02.2026 11:32 #1770895971808867
Это не трогай, эти квадратики бумаги на новый год уготовлены.
> Что касается потери евента внутри цепочки A, B, CТа ничего не теряется, у тебя есть оффсет в кафка-клиенте; пока всё не проитерирует, не успокоится.
> Что касается потери эвента номер 2Предлагаю пока не думать на тему "потери событий у ноды между своим бекендом и своей кафкой", не городить в этом направлении чего-либо. Столкнемся -- решим.
⭕️ Anonymous 12.02.2026 11:39 #1770896363126214
Это если в топик попадёт евент. Я пишу про ситуацию, когда у нас несогласованное состояние между СУБД и кафкой.
⭕️ Anonymous 12.02.2026 13:46 #1770903965322036
чееел забей
⭕️ Anonymous 12.02.2026 22:58 #1770937115923273
Тогда, видимо, придётся отдавать 404 с ссылоками на другие ноды и ризоном типа "у меня такого нет, возможно, есть у других".
⭕️ Anonymous 12.02.2026 23:36 #1770939363487971
Что ж, выкатил production-ready версию, потестируем на живых анонах. Теперь все ваши действия на борде пишутся в Kafka :)
Отослал доступы @kugichka, пусть глянет и оценит. Чуть погодя я разберусь с ACL для пользователей-потребителей, утвердим схемы внутри Kafka-топиков, договоримся о механизме bootstrap данных и будем ждать имплементации синхронизации между chan.kugi.club и scheoble.xyz.
⭕️ Anonymous 13.02.2026 00:21 #1770942070099514
Что сделать:
ACL для пользователей брокера.
Актуализировать схемы распредача в репо, использовать данные схемы для генерации событий в кафка.
Для фида у писсикаки добавить фильтры: только нити, сортировать по времени создания.
⭕️ Anonymous 13.02.2026 00:29 #1770942597585369
Только что воспроизвёл данную проблему - пост есть, евент был отправлен, кафка вернула успешный код и... не сохранила его, т.к. я включил у топика политику compact и не передавал key(требуется для данного режима). Интересное выходит - гарантировать, что сообщение точно было записано в кафку, используя librdkafka я не очень-то могу.
⭕️ Anonymous 13.02.2026 00:36 #1770942973708212
Ну либо не могу для compact-policy, точно не скажу.
⭕️ Anonymous 13.02.2026 00:44 #1770943463641893
Есть такая идея:
У сущностей есть статус: local:только локально, sync: синхронизировано.
Потребитель иной ноды после фиксирования у себя поста отправляет в топик
nodeSign-[posts,boards,passports,files]-syncedв режиме compact с идентификатором сущности событие типаSynced.Моя нода читает вышеуказанный топик и поставляет статусы синхронизации.
Можно получить список несинхронизированных сущностей.
В итоге мы приходим к Outbox, а чего бы и нет.
⭕️ Anonymous 13.02.2026 16:43 #1771000998046168
Чёта синхронизирует.
⭕️ Anonymous 13.02.2026 19:55 #1771012510002288
Правда?
⭕️ Anonymous 13.02.2026 20:20 #1771014013907819
Ну я гляжу вкладку потребителей.
⭕️ Anonymous 18.02.2026 23:46 #1771458411563909
Понел. Схему когда устаканим?
⭕️ Anonymous 19.02.2026 00:22 #1771460538277781
⭕️ Anonymous 19.02.2026 02:19 #1771467560399197
⭕️ Anonymous 24.02.2026 02:08 #1771898882596511
Потратил полчаса на чтение спецификации AsyncAPI - решения для создания спецификаций для EDA-приложений в openapi-like формате. Считаю его подходящим для наших планов.
Что планирую сделать:
Переписать схемы распредача в репо в AsyncAPI-формате.
Использовать данную схему в проекте pissykaka для сериализации событий по спецификации. Надо будет придумать какой-то маппинг из моих моделей в спеку и назад~
По возможности агитировать остальных заинтересованных в обмене событиями людей аналогичным образом использовать данную спецификацию внутри кода своих приложений. В идеале обновление репо со спекой должно будет применять новые схемы распредача нодах.
Когда? Не могу сказать, т.к. в деятельности кроме чана есть активности, отнимающие время. В худшем случае планирую на конец марта.
⭕️ Anonymous 24.02.2026 04:07 #1771906063184200
Это хорошо, давай возьмем это.
> EDA-приложенийНе смог сходу нагуглить, это что такое?
> Переписать схемы распредача в репо в AsyncAPI-форматеБуду ждать когда у тебя появится время и желание. Как только, так сразу.
> обновление репо со спекой должно будет применять новые схемы распредача нодахЭто как? Обновление зависимых от контракта никогда на моей памяти не происходило автоматизированно.
⭕️ Anonymous 25.03.2026 01:23 #1774401838209766
Вроде как логично использовать сертификат, который выпущен LSC для публичного домена, в процессе деплоя Apache Kafka с SSL-слушателем, но смущает тот факт, что для окружения JVM его нужно готовить в нужный формат JKS и делать это придётся при каждом обновлении сертификата. И что же? Использовать самоподписанный вроде как неспортивно, мб и проблемы вызовет у сторонних потребителей.
⭕️ Anonymous 25.03.2026 11:20 #1774437605389422
Я так заебался пердолить SASL_SSL:SCRAM-SHA-512 уже третий день без успеха, что просто думаю забить хуй, обернуть коннект к кафке в SSL-соединение сторонним решением и оставить SASL_PLAIN как сейчас. Проклятая хуита.
Я не нашёл ни единого рабочего конфига либо инструкции по настройке. У меня сгорела жопа, и мне стало похуй.
⭕️ Anonymous 26.03.2026 00:17 #1774484273217681
Но сдаваться я не думаю. Пердолю дальше! ><