Игра Яндекс Практикума
Игра Яндекс Практикума
Игра Яндекс Практикума

Как хранить лайки социальных сетей в базе данных ScyllaDB

Разбираемся, как обновлять большие данные в базах на ScyllaDB, если они постоянно меняются. В качестве примера используем социальные сети.

2К открытий3К показов

Задумывались ли вы когда-нибудь о том, как Instagram, Twitter, Facebook или другие платформы социальных сетей отслеживают, кому понравились ваши посты? Давайте разберемся в этом посте!

Это — перевод оригинальной статьи Database 101: How social media “likes” are stored in a database на английском языке. Повествование ведется от лица автора — Daniel Reis.

Пролог

Недавно меня пригласили выступить на мероприятии под названием «CityJS». Но вот в чем дело: я парень из PHP. Я вообще не занимаюсь JS, но я принял вызов.

Для мероприятия мне нужно было найти хороший пример работы высокомасштабируемой база данных с низкой задержкой.

Я попросил одного из коллег поискать примеры. Он предложил искать большие числа внутри любой платформы вроде счетчиков. В этот момент я понял, что любой тип метрик может подойти под этот пример: лайки, просмотры, количество комментариев и подписок.

В этой статье вы найдете мои исследования о том, как сделать правильное моделирование данных для счётчиков с помощью ScyllaDB.

Начинаем исследовать

Как хранить лайки социальных сетей в базе данных ScyllaDB 1

Сперва я должен был понять, как построить эту модель данных.

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

Мой первый вариант запроса для подсчета всех лайков был примерно таким:

Хорошо, если я просто сделаю запрос SELECT count(*) FROM social.post_likes, это может сработать, верно?

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

Но ScyllaDB может легко обрабатывать тысячи строк… Почему же она не так производительна в нашем случае?

ScyllaDB — даже как база данных с классными возможностями — не решит проблему плохого моделирования данных.

Нам нужно подумать, как сделать все быстрее.

Изучение типов данных

Давайте подумаем: что если я создам новую строку как целое число в таблице posts и буду увеличивать/уменьшать число каждый раз, когда будет поставлен или убран лайк?

Как хранить лайки социальных сетей в базе данных ScyllaDB 2

Это кажется хорошей идеей, но есть проблема: нам нужно отслеживать каждое изменение в таблице posts, и при обновлении данных мы создадим кучу бессмысленных записей в БД.

Это особенность ScyllaDB: каждый раз, когда нужно обновить имеющиеся данные, вы фактически создаете новые данные.

			scylla@cqlsh:socials> INSERT INTO socials.posts (id, user_id, description, image_url, created_at, likes) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, 'Such a cool event P99 Conf!', 'https://i.imgur.com/Xp8gi7t.jpg', '2023-04-23 15:02:49', 1);

scylla@cqlsh:socials> INSERT INTO socials.posts (id, user_id, description, image_url, created_at, likes) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, 'Such a cool event P99 Conf!', 'https://i.imgur.com/Xp8gi7t.jpg', '2023-04-23 15:02:50', 2);

scylla@cqlsh:socials> INSERT INTO socials.posts (id, user_id, description, image_url, created_at, likes) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, 'Such a cool event P99 Conf!', 'https://i.imgur.com/Xp8gi7t.jpg', '2023-04-23 15:02:51', 3);
		
			scylla@cqlsh:socials> SELECT * from posts;

 id                                 | user_id                           | created_at                    | description               | image_url                     | likes
--------------------------------------+--------------------------------------+---------------------------------+-----------------------------+---------------------------------+-------
 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 | 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129 | 2023-04-23 15:02:48.000000+0000 | Such a cool event P99 Conf! | https://i.imgur.com/Xp8gi7t.jpg |    1
 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 | 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129 | 2023-04-23 15:02:50.000000+0000 | Such a cool event P99 Conf! | https://i.imgur.com/Xp8gi7t.jpg |    2
 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 | 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129 | 2023-04-23 15:02:51.000000+0000 | Such a cool event P99 Conf! | https://i.imgur.com/Xp8gi7t.jpg |    3
		

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

После этого я залез в документацию ScyllaDB и обнаружил, что существует тип под названием counter, который подходит для наших нужд и считается ATOMIC.

Как хранить лайки социальных сетей в базе данных ScyllaDB 3

Хорошо, он подходит для наших нужд, но не для моделирования данных. Чтобы использовать counter, мы должны следовать правилам, и некоторые из них вызывают проблемы:

  1. Единственными другими столбцами в таблице со столбцом счетчика могут быть только столбцы первичного ключа (который нельзя обновлять).
  2. Никакие другие типы столбцов не могут быть включены.
  3. Для работы с таблицами, имеющими тип данных counter, необходимо использовать запросы UPDATE.
  4. Вы можете только увеличивать или уменьшать значения, установка конкретного значения не допускается.
Это ограничение защищает корректную обработку обновлений со счетчиками и без счетчиков, не допуская их в одной операции.

Итак, мы можем использовать этот счетчик, но не в таблице постов… Хорошо, кажется, мы нашли способ решить эту задачу.

Правильное моделирование

Учитывая информацию о том, что тип счетчика не должен быть «смешан» с другими типами данных в таблице, единственный вариант, который нам остается — это создать НОВУЮ ТАБЛИЦУ и хранить в ней данные этого типа.

Итак, я создал новую таблицу post_analytics, в которой будут храниться только типы счетчиков. На данный момент будем работать только с лайками, так как у нас уже создано отношение Many to Many (post_likes).

Как хранить лайки социальных сетей в базе данных ScyllaDB 4

Следующие запросы — это то, что вы, вероятно, будете выполнять для проверки нашего примера:

			## Social when you like a post

UPDATE socials.post_analytics SET likes = likes + 1 WHERE post_id = 4d18bb8c-9c57-44fe-827a-4a2d65f331e5;

INSERT INTO socials.post_likes (post_id, user_id, liked_at) VALUES (4d18bb8c-9c57-44fe-827a-4a2d65f331e5, 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129, '2023-04-23 15:02:50');

# Social when you dislike a post

DELETE FROM socials.post_likes WHERE post_id = 4d18bb8c-9c57-44fe-827a-4a2d65f331e5 AND user_id = 3edd5f1d-67e9-4a3e-af1a-9adbb41e2129;

UPDATE socials.post_analytics SET likes = likes - 1 WHERE post_id = 4d18bb8c-9c57-44fe-827a-4a2d65f331e5;
		

Теперь у вас в голове могут появиться новые вопросы: «Значит, каждый раз, когда мне нужен новый счетчик, связанный с какими-то данными, мне понадобится новая таблица?».

Зависит от того, как использовать данные.

В случае с социальными сетями, если вы хотите хранить данные о том, кто видел сообщение, вам, вероятно, понадобится таблица post_viewers с session_id и кучей других данных.

Простые запросы, которые можно выполнять без джойнов, будут намного быстрее, чем запросы типа count(*).

Заключение

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

Не забудьте поставить лайк этому посту и наполнить свою бутылку водой.

Следите за новыми постами
Следите за новыми постами по любимым темам
2К открытий3К показов