Необходимо спроектировать архитектуру бекенда для мессенджера (Slack, Teams, Mattermost). Требования и ограничения: только 1x1 чаты, без групповых чатов только текстовые сообщения, без вложений сервис доступен через интернет до 10.000 пользователей в системе сообщения должны доставляться быстро, в пределах нескольких секунд сохраняется порядок сообщений, сообщения не дублируются должна быть возможность скроллить чат в прошлое, т.е. сообщения нужно хранить клиенты – мобильные устройства, их не нужно проектировать авторизацию проектировать не нужно
Answer from AI
sobes.tech AI
Для проектирования бекенда мессенджера с 1x1 чатами и текстовыми сообщениями, учитывая требования, можно предложить следующую архитектуру:
-
API-сервер на Go — принимает запросы от клиентов, обрабатывает отправку и получение сообщений.
-
Хранение сообщений — реляционная база данных (например, PostgreSQL) с таблицей сообщений:
CREATE TABLE messages (
id SERIAL PRIMARY KEY,
sender_id INT NOT NULL,
receiver_id INT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
- Индексы по (sender_id, receiver_id, created_at) для быстрого получения истории чата.
-
Доставка сообщений — использовать WebSocket или long polling для обеспечения быстрой доставки сообщений в реальном времени.
-
Порядок и недублирование — сообщения нумеруются по времени создания, клиент получает их в порядке created_at. Сервер гарантирует уникальность id.
-
Масштабирование — при 10.000 пользователей нагрузка умеренная, можно использовать один API-сервер с балансировщиком.
-
Кэширование — можно добавить Redis для кэширования последних сообщений для ускорения загрузки.
-
Безопасность — хотя авторизацию проектировать не нужно, стоит предусмотреть базовую защиту от DDoS и валидацию данных.
Пример обработки отправки сообщения на Go (упрощённо):
func SendMessage(w http.ResponseWriter, r *http.Request) {
var msg Message
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
msg.CreatedAt = time.Now()
// Сохранить в БД
err := db.QueryRow(`INSERT INTO messages (sender_id, receiver_id, content, created_at) VALUES ($1, $2, $3, $4) RETURNING id`,
msg.SenderID, msg.ReceiverID, msg.Content, msg.CreatedAt).Scan(&msg.ID)
if err != nil {
http.Error(w, "DB error", http.StatusInternalServerError)
return
}
// Отправить через WebSocket получателю
sendToReceiver(msg)
w.WriteHeader(http.StatusOK)
}
Такой подход обеспечивает быстрый обмен сообщениями, хранение истории и упрощённую архитектуру, подходящую под заданные требования.