На правах мыслительных экспериментов, никаких задач не стоит, никакие проблемы не решаются (типа «заборем mysql по скорости!»). Наоборот куча новых проблем с консистентностью. Все ставящиеся тут проблемы вымышлены, безумны и не нужны.
Придумаем как можно держать модели данных, нужные для форума, в какой-нибудь NoSQL. Придумаем какие типы данных в NoSQL были бы полезны ещё, кроме key=value.
Желательно рассматривать nosql субд, которая внутри имеет B+-Tree, т.е. умеет упорядочивать ключи, а не просто держит их в огромной hashtable. Или какой-нибудь LSM типа LevelDB - неважно.
Считаем, что транзакций у нас нет, жизнь боль. Бизнес-логика должна так манипулировать БД, чтобы оставлять её в консистентном состоянии, максимум оставляя мусор в ней. Допустим у нас есть некий уборщик мусора в бизнес-логике приложения, который умеет иногда лениво походить по базе и подропать потерявшиеся ключи или что-то ещё, т.е. знает что считать мусором. Предположим, мусор возникает когда у нас падает бизнес-логика посреди многоэтапных модификаций. Т.е. обычно ошибок в проде нет, но когда они есть появляется мусор, но не потеря данных.
Топик (он же тред).
По сути это список (vector, array). Если бы был тип данных List, адресуемый ключём (т.е. key=value, где value поддерживает семантику List) то было бы круто.
Для постинга месаги мы говорим push(«7abedf31», «Hello World»), где первый аргумент - имя списка (ключа, хранящего в value список), второй элемент - месага. В конец списка добавляется ещё одна месага.
Редактирование мессаг и хранение версий
Просто редактировать - это update(«7abedf31.5544», «New Value»), где «7abedf31.5544» - имя списка и индекс в нём.
Хранить версии - уже тяжелее. Будем делать так: скажем что наш движок поддерживает списки списков. Тогда мы можем делать push(«7abedf31.5544», «New Value»). То есть, запушить ещё один элемент в конец списка, лежащего в элементе 5544 списка «7abedf31». Там (в элементе 5544) уже лежала строка, так что движок сконвертит её в список с 1 элементом и добавит второй элемент. Можно передать некий флаг разрешающий так делать.
При рисовании страницы треда будем говорить get(«7abedf31», offset = 1000, limit = 25) чтобы получить массив месаг. У списка в движке удобный «индекс», движок за O(1) может обратиться к элементу 1000 и линейно вычитать остальные, т.к. лежит всё это в памяти пластом (вектор). Некоторые вернутые этим запросом элементы будут строками (это месаги без редактирований), а некоторые элементы будут списками (пачки версий) - код бизнес-логики форума нарисует только последний элемент из списка версий, остальные элементы юзает чтобы нарисовать число версий, например и переключалку доступа к нужной версии.
Список топиков.
Это уже просто множество key=value вида, например, «fid_tu_topicname=7abedf31», где fid - ID форума, tu - это время апдейта топика - оно обеспечивает поднятие топика, ибо ключи в лексикографическом порядке сортируются например в B+-tree где хранятся, topicname - ну это название топика.
Если в топик что-то постят, мы тупо делаем INSERT того же самого ключа, но где tu посвежее. В итоге у нас 2 ключа, но это не «неконсистентность», ибо бизнес-логика легко выкинет второй ключ с тем же названием топика, а в value лежит всё тот же указатель на нужный список с мессагами.
Апдейт мессаг
Как описывалось ранее, это один push в подсписок. При чтении треда, где через одно все сообщения имеют по 20 редакций - это неоптимальная хрень, но маловероятная в жизни. Зато при апдейте это всего один push, оставляющий всё в консистентном виде.
Месаги похоже не удаляются. Я смог представить как можно реализовать список в виде совокупности «чанков» в B+-Tree вперемешку с обычными ключами, но не смог придумать как из такого списка дропнуть первый элемент. Ладно, скажем максимум мы можем пометить элемент как удалённый. Нормально, что на какой-то странице ты видишь пробелы вместо сообщений или надпись «НЛО прилетело» - зато страницы не сьезжают - скажем ты дал кому-то ссылку на страницу 176 и она осталась валидной, когда модеры потёрли пару страниц.
MongoDB?
«Заведи в монге документ с кучей списков и херачь в них» - скажет читатель (нормальный читатель скажет вообще не выпёрдываться и взять готовый движок на mysql). Какая у монги будет производительность, если треды будут по 40К страниц (элементов списка). Сколько в секунду можно будет добавить элементов списка в конец? Как быстро оно может достать N элементов с заданным offset?
Телеграм чатик: https://t.me/joinchat/FqPvww9IXM0RmazHBRiamw