Re: Задачка на проектирование
От: Мирный герцог Ниоткуда  
Дата: 24.04.20 18:21
Оценка: +1 :))) :)
Здравствуйте, Ватакуси, Вы писали:

В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.


держать счётчик в памяти, какие ещё могут быть решения? Гарантировать сохранение в базу будет raid-массив и дизель-генератор. Вероятность выхода из строя raid-массива с дизель-генератором считать много меньшей вероятности банкротства компании.
нормально делай — нормально будет
Re[3]: Задачка на проектирование
От: Pzz Россия https://github.com/alexpevzner
Дата: 25.04.20 08:24
Оценка: 10 (3) +1
Здравствуйте, Ватакуси, Вы писали:

В>Да. "Правильное решение" примерно так и должно выглядеть.

В>Как это осуществить?

Ну для начала, надо бы побенчмаркать, на чем вообще можно сделать HTTP-сервер, способный держать миллион пустых запросов в секунду. Скажем, если запрос и ответ укладываются в 1 килобайт (а это довольно близкое приближение), то там чисто сетевого трафика набегает по 8 гигабит в каждую сторону. Одна писишка, боюсь, не потянет, а десяток писишек потянут с легкостью, на чем не пиши. Т.е. понадобится какой-нибудь load balancer и сетевое хранилище, скорострельность которого нам не очень важна, но оно должено обладать одним хитрым свойством, о котором чуть позже.

Далее, вопрос о своевременности чтения, как многие уже заметили, не стоит, но вопрос о монотонности счетчика все же стоит упомянуть. В последовательности read-inc-read второй read должен возвращать число, которое больше, чем вернул первый read. Ну, хотя бы для приличия. И никакие два клиента, даже сговорившись, не должны увидеть одинаковый ответ на read, если в промежутке проскочил инкремент.

Поскольку для конструкции из сети, load balancer'а и нескольких писишек, обслуживание запросов будет наверняка происходить не всегда в порядке поступления, часть забот о монотонности нам придется переложить на клиентов. А именно, мы возьмем с них обязательство, что они не будут посылать несколько запросов одновременно, иначе мы не гарантируем, что их запросы будут обслужены в правильном порядке.

Еще одна печальная новость заключается в том, что из-за необходимости изображать из себя монотонный счетчик, нам придется запросы на чтение ставить в общую очередь с запросами на запись. Хотя приятнее было бы обслужить их, чтобы не мешалось, мгновенно после поступления, глядя просто на счетчик в памяти.

А что до хранилища, нам от него понадобится один единственный запрос, но хитрый: он должен прибавлять к счетчику, что сказали, и возвращать старое значение. Назовем его read-increment.

Ну а дальше все относительно просто. Нам понадобится очередь запросов. Изначально очередь пустая. Первый поступивший запрос посылает хранилищу запрос read-increment(0), если это запрос на чтение, и read-incrememt(1), если это запрос на увеличение счетчика, и становится в очередь. Остальные просто становятся в очередь. Запрос в хранилище посылается асинхронно. И еще, мы запоминаем, сколько запросов было в очереди, когда мы послали запрос в хранилище.

Когда из хранилища придет ответ, мы выгребаем из очереди столько запросов, сколько было на момент обращения к хранилищу — не зря мы запомнили это число. У нас есть вся информация, чтобы их обслужить: актуальный счетчик из базы и сколько к нему прибавилось по мере продвижения по очереди. Если у нас после этого в очереди остались запросы, мы считаем, сколько из них инкременты, и посылаем очередной read-increment(), указав в качестве параметра количество оставшихся инкрементов. Ну и так далее.

Еще было бы не лишне поставить какое-то ограничение на максимальную длинну очереди. Если оно превышено, очередной запрос сразу получает HTTP 503, и в очередь не становится.

По-моему, так (c) Винни Пух.
Re: Задачка на проектирование
От: Lexey Россия  
Дата: 24.04.20 17:22
Оценка: +4
Здравствуйте, Ватакуси, Вы писали:

В>read — получить текущее глобальное значение


А что такое "текущее" значение? Если у тебя дофига запросов на запись, то оно будет устаревать практически сразу после чтения.
"Будь достоин победы" (c) 8th Wizard's rule.
Re: Задачка на проектирование
От: mik1  
Дата: 24.04.20 22:37
Оценка: 5 (1) +2
Здравствуйте, Ватакуси, Вы писали:

В>REST-сервис


В>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>read — получить текущее глобальное значение

В>сервис на сервере, который пишет и читает из постгреса.


В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.


В>Ваши предложения.

В>Бюджет относительно небольшой, поэтому всякие супер-космические решения не годятся.

Какая разбивка между reads and increments? Одинаковый rps или сильный перевес с одну сторону?
Какая точность нужна для read (если ожидаем latency < 50 ms, то насколько старое значение можно вернуть, т.к очевидно что "текущее" не имеет смысла в такой системе)
И самое главное — зачем postgres, если мы по сути имеем всего несколько байт данных (ну или скаляр по одному числу на линию кэша)?

Как только вы ответите себе на эти вопросы, остальное станет просто.
Для 100К огород вообще городить не надо, один 1-сокетный сервер справится без проблем. На миллион тоже можно поколдовать.
Re: Задачка на проектирование
От: elmal  
Дата: 26.04.20 06:14
Оценка: 5 (1)
Здравствуйте, Ватакуси, Вы писали:

В>Бюджет относительно небольшой, поэтому всякие супер-космические решения не годятся.

Тестовое задание чтоль делаешь ?

Тривиально. Получил событие inc n — положил в очередь. Другие потоки, а то и сервера — они вычитывают из очереди и уже атомарно инкрементят счетчик, который либо в памяти, либо это распределенный кеш. Операция read тривиальная, просто достать значение. 100к держать будет даже на одной машине навскидку. Если нужен постгрес, и он оказывается узким местом (нужно проверять) — периодически иожно сбрасывать значение текущего счетчика в базу. По идее задача адекватно решается даже на одном серваке без резервирования.

Подобная концепция вроде как называется CQRS.
Re[5]: Задачка на проектирование
От: Pzz Россия https://github.com/alexpevzner
Дата: 04.05.20 19:51
Оценка: 5 (1)
Здравствуйте, Sharov, Вы писали:

Pzz>> Т.е. понадобится какой-нибудь load balancer и сетевое хранилище, скорострельность которого нам не очень важна, но оно должено обладать одним хитрым свойством, о котором чуть позже.


S>А lb то каким должен быть, ибо все эти 8Гб через него же ходят?


Вот не знаю, честно. Возможно, у них внутри что-нибудь более легковесное, чем linux TCP/IP stack.

Pzz>>А что до хранилища, нам от него понадобится один единственный запрос, но хитрый: он должен прибавлять к счетчику, что сказали, и возвращать старое значение. Назовем его read-increment.


S>Я правильно понимаю, что чтение из хранилища надо в сл. нескольких машин, а не одной?


Я не понял вопрос.

Pzz>>Ну а дальше все относительно просто. Нам понадобится очередь запросов. Изначально очередь пустая. Первый поступивший запрос посылает хранилищу запрос read-increment(0), если это запрос на чтение, и read-incrememt(1), если это запрос на увеличение счетчика, и становится в очередь. Остальные просто становятся в очередь. Запрос в хранилище посылается асинхронно. И еще, мы запоминаем, сколько запросов было в очереди, когда мы послали запрос в хранилище.


S>Смысл асинхронно, что мы будем делать в этот момент? Мы даже чтение обслужить без результата запроса не можем.


Выгребать запросы из сокетов, парсить их, ставить в очередь, рассылать ответы.

У нас основная нагрузка — это именно HTTP. Затраты на содержательную обработку запросов очень низкие.
Re[3]: Задачка на проектирование
От: Qulac Россия  
Дата: 24.04.20 15:22
Оценка: 2 (1)
Здравствуйте, Ватакуси, Вы писали:

В>>>REST-сервис


В>>>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>>>read — получить текущее глобальное значение

В>>>сервис на сервере, который пишет и читает из постгреса.

В>>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

G>>Что-то не очень точные входные данные.


G>>1) Предположим у нас есть бесконечно мощный веб-сервер, который сам по себе вывезет 1М rps. Тогда не нужен даже постгрес, просто пишем данные в файл на диск при inc с эксклюзивной блокировкой на запись и отдаем файл с диска при запросе read. Быстрее точно никак не получится. Это может даже для 100к сработать если соотношение чтении и записи 100:1.

G>>2) Но в реальности сервер не выдержит 1М rps, просто очередь переполнится. То есть надо будет несколько серверов и писать надо будет в postgres. И тут быстродействие упирается в сам postgres, потому что он сам будет задыхаться даже от 1К запросов на изменение данных. Но по условию надо получить ответ от базы. Тут поможет только сервер пожирнее, потому что мастшабировать запись в одну ячейку без потери целостности невозможно.

В>Именно в этом и заключается подвох задачи. Увеличивать мощность сервера приложений или даже сервера ДБ нельзя до бесконечности (да и деньги кончатся).

В>Поскольку все запросы inc будут биться за одну глобальную переменную, то они сразу станут в очередь.

В>Но решение (типа) есть.


Объединять несколько inc n на дополнительных серверах, а на основной отправлять inc n1+n2+n3+...? Но это только на запись и не известно быстрей ли будет.
Программа – это мысли спрессованные в код
Задачка на проектирование
От: Ватакуси Россия  
Дата: 24.04.20 10:16
Оценка: :)
REST-сервис

inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.
read — получить текущее глобальное значение

сервис на сервере, который пишет и читает из постгреса.

Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

Ваши предложения.
Бюджет относительно небольшой, поэтому всякие супер-космические решения не годятся.
Все будет Украина!
Re: Задачка на проектирование
От: L.K. Марс  
Дата: 24.04.20 10:27
Оценка: :)
В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

Redis + Golang?

В>Бюджет относительно небольшой


Миллион rps на виртуальном серваке за 5 баксов? Что за проект-то? Счётчик экземпляров короновируса?
Re[2]: Задачка на проектирование
От: Zhendos  
Дата: 24.04.20 15:23
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Ватакуси, Вы писали:


В>>REST-сервис


В>>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>>read — получить текущее глобальное значение

В>>сервис на сервере, который пишет и читает из постгреса.

В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

G>Что-то не очень точные входные данные.


G>1) Предположим у нас есть бесконечно мощный веб-сервер, который сам по себе вывезет 1М rps. Тогда не нужен даже постгрес, просто пишем данные в файл на диск при inc с эксклюзивной блокировкой на запись и отдаем файл с диска при запросе read. Быстрее точно никак не получится. Это может даже для 100к сработать если соотношение чтении и записи 100:1.

G>2) Но в реальности сервер не выдержит 1М rps, просто очередь переполнится.

ну можно взять какую-нибудь быструю ПЗУ, типа Intel Optane,
и писать туда напрямую, а TCP/IP и Ethernet обрабатывать почти полностью
в user-space или наоборот все в kernel space включаю логику инкремента и записи optane,
тогда я думаю 100k должно выдавать без проблем, даже на относительно слабом железе.
Re: Задачка на проектирование
От: Pzz Россия https://github.com/alexpevzner
Дата: 24.04.20 22:20
Оценка: +1
Здравствуйте, Ватакуси, Вы писали:

В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.


Очевидно, что никакая база тебе не даст "100к или даже миллион" записей в секунду. Однако требование на 50 мс на отклик внушает надежду — 20 записей в секунду можно потянуть, даже если хранить данные в текстовом файле, который каждый раз обновляется.

Значит, тебе надо собирать запросы в кучку, суммировать их эффект, сохранять их в базу одной записью на много запросов, и если она прошла уачно, всем везунчикам отвечать "200 ОК".
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 24.04.20 10:40
Оценка:
В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

LK>Redis + Golang?

Не гарантирует сохранение в базу.

В>>Бюджет относительно небольшой


LK>Миллион rps на виртуальном серваке за 5 баксов? Что за проект-то? Счётчик экземпляров короновируса?

Речь о том, что нельзя брать Redis Enterprise (например), который стоит миллионы денег.

Ну, скажем 100 тыщ денег у тебя есть.
Все будет Украина!
Отредактировано 24.04.2020 10:41 Ватакуси . Предыдущая версия .
Re[3]: Задачка на проектирование
От: L.K. Марс  
Дата: 24.04.20 12:39
Оценка:
LK>>Redis + Golang?
В>Не гарантирует сохранение в базу.

Почему?

В>Речь о том, что нельзя брать Redis Enterprise (например), который стоит миллионы денег.


Энтерпрайз на 100 гиг и 100k rps стоит 4k в месяц. Бюджета в 100k вполне хватит.
Re[4]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 24.04.20 12:54
Оценка:
LK>>>Redis + Golang?
В>>Не гарантирует сохранение в базу.

LK>Почему?

А если он упадёт?

В>>Речь о том, что нельзя брать Redis Enterprise (например), который стоит миллионы денег.


LK>Энтерпрайз на 100 гиг и 100k rps стоит 4k в месяц. Бюджета в 100k вполне хватит.

Где про это можно почитать? Меня уверяли совсем в других цифрах...
Все будет Украина!
Re[5]: Задачка на проектирование
От: L.K. Марс  
Дата: 24.04.20 13:08
Оценка:
В>А если он упадёт?

Для этого есть кластерная репликация. Также можно сделать отказоустойчивость на уровне REST-сервера (Golang).

LK>>Энтерпрайз на 100 гиг и 100k rps стоит 4k в месяц. Бюджета в 100k вполне хватит.

В>Где про это можно почитать?

На официальном сайте, разумеется:

https://redislabs.com/redis-enterprise-cloud/pricing/
Re[2]: Задачка на проектирование
От: DiPaolo Россия  
Дата: 24.04.20 13:14
Оценка:
Здравствуйте, L.K., Вы писали:

В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.


LK>Redis + Golang?


+ лад балансер, видимо
Патриот здравого смысла
Re: Задачка на проектирование
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.04.20 13:19
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>REST-сервис


В>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>read — получить текущее глобальное значение

В>сервис на сервере, который пишет и читает из постгреса.

В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

Что-то не очень точные входные данные.

1) Предположим у нас есть бесконечно мощный веб-сервер, который сам по себе вывезет 1М rps. Тогда не нужен даже постгрес, просто пишем данные в файл на диск при inc с эксклюзивной блокировкой на запись и отдаем файл с диска при запросе read. Быстрее точно никак не получится. Это может даже для 100к сработать если соотношение чтении и записи 100:1.
2) Но в реальности сервер не выдержит 1М rps, просто очередь переполнится. То есть надо будет несколько серверов и писать надо будет в postgres. И тут быстродействие упирается в сам postgres, потому что он сам будет задыхаться даже от 1К запросов на изменение данных. Но по условию надо получить ответ от базы. Тут поможет только сервер пожирнее, потому что мастшабировать запись в одну ячейку без потери целостности невозможно.
Re: Задачка на проектирование
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 24.04.20 14:23
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>REST-сервис


В>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>read — получить текущее глобальное значение
Зачем n?
В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.
В>Ваши предложения.
Ставишь Kafka/rabbit, складируешь запросы (гарантия что все будут обработаны), и раскидываешь их по обработчикам которые пишут в базу. Схема конечно тупая т.к. в базу будут ломиться все обработчики запросов и она будет узким местом, но если баз несколько, то можно наверное. Короче, я в этом не разбираюсь, написал как нафантазировал, возможно я бред несу .

В>Бюджет относительно небольшой, поэтому всякие супер-космические решения не годятся.

амазон SQS, динамические инстансы под нагрузку, вопрос только к том, выдержит ли твоя БД 1кк update-ов в секунду.
Sic luceat lux!
Re[6]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 24.04.20 15:11
Оценка:
LK>>>Энтерпрайз на 100 гиг и 100k rps стоит 4k в месяц. Бюджета в 100k вполне хватит.
В>>Где про это можно почитать?

LK>На официальном сайте, разумеется:


LK>https://redislabs.com/redis-enterprise-cloud/pricing/

Я может тупой, но где там про 100k rps написано?
Все будет Украина!
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 24.04.20 15:14
Оценка:
В>>REST-сервис

В>>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>>read — получить текущее глобальное значение

В>>сервис на сервере, который пишет и читает из постгреса.

В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

G>Что-то не очень точные входные данные.


G>1) Предположим у нас есть бесконечно мощный веб-сервер, который сам по себе вывезет 1М rps. Тогда не нужен даже постгрес, просто пишем данные в файл на диск при inc с эксклюзивной блокировкой на запись и отдаем файл с диска при запросе read. Быстрее точно никак не получится. Это может даже для 100к сработать если соотношение чтении и записи 100:1.

G>2) Но в реальности сервер не выдержит 1М rps, просто очередь переполнится. То есть надо будет несколько серверов и писать надо будет в postgres. И тут быстродействие упирается в сам postgres, потому что он сам будет задыхаться даже от 1К запросов на изменение данных. Но по условию надо получить ответ от базы. Тут поможет только сервер пожирнее, потому что мастшабировать запись в одну ячейку без потери целостности невозможно.

Именно в этом и заключается подвох задачи. Увеличивать мощность сервера приложений или даже сервера ДБ нельзя до бесконечности (да и деньги кончатся).
Поскольку все запросы inc будут биться за одну глобальную переменную, то они сразу станут в очередь.

Но решение (типа) есть.
Все будет Украина!
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 24.04.20 15:16
Оценка:
В>>REST-сервис

В>>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>>read — получить текущее глобальное значение
K>Зачем n?
Хочешь на 1 увеличить или на 10, например.

В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

В>>Ваши предложения.
K>Ставишь Kafka/rabbit, складируешь запросы (гарантия что все будут обработаны), и раскидываешь их по обработчикам которые пишут в базу. Схема конечно тупая т.к. в базу будут ломиться все обработчики запросов и она будет узким местом, но если баз несколько, то можно наверное. Короче, я в этом не разбираюсь, написал как нафантазировал, возможно я бред несу .
Да, всё упрётся в базу.
Но кафка (типа) часть решения, да.

В>>Бюджет относительно небольшой, поэтому всякие супер-космические решения не годятся.

K>амазон SQS, динамические инстансы под нагрузку, вопрос только к том, выдержит ли твоя БД 1кк update-ов в секунду.
Одной БД не сделать, это понятно.
Все будет Украина!
Re[7]: Задачка на проектирование
От: L.K. Марс  
Дата: 24.04.20 15:20
Оценка:
LK>>https://redislabs.com/redis-enterprise-cloud/pricing/
В>Я может тупой, но где там про 100k rps написано?

Large Datasets / Many Databases / Redis Modules
100GB
100k ops/sec | 64 Databases
$5.60/hr

А вообще, о каком хайлоде может идти речь? Если ты искать и читать не умеешь...
Re[3]: Задачка на проектирование
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.04.20 17:03
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>Именно в этом и заключается подвох задачи. Увеличивать мощность сервера приложений или даже сервера ДБ нельзя до бесконечности (да и деньги кончатся).

В>Поскольку все запросы inc будут биться за одну глобальную переменную, то они сразу станут в очередь.
В>Но решение (типа) есть.

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

Но в реальности нет такого, что количество запросов растет бесконечно. Более того, 90% проектов не преодолеют возможности одной машины.
Re[3]: Задачка на проектирование
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 24.04.20 18:21
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>Хочешь на 1 увеличить или на 10, например.

Мне не понятно зачем тебе счётчик такой нужен.
В>Одной БД не сделать, это понятно.
можно амазоновускую заюзать, но $$$$ отвалишь .
Sic luceat lux!
Re[2]: Задачка на проектирование
От: Lazy Bear Канада  
Дата: 24.04.20 21:12
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, Ватакуси, Вы писали:


В>>read — получить текущее глобальное значение


L>А что такое "текущее" значение? Если у тебя дофига запросов на запись, то оно будет устаревать практически сразу после чтения.


Во-во. Может быть, настоящая задача совсем другая
Re[8]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:39
Оценка:
LK>А вообще, о каком хайлоде может идти речь? Если ты искать и читать не умеешь...

И вам не кашлять.
Все будет Украина!
Re[4]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:39
Оценка:
В>>Именно в этом и заключается подвох задачи. Увеличивать мощность сервера приложений или даже сервера ДБ нельзя до бесконечности (да и деньги кончатся).
В>>Поскольку все запросы inc будут биться за одну глобальную переменную, то они сразу станут в очередь.
В>>Но решение (типа) есть.

G>Если мы предполагаем что количество запросов растет бесконечно, то есть заведомо больше чем любая жеезная конфигурация может выдержать, то нет решения без дополнительных условий.

G>Потому что CAP-теорему (будь она неладна) обмануть нельзя. Тут или согласованностью чтения надо жертвовать, или время ответа не жестко фиксировать.

G>Но в реальности нет такого, что количество запросов растет бесконечно. Более того, 90% проектов не преодолеют возможности одной машины.

Не бесконечно, конечно же. Кол-во запросов просто большое.
Все будет Украина!
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:40
Оценка:
В>>read — получить текущее глобальное значение

L>А что такое "текущее" значение? Если у тебя дофига запросов на запись, то оно будет устаревать практически сразу после чтения.


Согласен.
Но интуитивно, это значение, которое успело уже записаться.
Все будет Украина!
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:42
Оценка:
В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

МГ>держать счётчик в памяти, какие ещё могут быть решения? Гарантировать сохранение в базу будет raid-массив и дизель-генератор. Вероятность выхода из строя raid-массива с дизель-генератором считать много меньшей вероятности банкротства компании.


Смешно
Все будет Украина!
Re[4]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:43
Оценка:
В>>Хочешь на 1 увеличить или на 10, например.
K>Мне не понятно зачем тебе счётчик такой нужен.
Просто поболтать, это же не настоящая задача, ты понимашь.
Все будет Украина!
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:44
Оценка:
В>>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.

Pzz>Очевидно, что никакая база тебе не даст "100к или даже миллион" записей в секунду. Однако требование на 50 мс на отклик внушает надежду — 20 записей в секунду можно потянуть, даже если хранить данные в текстовом файле, который каждый раз обновляется.


Pzz>Значит, тебе надо собирать запросы в кучку, суммировать их эффект, сохранять их в базу одной записью на много запросов, и если она прошла уачно, всем везунчикам отвечать "200 ОК".


Да. "Правильное решение" примерно так и должно выглядеть.
Как это осуществить?
Все будет Украина!
Re[2]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:46
Оценка:
M>Какая разбивка между reads and increments? Одинаковый rps или сильный перевес с одну сторону?
M>Какая точность нужна для read (если ожидаем latency < 50 ms, то насколько старое значение можно вернуть, т.к очевидно что "текущее" не имеет смысла в такой системе)
Это заранее неизвестно, скажем так. Т.е. может быть любое соотношение.

M>И самое главное — зачем postgres, если мы по сути имеем всего несколько байт данных (ну или скаляр по одному числу на линию кэша)?

Можно предлагать, что угодно. Можно и отказаться от него, если есть решение.

M>Как только вы ответите себе на эти вопросы, остальное станет просто.

M>Для 100К огород вообще городить не надо, один 1-сокетный сервер справится без проблем. На миллион тоже можно поколдовать.
Очевидно, что узким местом тут является запись в глобальную переменную. Как это распарралелить?
Все будет Украина!
Re[3]: Задачка на проектирование
От: Ватакуси Россия  
Дата: 25.04.20 06:48
Оценка:
Z>ну можно взять какую-нибудь быструю ПЗУ, типа Intel Optane,
Z>и писать туда напрямую, а TCP/IP и Ethernet обрабатывать почти полностью
Z>в user-space или наоборот все в kernel space включаю логику инкремента и записи optane,
Z>тогда я думаю 100k должно выдавать без проблем, даже на относительно слабом железе.

Довольно необычное решение. Спасибо.
Все будет Украина!
Re[3]: Задачка на проектирование
От: Sharowarsheg  
Дата: 25.04.20 07:28
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>>>read — получить текущее глобальное значение


L>>А что такое "текущее" значение? Если у тебя дофига запросов на запись, то оно будет устаревать практически сразу после чтения.


В>Согласен.

В>Но интуитивно, это значение, которое успело уже записаться.

В смысле, с гарантией, что при повторном запросе нельзя получить ответ меньше, чем при первом запросе. Никакой другой гарантии особо не получится.
Re: Задачка на проектирование
От: v.a.v СССР  
Дата: 25.04.20 10:55
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>REST-сервис


В>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>read — получить текущее глобальное значение

В>сервис на сервере, который пишет и читает из постгреса.


В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.


В>Ваши предложения.

В>Бюджет относительно небольшой, поэтому всякие супер-космхраниические решения не годятся.

Абстрактная проблема — абстрактное решение.

Несколько серверов с сервисами для обслуживания запросов "inc n".
Каждый сервер со своим экземпляром СУБД(PostgreSQL по условию задачи), на локальном диске/дисковом массиве(никаких внешних СХД). В каждом экземпляре PostgreSQL собственный счетчик-накопитель. Сервисы обрабатывающие запросы "inc n" кешируют текущее значение счетчика-накопителя в памяти(изменение кеша после успешного изменения в БД), и периодически отправляют(push) его сервису-агрегатору(собственный протокол поверх UDP, или даже RDMA).
Балансировка, например посредством DNS. Получаем практически неограниченное горизонтальное масштабирование по запросу "inc n".

Сервис-агрегатор периодически суммирует push-и от вышеописанных сервисов и отправляет(push) результат множеству сервисов "read"(собственный протокол поверх multicast UDP, или RDMA, если RDMA умеет multicast). Сервис-агрегатор не нуждается в хранилище данных.

Несколько сервисов "read" котрые отправляют суммарное значение счетчиков-накопителей клиентам по запросу. Получаем практически неограниченное горизонтальное масштабирование по запросу "read". Сервис "read" не нуждается в хранилище данных.

Потенциальное узкое место — сервис-агрегатор. Но он только суммирует числа и отправляет результаты(причем не персонально каждому сервису получателю, а сразу всем, и без установки соединения). В крайнем случае можно применить каскадирование агрегаторов, и тогда агрегация станет горизонтально масштабируемой.

Стоимость реализации сравнительно не высока, так как специальнго оборудования не требуется. Сервисам-агрегаторам и сервисам "read" даже HDD после старта не нужен. Для сервисов "inc n" важны только накопители с низкой задержкой.

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

Можно обойтись и без "собственный протокол поверх UDP, или даже RDMA", но тогда возможно придется увеличить количество экземпляров сервисов, да и лаги станут больше.
Отредактировано 25.04.2020 11:08 v.a.v . Предыдущая версия .
Re[4]: Задачка на проектирование
От: Sharov Россия  
Дата: 04.05.20 19:16
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, Ватакуси, Вы писали:


В>>Да. "Правильное решение" примерно так и должно выглядеть.

В>>Как это осуществить?

Pzz> Т.е. понадобится какой-нибудь load balancer и сетевое хранилище, скорострельность которого нам не очень важна, но оно должено обладать одним хитрым свойством, о котором чуть позже.


А lb то каким должен быть, ибо все эти 8Гб через него же ходят?


Pzz>А что до хранилища, нам от него понадобится один единственный запрос, но хитрый: он должен прибавлять к счетчику, что сказали, и возвращать старое значение. Назовем его read-increment.


Я правильно понимаю, что чтение из хранилища надо в сл. нескольких машин, а не одной?

Pzz>Ну а дальше все относительно просто. Нам понадобится очередь запросов. Изначально очередь пустая. Первый поступивший запрос посылает хранилищу запрос read-increment(0), если это запрос на чтение, и read-incrememt(1), если это запрос на увеличение счетчика, и становится в очередь. Остальные просто становятся в очередь. Запрос в хранилище посылается асинхронно. И еще, мы запоминаем, сколько запросов было в очереди, когда мы послали запрос в хранилище.


Смысл асинхронно, что мы будем делать в этот момент? Мы даже чтение обслужить без результата запроса не можем.
Кодом людям нужно помогать!
Re: Задачка на проектирование
От: scf  
Дата: 04.05.20 19:31
Оценка:
Здравствуйте, Ватакуси, Вы писали:

В>REST-сервис


В>inc n — увеличить глобальное значение на n. После того как запись в базу сделана возвращается код 200. Это гарантия, что счётчик увеличился.

В>read — получить текущее глобальное значение

В>сервис на сервере, который пишет и читает из постгреса.


В>Как сделать / спроектировать систему так, чтобы она работала на 100k или даже миллионе rps и не более 50 мс отклик.


В>Ваши предложения.

В>Бюджет относительно небольшой, поэтому всякие супер-космические решения не годятся.

Надежность какая нужна? Судя по неидемпотентному API, абсолютная точность не требуется. Так что оптимально — синхронизированный счетчик в памяти, который периодически, каждые 10 мс, например, пишется в постгрес.

Для масштабирования разворачиваются несколько нод, каждая со своим собственным счетчиком. read читает данные всех счетчиков и суммирует.
Re[6]: Задачка на проектирование
От: Sharov Россия  
Дата: 04.05.20 20:38
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>>>А что до хранилища, нам от него понадобится один единственный запрос, но хитрый: он должен прибавлять к счетчику, что сказали, и возвращать старое значение. Назовем его read-increment.

S>>Я правильно понимаю, что чтение из хранилища надо в сл. нескольких машин, а не одной?
Pzz>Я не понял вопрос.

В случае одной машины зачем в базу лезть? Т.е. писать надо, а отвечать можно по памяти.
Кодом людям нужно помогать!
Re[7]: Задачка на проектирование
От: Pzz Россия https://github.com/alexpevzner
Дата: 04.05.20 20:41
Оценка:
Здравствуйте, Sharov, Вы писали:

S>В случае одной машины зачем в базу лезть? Т.е. писать надо, а отвечать можно по памяти.


Если отвечать по памяти, и програмка упадет в процессе записи, не успев ничего записать, то кто-то получит одну и ту же чиселку два раза.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.