Як очистити чат і видалити повідомлення в Discord

Найчастіше у користувачів текстових чатів виникає бажання видалити все старе листування, що втратило актуальність, і займає зайве місце. Тим часом спроби зробити це через програмний інтерфейс не дозволяють цього зробити. Як бути в даній ситуації, і чи є можливість провести очищення?

Поняття чату

Під чатом у програмі Discord розуміються окремі канали. Вони у свою чергу за типом використовуваних способів спілкування поділяються на голосові та текстові.

Як базовий елемент роботи в Discord виступає сервер, створюваний користувачем. Після цього в ньому є можливість створення необмеженої кількості каналів обох типів.

Очищення чату у програмі Discord

Відразу необхідно сказати, що інструментів для моментального видалення всіх повідомлень, що накопичилися в каналі, програма користувачам не надає. Видалення можливе лише окремих записів (повідомлень). Проте існує один спосіб, що дозволяє прискорити процес очищення. Йдеться такому терміні як «реакція», тобто відповідь інших учасників розмови на викладені повідомлення.

Для видалення всіх реакцій у чаті передбачається наступний порядок дії:

  • Увійти до програми Discord;
  • Вибрати канал, що цікавить;
  • Праворуч від вибраного повідомлення натиснути за значок «двокрапка»;
  • Вибрати з меню «Видалити всі реакції».

Звичайно, таким чином неможливо одним натисканням провести чищення всіх повідомлень, але це дозволить суттєво знизити потрібний час для повного очищення. Самі повідомлення учасників бесіди доведеться видаляти вручну по одному.

Для цього потрібно:

  • Увійти у додаток;
  • Вибрати канал, що цікавить;
  • Напроти кожного повідомлення натиснути на піктограму «двокрапка»;
  • Вибрати з меню «Видалити».

Ви можете видалити і видалити текст повідомлення правою клавішею з подальшим натисканням на запропонований варіант дій «Видалити».

У разі зникнення потреби в каналі, його можна просто видалити, причому для цього потрібно всього кілька натискань клавіш. Для цього потрібно виконати наступний набір дій:

  • Зайти у додаток;
  • Вибрати канал, що цікавить;
  • Перейти до розділу «Меню» або клацнути правою кнопкою;
  • Із запропонованого списку дій виберіть варіант «Видалити канал».

Таким чином, можливо, як видалення самого каналу, так і записів у ньому. Нехай остання процедура вимагає певних втрат часу.

Про саму програму

Програма Discord призначена для організації голосового спілкування онлайн-ігор. Звичайно, сервіс пропонує і стандартні можливості текстового спілкування, але при цьому необхідно визнати, що за рівнем функціональних можливостей текстові канали програми поступаються месенджерам. Не можна не визнати, що проект Discord орієнтований насамперед на геймерську аудиторію.

  • Переклад

Discord продовжує зростати швидше, ніж ми очікували, як і контент користувача. Чим більше користувачів – тим більше повідомлень у чаті. У липні ми оголосили про 40 млн повідомлень на день, у грудні оголосили про 100 млн, а в середині січня подолали 120 млн. Ми відразу вирішили зберігати історію чатів вічно, так що користувачі можуть повернутися в будь-який момент і отримати доступ до своїх даних з будь-якого пристрої. Це багато даних, потік та обсяг яких наростає, і всі вони мають бути доступними. Як ми це робимо? Cassandra!

Що ми робили

Початкову версію Discord написали швидше ніж за два місяці на початку 2015 року. Можливо, однією з найкращих СУБД для швидкого виконання ітерацій є MongoDB. Все в Discord спеціально зберігалося в єдиному реплісеті (replica set) MongoDB, але ми також готували все для простої міграції до нової СУБД (ми знали, що не збираємося використовувати шардинг MongoDB через його складність та невідому стабільність). Насправді це частина нашої корпоративної культури: розробляй швидко, щоб випробувати нову функцію продукту, але завжди з курсом більш надійного рішення.

Повідомлення зберігалися в колекції MongoDB з єдиним складовим індексом channel_id і created_at . Приблизно в листопаді 2015 року ми вийшли на кордон 100 млн повідомлень у базі, і тоді почали розуміти проблеми, які на нас чекають: дані та індекс більше не поміщаються в ОЗУ, а затримки стають непередбачуваними. Настав час мігрувати до більш відповідної СУБД.

Вибір правильної СУБД

Перед вибором нової СУБД нам потрібно було зрозуміти наявні шаблони читання/запису і чому виникли проблеми з поточним рішенням.
  • Швидко стало зрозуміло, що операції читання є виключно випадковими, а співвідношення читання/запис приблизно 50/50.
  • Тяжкі сервери голосових чатів Discord практично не надсилали повідомлень. Тобто вони надсилали одне або два повідомлення кожні кілька днів. За рік сервер такого типу навряд чи досягне рубежу 1000 повідомлень. Проблема в тому, що навіть незважаючи на таку малу кількість повідомлень, ці дані складніше доставляти користувачам. Просто повернення користувачеві 50 повідомлень може призвести до багатьох випадкових операцій пошуку на диску, що призводить до витіснення дискового кешу.
  • Тяжкі сервери приватних текстових чатів Discord відправляють пристойну кількість повідомлень, легко потрапляючи в діапазон між 100 тис. і 1 млн повідомлень на рік. Запрошують вони зазвичай лише останні дані. Проблема в тому, що на цих серверах зазвичай менше 100 учасників, тому швидкість запиту даних низька і навряд чи вони будуть у дисковому кеші.
  • Великі публічні сервери Discord надсилають багато повідомлень. Там тисячі учасників, які надсилають тисячі повідомлень на день. Легко набираються мільйони повідомлень на рік. Вони майже завжди вимагають повідомлення, надіслані в останню годину, і це відбувається часто. Тому дані зазвичай знаходяться у дисковому кеші.
  • Ми знали, що в наступному році у користувачів з'явиться ще більше способів генерувати випадкові читання: це можливість переглядати свої згадки за останні 30 днів і потім перескакувати на той момент історії, перегляд і перехід до прикріплених повідомлень та повнотекстовий пошук. Все це означає ще більше випадкових читань!
Потім ми визначили наші вимоги:
  • Лінійна масштабованість- Ми не хочемо переглядати рішення пізніше або вручну переносити дані в інший шард.
  • Автоматична відмовостійкість- Нам подобається спати ночами і робити Discord таким, що самозцілюється, наскільки це можливо.
  • Невелика підтримка- Вона має працювати відразу ж, як ми її встановимо. Від нас потрібно лише додавати більше нод у міру збільшення даних.
  • Доведено у роботі- Ми любимо пробувати нові технології, але не надто нові.
  • Передбачувана продуктивність- Нам надсилаються повідомлення, якщо час відгуку API у 95% випадків перевищує 80 мс. Ми також не хочемо стикатися з необхідністю кешувати повідомлення в Redis або Memcached.
  • Не сховище блобів- Запис тисяч повідомлень за секунду не буде добре працювати, якщо нам доведеться безперервно десеріалізувати блоби і приєднувати до них дані.
  • Open source- Ми віримо, що керуємо власною долею і не хочемо залежати від сторонньої компанії.
Cassandra виявилася єдиною СУБД, яка задовольнила всі наші вимоги. Ми можемо просто додавати ноди при масштабуванні, а вона справляється із втратою нод без жодного впливу на додаток. У великих компаніях на кшталт Netflix і Apple - тисячі нод Cassandra. Пов'язані дані зберігаються поруч на диску, забезпечуючи мінімум операцій пошуку та легкий розподіл кластера. Вона підтримується компанією DataStax, але поширюється з відкритим вихідним кодом та силами спільноти.

Зробивши вибір, треба було довести, що він справді виправданий.

Моделювання даних

Найкращий спосіб описати новачкові Cassandra - це абревіатура KKV. Дві букви “K” містять у собі первинний ключ. Перша “K” – це ключ розділу. Він допомагає визначити, в якій ноді живуть дані та де їх знайти на диску. Усередині розділу безліч рядків, і конкретний рядок усередині розділу визначає другий "K" - ключ кластеризації. Він працює як первинний ключ усередині розділу та визначає спосіб сортування рядків. Можете уявити розділ як упорядкований словник. Всі ці якості разом узяті дозволяють дуже потужне моделювання даних.

Пам'ятайте, що повідомлення MongoDB індексувалися з використанням channel_id і created_at ? channel_id став ключем розділу, оскільки всі повідомлення працюють у каналі, але created_at не дає хорошого ключа кластеризації, тому що два повідомлення можуть бути створені одночасно. На щастя, кожен ID в Discord насправді створений у Snowflake, тобто хронологічно сортується. Тож можна було використати саме їх. Первинний ключ перетворився на (channel_id, message_id) , де message_id - це Snowflake. Це означає, що за завантаження каналу ми можемо сказати Cassandra точний діапазон, де шукати повідомлення.

Ось спрощена схема нашої таблиці повідомлень (вона пропускає приблизно 10 колонок).

CREATE TABLE messages (channel_id bigint, message_id bigint, author_id bigint, content text, PRIMARY KEY (channel_id, message_id)) WITH CLUSTERING ORDER BY (message_id DESC);
Хоча схеми Cassandra і схожі на схеми реляційних БД, їх легко змінювати, що не надає будь-якого тимчасового впливу на продуктивність. Ми взяли найкраще від сховища блобів та реляційного сховища.

Як тільки почався імпорт існуючих повідомлень у Cassandra, ми відразу побачили у логах попередження, що знайдено розділи розміром понад 100 МБ. Та НУ?! Адже Cassandra заявляє про підтримку розділів 2 ГБ!Очевидно, сама можливість не означає, що так треба робити. Великі розділи накладають сильне навантаження на збирач сміття Cassandra при ущільненні, розширенні кластера і т.д. Наявність великого розділу також означає, що дані не можна розподілити по кластеру. Стало ясно, що нам доведеться обмежити розміри розділів, тому що деякі канали Discord можуть існувати роками і постійно збільшуватися в розмірі.

Ми вирішили розподілити наші повідомлення блоками (buckets) за часом. Ми подивилися на найбільші канали Discord і визначили, що якщо зберігати повідомлення блоками приблизно по 10 днів, то комфортно вкладемося в ліміт 100 МБ. Блоки потрібно отримувати з message_id чи мітки часу.

DISCORD_EPOCH = 1420070400000 BUCKET_SIZE = 1000 * 60 * 60 * 24 * 10 def ins the number of # seconds since the DISCORD_EPOCH. timestamp = snowflake_id >> 22 return int(timestamp / BUCKET_SIZE) def make_buckets(start_id, end_id=None): return range(make_bucket(start_id), make_bucket(end_id) + 1)
Ключі розділів Cassandra можуть бути складовими, тому нашим новим первинним ключем став ((channel_id, bucket), message_id) .

CREATE TABLE messages (channel_id bigint, bucket int, message_id bigint, author_id bigint, content text, PRIMARY KEY ((channel_id, bucket), message_id)) WITH CLUSTERING ORDER BY (message_id DESC);
Для запиту недавніх повідомлень у каналі ми згенерували діапазон блоків від поточного часу до channel_id (він теж хронологічно сортується як Snowflake і має бути старшим, ніж перше повідомлення). Потім ми послідовно опитуємо розділи до того часу, поки зберемо достатньо повідомлень. Зворотний бік такого методу в тому, що зрідка активним інстансам Discord доведеться опитувати багато різних блоків, щоб зібрати достатньо повідомлень з часом. На практиці виявилося, що все гаразд, тому що для активного інстансу Discord зазвичай знаходиться достатньо повідомлень у першому розділі, і таких більшість.

Імпорт повідомлень у Cassandra пройшов без перешкод, і ми були готові випробувати її у виробництві.

Важкий запуск

Виводити нову систему у виробництво завжди страшно, тому гарною ідеєю буде перевірити її, не торкаючись користувачів. Ми налаштували систему дублювання операцій читання/запису в MongoDB і Cassandra.

Негайно після запуску в баг-трекер з'явилися помилки, що author_id дорівнює нулю. Як він може бути нульовим? Це обов'язкове поле!

Узгодженість у кінцевому рахунку

Cassandra – система типу, тобто гарантована цілісність тут приноситься в жертву доступності, що ми й хотіли, загалом. У Cassandra протипоказано читання перед записом (операції читання дорожчі) і тому все, що робить Cassandra, - це оновлення та вставку (upsert), навіть якщо надати лише певні колонки. Ви також можете писати в будь-яку ноду, і вона автоматично вирішить конфлікти, використовуючи семантику "останній запис виграє" по кожній колонці. То як це нас торкнулося?


Приклад стану гонки редагування/видалення

У випадку, якщо користувач редагував повідомлення, в той час як інший користувач видаляв те саме повідомлення, у нас з'являвся рядок з відсутніми даними, за винятком первинного ключа і тексту, тому що Cassandra записує тільки оновлення і вставки. Для цієї проблеми є два можливі рішення:

  1. Записувати назад ціле повідомлення під час редагування повідомлення. Тоді є можливість воскресіння видалених повідомлень та додаються шанси конфліктів для одночасних записів до інших колонок.
  2. Виявити пошкоджене повідомлення та видалити його з бази.
Ми вибрали другий варіант, визначивши необхідну колонку (у цьому випадку author_id) та видаляючи повідомлення, якщо воно порожнє.

Вирішуючи цю проблему, ми помітили, що були дуже неефективними з операціями запису. Оскільки Cassandra узгоджена в кінцевому рахунку, то вона не може взяти ось так і негайно видалити дані. Їй потрібно реплікувати видалення інші ноди, і це слід зробити навіть якщо ноди тимчасово недоступні. Cassandra справляється з цим, прирівнюючи видалення до своєрідної форми запису під назвою “tombstone” («надгробок»). Під час операції читання вона просто проскакує через надгробки, які зустрічаються по дорозі. Час життя "надгробків" налаштовується (за замовчуванням, 10 днів), і вони назавжди видаляються під час ущільнення бази, якщо термін вийшов.

Видалення колонки та запис нуля в колонку - це абсолютно одне й те саме. В обох випадках створюється надгробок. Оскільки всі записи в Cassandra є оновленнями і вставками, то ви створюєте надгробок навіть якщо спочатку записуєте нуль. На практиці наша повна схема повідомлення складалася з 16 колонок, але середнє повідомлення мало тільки 4 встановлених значення. Ми записували 12 «надгробків» у Cassandra, зазвичай без жодної причини. Вирішення проблеми було простим: записувати в базу лише ненульові значення.

Продуктивність

Відомо, що Cassandra швидше виконує операції запису, ніж читання, і ми спостерігали точно це. Операції запису відбувалися в інтервалі менше мілісекунди, а операції читання – менше 5 мілісекунд. Такі показники спостерігалися незалежно від типу даних, яких здійснювався доступ. Продуктивність зберігалася незмінною протягом тижня тестування. Нічого дивного, ми отримали точно те, чого очікували.


Затримка читання/запису за даними з лога

Відповідно до швидкої, надійної продуктивності читання, ось приклад переходу до повідомлення річної давності в каналі з мільйонами повідомлень:

Великий сюрприз

Все пройшло гладко, тому ми викотили Cassandra як нашу основну базу даних і вивели з ладу MongoDB протягом тижня. Вона продовжувала бездоганно працювати… приблизно 6 місяців, поки одного разу не припинила реагувати.

Ми помітили, що Cassandra безупинно зупиняється на 10 секунд під час складання сміття, але зовсім не могли зрозуміти чому. Почали копати і знайшли канал Discord, який вимагав 20 секунд для завантаження. Винуватцем був публічний Discord-сервер підреддиту Puzzles & Dragons. Оскільки він публічний, ми приєдналися подивитися. На наш подив, на каналі було тільки одне повідомлення. На той момент стало очевидно, що вони видалили мільйони повідомлень через наші API, залишивши лише одне повідомлення на каналі.

Якщо ви уважно читали, то пам'ятайте, як Cassandra обробляє видалення за допомогою "надгробків" (згадано в розділі "Узгодженість в кінцевому рахунку"). Коли користувач завантажує цей канал, хоч там одне повідомлення, Cassandra доводиться ефективно сканувати мільйони надгробків повідомлень. Тоді він генерує сміття швидше, ніж JVM може зібрати його.

Ми вирішили цю проблему так:

  • Зменшили час життя надгробків з 10 днів до 2 днів, тому що ми щовечора запускаємо ремонт Cassandra (протиентропійний процес) на нашому кластері повідомлень.
  • Змінили код запитів, щоб відстежувати порожні блоки на каналі та уникати їх у майбутньому. Це означає, що якщо користувач знову ініціював цей запит, то в гіршому випадку Cassandra скануватиме лише останній блок.

Майбутнє

На даний момент у нас працює кластер з 12 нодів з коефіцієнтом реплікації 3, і ми продовжимо додавати нові ноди Cassandra при необхідності. Ми віримо, що цей підхід працездатний у довгостроковій перспективі, але зі зростанням Discord проглядається віддалене майбутнє, коли доведеться зберігати мільярди повідомлень на день. У Netflix і Apple працюють кластери з сотнями нодів, тому поки що нам нема про що хвилюватися. Однак хочеться мати пару ідей про запас.

Найближче майбутнє

  • Оновити наш кластер повідомлень з Cassandra 2 на Cassandra 3. Новий формат зберігання Cassandra 3 може скоротити обсяг зберігання більш ніж на 50%.
  • Нові версії Cassandra краще справляються з обробкою більшої кількості даних у кожному ноді. Ми зараз зберігаємо приблизно 1 ТБ стислих даних у кожному з них. Думаємо, що можна безпечно скоротити кількість нодів у кластері, збільшивши цей ліміт до 2 ТБ.

Віддалене майбутнє

  • Вивчити Scylla – це СУБД, сумісна з Cassandra та написана на C++. У нормальній роботі наші ноди Cassandra в реальності споживають небагато ресурсів CPU, проте в непикові години під час ремонту Cassandra (протиентропійний процес) вони досить сильно залежать від CPU, а час ремонту зростає в залежності від кількості даних, записаних з моменту минулого ремонту. Scylla обіцяє значно збільшити швидкість ремонту.
  • Створити систему для архівації каналів, що не використовуються, в Google Cloud Storage і завантаження їх назад на вимогу. Ми хочемо уникнути цього і не думаємо, що таке доведеться робити.

Висновок

Пройшло вже більше року з моменту переходу на Cassandra, і незважаючи на «великий сюрприз»Це було спокійне плавання. Ми вийшли з понад 100 мільйонів загальної кількості повідомлень на більш ніж 120 мільйонів повідомлень на день, зберігши продуктивність та стабільність.

Завдяки успіху цього проекту, з тих пір ми перенесли решту наших даних у виробництві на Cassandra, і теж успішно.

Продовжуючи цю статтю, ми досліджуємо, як ми здійснюємо повнотекстовий пошук за мільярдами повідомлень.

У нас досі немає спеціалізованих інженерів DevOps (тільки чотири інженери бекенда), тому дуже класно мати систему, про яку не доводиться хвилюватися. Ми набираємо співробітників, так що звертайтеся, якщо подібні завдання лоскочуть вашу уяву.

Теги: Додати теги

Зараз, коли комп'ютерна та мобільна технологія розвинена негодами, питання першої важливості зосереджено на можливостях підтримувати спілкування між собою.

Месенджери дозволяють у реальному часі обговорити будь-які питання, починаючи від приватних та закінчуючи діловими конференціями. Тому їх популярність анітрохи не менше ніж у розрахованих на багато користувачів ігор.

Всі месенджери мають одну проблему, яка полягає у швидкому накопиченні старих повідомлень. Вони займають зайву пам'ять вашого пристрою.

Очищення чату в Дискорді (інструкція)

Регулярне спілкування у месенджері має властивість забивати пам'ять пристрою. Повідомлення накопичуються, а багато хто з них не несуть смислового навантаження. Тому їхнє видалення необхідне.

Крім того, зберігати все листування дуже ризиковано. Існує велика ймовірність витоку даних, внаслідок чого може бути використана як компромат на вас самих. Щоб не допустити такого результату подій, необхідно своєчасно чистити історію. У Дискорді це можна виконати трьома способами:

  • Видалити канал.
  • Окреме видалення кожного повідомлення.
  • Видалення всіх повідомлень за останній тиждень.

Після відправки є всього кілька секунд, які дозволяють видалити повідомлення до того, як його побачать всі учасники каналу. Вибір способу очищення дуже ситуативний, і підбирається під особисті потреби автора сервера. Докладніше про кожен із методів з інструкцією використання.

Спосіб перший, видалити весь канал і створити новий Р2>

Простіше варіанта не придумати. Коли тема вичерпала себе, або просто накопичилося багато компромату в обговореннях, повністю видаліть канал і створіть новий. Видалення відбувається за кілька секунд і відновленню не підлягає.

Увага! Якщо є важлива інформація, перепишіть окремий документ або перезбережіть скріншотами.

Потрібно виконати кілька простих кроків:



Потім створюєте новий, можна навіть із попередньою назвою.

Спосіб другий: видаляємо кожне повідомлення окремо

Найтриваліший спосіб чищення. Через великі тимчасові витрати, підходить тільки для видалення невеликої кількості. Інструкція по використанню:



Віддалені повідомлення зникнуть у всіх користувачів каналу. Якщо було помічено в закладки – зникне.

Спосіб третій: чищення за останні 7 днів

Цей метод застосовується лише до повідомлень користувача, якого ви бажаєте забанити. Перед надсиланням до чорного списку вам буде запропоновано вибір, за який період видалити історію листів від користувача:

  • За двадцять чотири години.
  • Або останні сім днів (і ночей).


Як помістити людину в чорний список:

  • на імені користувача натиснути правою кнопкою мишки та вибрати – Забанити (далі буде вказано нікнейм користувача).


Вказувати причину за бажанням, можете залишити поле порожнім.

Як часто варто очищати чат?

Очищення чату повністю залежить від вашої тематики спільноти. Якщо ви обмінюєтеся гумором, тоді немає сенсу видаляти, краще залишити все як є, щоб можна було, повернуться до запису, що сподобався.

Якщо у вас збірна солянка, умовно, повна свобода обговорення на різні тематики, то краще підчищати хоча б раз на кілька днів. В ідеалі звісно – раз на добу. Конкретних вимог у цьому питанні немає, тож кожен Адміністратор сам встановлює собі планку у цьому питанні.