Pull to refresh
59
29
Стас Выщепан @gandjustas

Умею оптимизировать программы

Send message
По порядку:
1) Скорость записей упирается в диски. Хотя я даже на обычном SQL Server делал 10к записей в секунду пачками по 5к в транзакции. Уровень надежности не ниже записи в любую nosql базу.
2) Рекомендации не пересчитывают на каждое событие ибо это очень дорогая операция, которая далеко не в скорость записи упирается. А влияние одного события на рекомендации ничтожное. Я делал системы рекомендаций и прекрасно знаю как они работают.
3) В принципе существуют системы для онлайн пересчета аналитики по событиям, им необязательно писать каждое событие на диск.
4) По поводу ebay не знаю, возможно при их объемах и нагрузке Cassandra помогает. Но далеко не каждый проект вырастает до масштабов ebay, а nosql на старте проекта только мешает. Из за отсутствия гарантий приходится или сильно больше кода писать, или мириться с багами.
5) Использование NoSQL, там где прекрасно справится РСУБД, очень напоминает предварительную оптимизацию, которая, как известно, зло. Причем, как ни странно, NoSQL требует больше ресурсов (много памяти и несколько серверов), по сравнению с какойнить бесплатной РСУБД.

Я знаю что есть типовые сценарии, для которых NoSQL работает лучше РСУБД. Но я бы не брался 100% утверждать на старте проекта, что именно такой сценарий будет в приложении
Да, пример с билетами вполне из реальной жизни, но я о другом: реализовывать так его никто не будет.

А как будет?

Например, подсчет статистики, аналитика, системы сообщений/комментариев

Для этого уже давно есть материализованные\индексированные представления. В SQL Server появились updateable columnstore индексы. А для больших объемов также давно есть OLAP системы.

А теперь представьте себе реализацию этой системы в синхронном хранилище.

Представил, а в чем проблема? Рекомендации ведь не будут на каждый клик пересчитываться, иначе мощностей никаких не хватит. А писать клики в permanent inconsistent (eventual consistent) базу или в обычную с ACID гарантиями — разницы нет, а можно вообще сохранять на локальном диске веб-сервера, а потом прогонять через механизм расчета рекомендаций.

По сути нет ни одного сценария, где eventual consistent было бы выгоднее, чем strong consistent.

В целом согласен, хотя пример с бронированием билетов утрирован.

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

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

Для чтения мастер не нужен, а для записи нужен. У multimaster в общем случае возникают проблемы с consistency, когда параллельно две транзакции в разные мастеры пишут по одним и тем же ключам.

Тогда ведь и консистентность можно считать функцией от времени, которое прошло с момента добавления данных, нужных для выборки?

Считать можно вообще что угодно. Но смысла в этом обычно нет. Strong consistency это гарантия для приложения, eventual consistency это просто слова, которые ничего не дают приложению.

На примере той же продажи билетов. Если есть eventual consistency в 10 секунд, то как это поможет не продать более одного билета на одно место?

Если eventual consistency имеет такое маленькое значение, что в реальности наблюдатель никогда не увидит кластер в неконсистентном состоянии, то в чем разница со strong consistency? Да и стоить это будет одинаково.
[Удалено] Промахнулся
Partition tolerance это тоже оксюморон ;)
Банальная ситуация — сервис по продаже билетов в кино, на одну ноду приходит команда, которая бронирует билет и тут рвется связь. Вторая нода не знает что билет забронирован, тут приложение обращается ко второй ноде и пытается забронировать тот же билет.
Тут два варианта:
1) если билет таки удастся забронировать, то после восстановления связи будет две брони на одно место.
2) не писать пока нет связи с мастером, то ест сервис в одной из частей не доступен.

Даже если система ждет ответа е от всех нод, а от подмножества, то сеть может поделиться по границе подмножества. Короче честный partition tolerance без strong consistency сделать нельзя.

Это приводит к неутешительному выводу: для честного partition tolerance нужно иметь мастер-ноду, куда будет приходить вся запись, а также синхронный коммит, чтобы в случае падения мастера можно было переключиться на другу ноду (сделать её мастером). Понятно что падение мастера синхронно отследить не удастся, поэтому любая реальная система может быть только CP.
Кстати если почитать обсуждения cap теоремы, то для устранения этого «бага» понятие consistency поменяли, и оно больше похоже на atomicity в ACID.

Но не все так плохо. Если consistency и partition tolerance это бинарные понятия. Они или есть или нет. То availability это непрерывная величина между 0 и 1, причем существует она не сама по себе, а еще и зависит от инфраструктуры. Предположим что мы смогли инфраструктурно добиться доступности серверов бд в 99,99% и время на продвижение нового мастера менее 1 секунды. Это значит что приложение может просто повторять попытки записи в базу в течение и для пользователя система будет доступна на те же 99,99%.причем это легко делается на sql server.
eventually consistent это оксюморон.
1) Если частота записей больше, чем время, которое необходимо до получения консистентного состояния в кластере, то eventually consistent превращается в permanently inconsistent.
2) eventually consistent не дает абсолютно никаких гарантий, в отличие от strong consistency.
нет принципиальных ограничений сделать acid даже в nosql на одной машине. Но это сильно бьёт по скорости записи, что использовать nosql становится невыгодно. Даже можно сделать «зеркалирование» с синхронным коммитом, но это еще медленнее.
Сложность разная бывает:
1) Сложность написания. То есть количество времени для получения конкретного результата. Самый незначимый вид сложности, хотя дающий максимальный эмоциональный эффект.
2) Сложность чтения. То есть сколько времени нужно потратить чтобы восстановить мысль автора по коду. Так как код читается гораздо больше чем пишется, то это самый значимый вид сложности.
3) Сложность понимания как оно работает. То есть сколько времени нужно потратить до того чтобы понять как код работает. Эта сложность вызывает больше всего холиваров.

Так вот язык C и Java имеют среднюю сложность написания и понимания и низкую сложность чтения.
А большинство ФЯ снижают сложность написания и повышают сложность понимания и чтения.
Покажи схему и скажи что надо получить. Коллективный разум позволит родить запрос.
Зачастую производительность достигается варьированием нагрузки.

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

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

Только в двух случаях такое «варьирование нагрузки» помогает:
1) Логика невыразима в терминах TSQL, например рекурсии или moving average
2) База очень маленькая (до 1ГБ), тогда выгоднее всосать все в память приложения и использовать навигационный доступ между объектами.
По моим замерам там прирост на десятые доли микросекунд на объект. Этож сколько надо материализовать чтобы тормоза были заметны? Если в секунду материализуешь более миллиона объектов, то скорее всего что-то не так делаешь и проблема вовсе не в EF или другом ORM.
Этож старье. Там ef еще первой версии.
Никаких замеров в инернетах я не нашел. У вас есть? Поделитесь.
А где замеры, статистика, графики?
Какой sql получился из двух запросов?
А нельзя было написать функцию (inline TVF) в sql и дергать её из контекста с материализацией?
О чем статья вообще?
Пример нашелся?
Проблема есть не только у меня, о чем свидетельствует SO.

не читайте до обеда советских газет

Пример будет интересен, только пожалуйста без экзотики.
Я уверен, что её либо не запили вообще, либо это сделали не полностью.

:) Откуда такая уверенность?

Это легко проверить, ASP.NET для создания и выполнения Task'ок использует AspNetSynchronizationContext, который в свою очередь использует ThreadPool для управления потоками.
Можно попробовать создать много запросов к приложению, и ждать когда продолжение(continuation) веб-запроса будет выполняться не потоком инициатором запроса. И вот тогда будет проблема(я с ней столкнулся). Опять-таки это проблема EF, а не проблема ASP.NET, так как EF не потокобезопасен.

Запустил LoadTest, 500 запросов в секунду, ошибок нет. Так что нет проблем у EF и ASP.NET (в том числе MVC и WebAPI), по крайней мере тех, о которых вы думаете.
Поток один, как с отладчиком, так и без. При этом в callstack видно что это честное асинхронное продолжение
Ты думаешь что для такого кейса не запилили бы стабильную реализацию?
Только что написал пример:
        public async Task<ActionResult> Index()
        {

            var dbContext = new TestEntites();
            var something = await dbContext.Foo.FirstOrDefaultAsync(e => e.Id == 1);
            var morething = await dbContext.Foo.FirstOrDefaultAsync(e => e.Id == 2);

            return View();
        }

Естественно работает без ошибок.

Information

Rating
269-th
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity

Specialization

Software Architect, Delivery Manager
Lead
C#
.NET Core
Entity Framework
ASP.Net
Database
High-loaded systems
Designing application architecture
Git
PostgreSQL
Docker