У нас виникла ситуація, коли мені доводиться стикатися з масовим напливом подій, що надходять на наш сервер, в середньому близько 1000 подій в секунду (пік може бути ~ 2000).
Проблема
Наша система розміщується на Heroku та використовує відносно дорогий БД Heroku Postgres , який дозволяє максимум 500 підключень до БД. Ми використовуємо пул з'єднань для підключення з сервера до БД.
Події надходять швидше, ніж може працювати пул з'єднань з БД
Проблема в нас полягає в тому, що події відбуваються швидше, ніж пул з'єднань може впоратися. До того моменту, коли одне з'єднання закінчило мережевий перехід із сервера в БД, тож воно може бути відпущене назад до пулу, і не nвідбудеться більше додаткових подій.
Врешті-решт події складаються, очікуючи збереження, і тому що в пулі немає доступних з'єднань, вони вичерпуються, і вся система виводиться з ладу.
Ми вирішили надзвичайну ситуацію, випускаючи від клієнтів високочастотні події повільнішими темпами, але ми все ще хочемо знати, як поводитися з цими сценаріями у випадку, якщо нам потрібно обробляти ці високочастотні події.
Обмеження
Інші клієнти можуть одночасно читати події
Інші клієнти постійно вимагають прочитати всі події певним ключем, навіть якщо вони ще не збережені в БД.
Клієнт може запитувати GET api/v1/events?clientId=1та отримувати всі події, надіслані клієнтом 1, навіть якщо ці події ще не виконані, зберігаючи в БД.
Чи є приклади «класної кімнати», як з цим боротися?
Можливі рішення
Замовте події на нашому сервері
Ми можемо передбачити події на сервері (з чергою максимальна сумісність 400, щоб пул зв’язків не закінчувався).
Це погана ідея, оскільки:
- Він з'їсть доступну пам'ять сервера. Складені захоплені події будуть використовувати велику кількість оперативної пам’яті.
- Наші сервери перезапускаються раз на 24 години . Це жорстка межа, нав'язана Героку. Сервер може перезапуститись, коли події вмикаються, внаслідок чого ми втрачаємо події, що перебувають у спаді
- Він вводить стан на сервері, тим самим шкода масштабованості. Якщо у нас є налаштування декількох серверів, і клієнт хоче прочитати всі зафіксовані + збережені події, ми не будемо знати, на якому сервері живуть події, котрі стосуються.
Скористайтеся окремою чергою повідомлень
Я припускаю, що ми могли б використовувати чергу черг (наприклад, RabbitMQ ?), Де ми перекачуємо повідомлення в ній, а на іншому кінці є ще один сервер, який займається збереженням подій у БД.
Я не впевнений, чи дозволяють черги повідомлень запитувати події, пов’язані з запитом (які ще не збереглися), тому якщо інший клієнт хоче прочитати повідомлення іншого клієнта, я можу просто отримати збережені повідомлення з БД та очікувані повідомлення з черги і з'єднати їх разом, щоб я міг відправити їх назад клієнту із запитом на читання.
Використовуйте кілька баз даних, кожна з яких зберігає частину повідомлень на центральному сервері координатора БД для управління ними
Ще одне рішення, яке ми маємо, - це використання декількох баз даних з центральним "координатором БД / балансиром завантаження". Отримавши подію, цей координатор вибере одну з баз даних, на яку написати повідомлення. Це повинно дозволяти нам використовувати декілька баз даних Heroku, таким чином збільшуючи межу з'єднання до 500 x кількості баз даних.
Після запиту читання, цей координатор може видати SELECTзапити до кожної бази даних, об'єднати всі результати та відправити їх тому клієнту, який запросив прочитане.
Це погана ідея, оскільки:
- Ця ідея звучить як ... гм .. надмірна інженерія? Був би кошмаром і для керування (резервне копіювання тощо). Складно створювати та підтримувати, і якщо це абсолютно не потрібно, це звучить як порушення KISS .
- Він жертвує послідовністю . Здійснення транзакцій у кількох БД - це безрезультатно, якщо ми з цією ідеєю.
ANALYZEнад запитами, і вони не є проблемою. Я також створив прототип, щоб перевірити гіпотезу пулу підключень і переконався, що це справді проблема. База даних і сам сервер живуть на різних машинах, отже, і затримка. Крім того, ми не хочемо відмовлятися від Heroku, якщо це абсолютно не потрібно, не турбуючись про розгортання - це величезний плюс для нас.
select nullна 500 підключень. Б'юсь об заклад, ви виявите, що пул з'єднань тут не проблема.
