Выбор современного форума и миграция с Discuz на NodeBB
После прекращения поддержки Discuz потребовался выбор альтернативного форума. Протестировал несколько вариантов, кратко расскажу о впечатлениях и методах миграции.
Ниже представлены варианты в порядке рейтинга на Github.
discourse
Этот форум занимает первое место, но он построен на Ruby on Rails. RoR имеет низкую производительность и высокое потребление памяти, что не подходит для небольших сайтов, поэтому сразу отказался от него.
У нас уже несколько раз падали сайты на RoR из-за активности краулеров, так что мы не можем себе его позволить.
flarum
У этого форума отличный интерфейс. Основан на PHP + MySQL, в теории проблем с производительностью быть не должно. Однако, SQL-запросы на форуме не оптимизированы: доступ к первой теме на пустом форуме генерирует около 100 SQL-запросов, время загрузки начинается от 100 мс, а при использовании облачной базы данных начального уровня 200 мс — это норма. С учётом загрузки остального контента время ожидания приближается к 1 секунде.
nodebb
Этот форум построен на NoSQL + Node.js, обладает высокой производительностью и низкой нагрузкой на CPU. Кроме того, он использует постоянное websocket-соединение, что обеспечивает очень быстрый отклик. Начальное потребление памяти составляет 1 ГБ, но рост медленный. Выбрал его из-за наличия полного набора плагинов и API.
apache / answer
Это тоже отличный вариант, похож на Zhihu или StackOverflow. Однако я не нашёл способа отключить такие функции, как задавание вопросов и принятие ответов. Если бы это было возможно, получился бы форум, ориентированный на статьи (длинные основные посты), подходящий для ресурсов с гайдами, где не требуется много функций для общения.
flaskbb / flaskbb
Форум на Python, обладает хорошей производительностью, но давно не обновлялся.
rafalp / Misago
С первого взгляда — форум для аниме-сообщества. Тоже на Python. Автор начал разработку не так давно, но работает очень активно. Посмотрел, он использует библиотеку SocialAuth для Python, которая позволяет легко интегрировать различные способы входа, включая QQ, Weixin, Google, а также собственную авторизацию сайта.
Ещё есть два китайских форума, которые выглядят неплохо: один — Casbin, сильно напоминающий v2ex, а также bbs-go и symphony, похожие на блог CSDN, но я их не тестировал.
Миграция с Discuz на NodeBB
Если у вас есть собственный сайт, для настройки единого входа (SSO) в NodeBB можно использовать два официальных плагина: nodebb-plugin-session-sharing или nodebb-plugin-sso-oauth2-multiple.
Что касается импорта данных из Discuz, здесь придётся писать код самостоятельно. Можно попросить ИИ на Python создать каркас, а остальное доделать самому.
Если нужно импортировать только сообщения, то можно пройтись циклом по таблице posts из Discuz, где каждая строка — это сообщение, а first=1 указывает на начальное сообщение темы.
Для создания темы используйте API NodeBB api/v3/topics/. Для ответов используйте api/v3/topics/{tid}. Для пользователей можно использовать API создания пользователей. Поскольку я использовал session-sharing, то применял интерфейс api/session-sharing/user, а для поиска пользователя — api/session-sharing/lookup?id={passport_id}.
Скорость обработки API составляет около 5 запросов в секунду, будьте готовы к длительной миграции.
Пример вызова:
async def create_topic(title, body, timestamp, category, tags, uid):
# Создание темы POST
data = {
"cid": category, # ID раздела
"title": title,
"content": body,
"timestamp": int(timestamp), # Время в миллисекундах
"tags": tags,
"_uid": uid # ID автора
}
# API-ключ администратора
headers = {"Authorization": f"Bearer 1239383-3323-2323-2323-asd123123123"}
# Вызов
async with aiohttp.ClientSession() as session:
async with session.post(
'https://xxx.com/api/v3/topics/',
headers=headers,
json=data
) as response:
if response.status != 200:
# Если ошибка типа "Пожалуйста, добавьте содержимое сообщения, оно не может быть меньше 1 символа", значит content не экранирован
response_text = await response.text()
raise Exception(f"Error creating topic {title}: {response_text}")
result = await response.json()
topic_object = result['response']
return topic_object['tid']Обратите внимание, что логика публикации через API и публикации пользователем одинакова, поэтому действуют все ограничения форума на длину сообщения. Аналогично, параметр timestamp из-за этого может игнорироваться, и сообщение будет опубликовано с текущим временем. Решение — изменить временную метку в строке 16 файла src/api/helpers.js, просто закомментировав строку data.timestamp = Date.now();. После завершения миграции не забудьте вернуть всё обратно, иначе пользователи тоже смогут менять время.
После этого изменения API для ответов api/v3/topics/{tid} также будет поддерживать передачу параметра timestamp для указания времени.
b96cfe3