LINUX.ORG.RU

Функциональщина на C++

 , ,


0

5

По мотивам: Си с классами

бери с++20 с концепциями, корутинами и ренжами. игнорируй всё из с++17, сфинае, не пиши упоротые шаблоны, вообще шаблоны старайся не писать, и всё будет ок.
концепции уже вроде работают, ренжи тоже есть, корутины ещё не подъехали, но в будущем пригодятся, генераторы там всякие, всё такое. ещё будет проще потом перелезть на экзекюторы и т.д. потом ещё модули затащишь.

Как эффективно учиться? (комментарий)

Я недавно всерьез собрался найти где-то гайды по крестам, которых был бы описан какой-то цельный подход к писанию на новых крестах с полным игнорированием неудачного наследования старых крестов, но с удивлением обнаружил, что таких нет или почти нет — можно найти отдельные подсказки, которые придется долго собирать воедино, а самому мне это делать тяжеловато, потому что кресты я только начинаю осваивать

Конкретно мне интересен функционально-процедурный подход к написанию кода на крестах, что-то похожее на Rust, только без абсурдной помешанности на безопасности памяти, так сказать «си с плюшками», но совсем НЕ «си с классами», как было в упомянутом треде. Для примера: Qt и UE — это примеры плохой архитектуры в данном контексте. Например, fstream — это плохая реализация файловых операций, поскольку скатывается в классы и исключения, в ней даже нельзя без исключений получить конкретную ошибку файловых операций.

Итак: какие есть конкретные хорошо проработанные приемы и библиотеки для писания на крестах в функционально-процедурном стиле?

★★★

Ответ на: комментарий от byko3y

Сущность никто не использует какое-то время и ссылок на нее нет — всё, эту сущность можно убивать.

Ну так определи, что она не используется.

Ты про механизмы переиспользования памяти epoch-based/quiescent-state?

Нет. Давай я просто опишу задачу, чтобы было понятнее.

Есть CoW persistent tree. Если мы хотим удалять старые версии, нам нужен или трассирующий сборщик мусора, или ARC с атомарными счетчиками (если мы хотим иметь несколько писателей, которые будут удалять память) для каждого узла. Счетчик содержит количество ссылок на узел.

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

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

Можно, наверное, предложить и другие схемы сборки мусора. Я тут не спец, мне эта тема не особо интересна. Мне Scale-Up интересен.

aist1 ★★ ()
Ответ на: комментарий от aist1

Не, про CAP-теорему тут не стоит. Её еще понимать надо правильно

Я уже пояснял про целостность. Целостность ACID — это целостность тухлых данных для аналитических запросов. Целостность CAP — это целостность актуальных данных, которая нужна для операций обновления с проверкой инвариантов, которую нельзя выполнить без доступа к этим актуальным данным. А ведь именно про эту вторую целостность мы и говорим... Если я правильно понял, конечно.

Так вот, мы стремимся к тому, чтобы вероятность сбоя софтового уровня из-за параметров потока запросов была существенно ниже вероятности сбоя системного/аппаратного уровня. И в этом, вероятностном смысле, мы можем иметь «достаточно сильную» консистентность и опираться на предоставляемые ею гарантии при разработки приложений

Кстати, да, ты интересный вопрос поднял. Даже один узел может быть сбойным, но при этом его сбойность незарегистрирована и он портит ответы на запросы. Потому ответы должны перепроверяться хотя бы еще одним узлом. Чего, насколько мне известно, не делает подавляющее большинство распределенных систем, поскольку эту жутко дорого.

Да, ECC в памяти позволяет снизить риск возникновения ошибки до практического нуля, но оператива, мягко говоря, является не единственным звеном. RAID-контроллер может зарегистрировать ошибку чтения, может зарегистрировать отличие томов при запланированной сверке, но он не сможет ничего сделать, если некорректные данные софт съел как корректные. Особенно если сам же этот софт эти некорректные данные туда и записал.

Маленькие кластеры из 3-5 машин многоядерных машин (или стоек, не важно) будут достаточно надежны, чтобы обеспечить весьма высокую производительность в рамках сильной консистентности

Два узла в постгресе в режиме синхронной реплики. Всё, это потолок. По мере роста числа машин производительность очень сильно падает и целостностью приходится жертвовать — так делает Galera, кооторая притворяется синхронным мультимастером, хотя на самом деле не является им, а только делает самые важные проверки по индексам и асинхронно реплицирует остальные данные, таким образом оставаясь без «сильной» целостности данных.

Важно то, что сильная консистентность упрощает дизайн софта и снижает стоимость его сопровождения

Важно то, что простую систему проще разрабатывать и сопровождать. Всё просто: простую распределенную систему просто делать и сопровождать — сложную распределенную систему со сложными алгоритмами выбора координатора сложно делать и сопровождать. Если же твоя распределенная система имеет единственного координатора, при падении которого отваливается вся система, то доступности у тебя не будет, но система будет сильно проще. Если с целью гарантий инвариантов (порядок, уникальность, сумма) ты делаешь требующие инвариантов записи строго последовательно на координаторе, то система оказывается простой и дешевой, но с низкой производительность и доступностью (по крайней мер при записи с проверкой инвариантов). И не обязательно при этом именно иметь строгую целостность, и не обязательно задействовать CRDT.

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

Если ты так уверен в расслабленных моделях консистентности, то CRDT-флаг тебе в руки :) Я же — пас. Если меня явно не попросят и не поклянутся мамой, что знают, на что идут, я этим заниматься не хочу

Так и я не буду. Готового решения-то у меня нет, и не факт что оно будет. Я предпочту полететь на боинге 737, чем на еще не выпущенном новом опытном самолете.

Гораздо проще ослабить консистентность изначально сильно консистентного хранилища, чем костылять усиление консистентности над EC-хранилищем. Хотя последние и быстрее

Даже монга на одном узле использует довольно хорошую целостность данных за счет движка WiredTiger. Просто, не нужно впадать в крайности вроде «только ACID» или «только Eventual Consistency».

byko3y ★★★ ()
Ответ на: комментарий от aist1

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

Я могу придумать сценарий, когда она не нужна. Собственно, я его уже описал в предыдущем сообщении: сборщик мусора периодически получает сообщения от распределенных агентов об их активности и о состоянии их локальных счетчиков/локальных ссылок/изменениях числа ссылок; ему не нужна эта информация прямо здесь и сейчас в самом актуальном виде, ему достаточно знать, что когда-то в прошлом никто не использовал некую версию и не мог получить к ней доступ в ближайшее время. Да, версии удалятся позже, возможно даже сильно позже, тем позже, чем слабее требования по предоставлению сообщений от распределенных агентов — но зато необходимость в строго целостности отпадает.

x86 на самом деле занимается примерно тем же, только «сообщения» от распределенных агентов приходят очень быстро, порядка 30 циклов процессора для многоядерного однопроцессора, порядка сотен циклов для многопроцессорной системы — то есть, как бы «мгновенно», сравнимо со скоростью доступа к некэшированной памяти, и потому их можно синхронно подождать.

А в Firebird вообще сборка мусора по умолчанию отложена до следующего чтения кортежа — то есть, она может выполнится даже через год после того, как пропали все ссылки на версию кортежа. Хз, сколько это будет в циклах процессора.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

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

Если мы говорим, о CoW-tree, то удаляем мы не версию, а узел дерева, который может косвенно принадлежать нескольким версиям. Сходу я не могу провалидировать твою схему. Можно потом будет попробовать промоделировать этот сценарий в Мемории вживую, я, наверное, могу сделать специальный Store для этого (тут могут быть легальные ограничения для меня, а не технические).

Насчет CRDT, ты можешь попробовать это все самому делать. Есть хранилища с различными свойствами, можно лепить CRDT-шки над ними. Riak, вроде как, прямо на это и заточен даже. Т.е. можно делать операционную БД «самому», и, более того, те, кто идет по модной сейчас дорожке микросервисов, по факту будут делать свою операционную СУБД. Или это будут только микросервисы без состояния, то есть «не настоящие». Можно, конечно, отбрехаться, что облачные архитектуры всячески навязывают выделенную managed DB, и на долю девелоперов остаются только сервисы без состояния.

Но тот, кто вступит на эту дорогу, делать свою БД, узнает, что самое сложное тут — это вовсе не распределенность, а поддерживаемые всем стеком типы данных.

aist1 ★★ ()
Ответ на: комментарий от byko3y

Просто, не нужно впадать в крайности вроде «только ACID» или «только Eventual Consistency».

Можно так? «EC только при условии, что вы точно знаете, что вам нужно именно это и осознаете, во что это вам обойдется».

Насчет кластера из 3-5 узлов (или стоек), я не про Pg говорил. Этот еще лет 10 будет пытаться лечить ограничения своей архитектуры. Я говорил про то, что само такое железо, благодаря своему профилю отказоустойчивости, может в принципе обеспечить высокую абсолютную производительность. Задача софта — утилизировать её. Pg в этом смысле — не лучший вариант. Хотя и хороший во всех остальных смыслах.

Дело в том, что имея Меморию на руках, я технически могу это железо утилизировать. Потому что Мемория дизайнится для scale-up-сценариев: я там контролирую весь путь от io_uring/SPDK-exposed устройства и до обработки данных на акселераторах. Там по умолчанию SWMR-сериализованные транзакции с MVCC, но можно делать высокоуровневый шардинг, чтобы ослаблять консистентность там, где надо, и на столько, на сколько надо.

SWMR (single writer, multiple readers), кстати, очень классная схема. Вообще гениальная, если в сочетании с ПСД. Она позволяет атомарно сбрасывать состояние RAM на NVmem так, что новые данные никогда не перезатирают старые, и не требует сборки мусора (но все равно требует не-атомарных счетчиков).

Что касается софта в такой модели. Я буду на основе ПСД делать хранилище для системы сборки в своем форке Clang. Это будет BaaS для IDE-шек, который возьмет на себя весь цикл: редактирование, сборка, аналитика и т.д. Компилятор там умеет в метафункции и через них будет тесно интегрирован с системой сборки.

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 1)
Ответ на: комментарий от LamerOk

виртуальные адресные пространства, сегментные регистры - это костыли для совместимости

процессор 86 унаследовал часть команд процессора 8080, когда программировал на ассемблере меня удивило что большая часть кода команд 86 и z80 совпадало хотя ассемблер-мемоники команд разные (z80 также произошёл от 8080)

процессор 8080 мог адресовать только 64кб оперативы чтобы программы 8080 исполнялись на 86 добавили сегментные регистры (так ли это я информацией не владею, это моё мнение, в котором я абсолютно уверен)

Это всё равно что человек делал одноэтажные домики, а тут внезапно попросили сделать многоэтажку и он ставит один дом на другой склеивая их изолентой.

Самое удивительное при переходе с 86 на 386 intel их сохранил и расширил

слава богу что развитием 386 на 64 рулила AMD и в 64битном режиме от них избавились, был бы это intel и сегментные регистры появились бы и там

прелесть Си что он является универсальным языком для всех аппаратных платформ

надеюсь что в Си появятся абстракции для не синхронной быстрой памяти

s-warus ()
Ответ на: комментарий от byko3y

несколько программ могут изменить один файл с непредсказуемыми последствиями — но никто об этом не парится

Вообще-то, об этом парятся разработчики операционных систем, позволяющие явно задать режим работы с файлом, что и делают все приличные программы.

Единственное что — это ОС проверяет конфликты имен файлов и не дает удалять непустые каталоги.

Слава богу, нет. Нормальные ОС поддерживают полностью атомарный режим работы с содержимым файлов.

LamerOk ★★★★★ ()
Последнее исправление: LamerOk (всего исправлений: 1)
Ответ на: комментарий от aist1

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

Чего ты прилип к CRDT? Смотри: для большей части данных строгая целостность не нужна, вроде комментария к заказу, сканов документов, фамилии заказчика — мы можем немного подождать их; для меньше части данных, вроде первичного ключа или уникального значения или резервирования товара на складе, мы можем применять небольшую БД со строгой целостностью. Всё, очень просто, очень тупо, не нужно даже таких заморочек и закоса под распределенность, как в ActorDB.

Необходимость более строго целостности данных, чем вообще-то нужно для задачи, возникает в реляционных СУБД потому, что запись в одной таблице должна ссылаться на ключ записи в другой таблице, и все данные утыканы с ног до головы этими ключами, за целостностью которых нужно следить. Всё становится просто в тот момент, когда ты понимаешь, что большая часть этих этих гарантий никому не нужны, кроме самой СУБД, проблемы которой мы вынуждены решать, а не наоборот, СУБД решает наши проблемы.

В чем было решающее преимущество MongoDB (название NoSQL базы сейчас не важно)? Она просто кидала цельный документ как единое значение, без необходимости поддерживать какие-то связи между этими документами. Далее изменение структуры данных не требовало вообще никаких операций над хранилищем — менялось только представление. Сравни это с подходом РСУБД, которые при смене структуры данных будут перекраивать все таблицы под новые условия.

Но тот, кто вступит на эту дорогу, делать свою БД, узнает, что самое сложное тут — это вовсе не распределенность, а поддерживаемые всем стеком типы данных

Да. Я уже давно оббил себе всё лицо этими граблями. БД начинались со встроенных баз, и закончатся ими же. РСУБД были временным помешательством, которому пора на помойку. Почему-то создатели СУБД часто считают, что пользователь может хранить в БД только данные плана «одно число» или «строка длиной 10 символов». Так действительно было когда-то очень много лет назад, когда компьютеры толком мало что могли полезного делать.

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

Мало кто понимает, что Clickhouse — это самая обыкновенная СУБД, которая просто хранит данные в том виде, в котором они нужны, а не в том виде, в котором захотелось конкретной РСУБД. Упрощенный вариант такой СУБД, без репликации, без снимков, без поддержки SQL можно написать менее чем за неделю. Современное железо свободно обрабатывает сотни миллионов запросов к ассоциативному массиву в секунду, но какой-нибудь MySQL в тепличных условиях отрабатывает порядка сотни тысяч, или под миллион если дергать InnoDB API напрямую. То есть, три порядка потери производительности по сравнению с теорией даже на CPU, а если вспомнить про GPGPU, у которого производительность свыше миллиарда доступов к ключам в секунду?

byko3y ★★★ ()
Ответ на: комментарий от aist1

Можно так? «EC только при условии, что вы точно знаете, что вам нужно именно это и осознаете, во что это вам обойдется»

Надеюсь, пояснил: Функциональщина на C++ (комментарий)

Насчет кластера из 3-5 узлов (или стоек), я не про Pg говорил. Этот еще лет 10 будет пытаться лечить ограничения своей архитектуры. Я говорил про то, что само такое железо, благодаря своему профилю отказоустойчивости, может в принципе обеспечить высокую абсолютную производительность. Задача софта — утилизировать её. Pg в этом смысле — не лучший вариант

Если говорить про асинхронную репликацию, то постгрес вполне справляется с задачей. Он может выдать и 5, и 10, и 20 узлов, на которых будут параллельно выполняться запросы.

byko3y ★★★ ()
Ответ на: комментарий от LamerOk

Вообще-то, об этом парятся разработчики операционных систем, позволяющие явно задать режим работы с файлом, что и делают все приличные программы
Нормальные ОС поддерживают полностью атомарный режим работы с содержимым файлов

В тех же никсах это уже надстройки-дополнения-расширения. Так-то я могу «поддерживать полностью атомарный режим работы» через блокировку на удаленном сервере-координаторе, но это не значит, что у меня изначально файлы умеют в координацию. Там всё упирается в производительность, которая может оказаться очень низкая при наивном применении flock, и тем более при использовании глобального мьютекса или файла глобальной блокировки.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

Чего ты прилип к CRDT?

Потому что нам нужно строить абстракции над хранилищем. Вот, скажем, хранилище дает тебе K->V. А твоему приложению нужен multimap, или счетчик, или очередь... И что, ты на каждый тип данных будешь подбирать своё хранилище? Думаю, не надо тебя убеждать, что выбор очень быстро кончится.

CRDT — это просто способ создавать новые типы данных над EC-хранилищем методом структурной композиции. Можно и без CRDT, но будет грустно.

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

Смотри. Между строгой консистентностью и EC есть еще каузальная консистентность. И вот тем приложениям, которые ты упоминаешь, нужна как минимум каузальная консистентность. А с нею далеко не всё так просто, хотя общая канва того, что ты говоришь выше и ниже к ней и ведет. Каузальная консистентность неплохо реализуется при условии, что каждый участник может хранить всю БД у себя локально. И это может быть даже встраиваемая СУБД, если мы обеспечили отказоустойчивость.

Что касается OLTP, то там БД, как правило, небольшие. Поскольку хранят факты об операциях. И даже очень большие операционные БД можно поднять на одной машине.

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

Современное железо свободно обрабатывает сотни миллионов запросов к ассоциативному массиву в секунду

Если массив динамический и конкуррентно обновляемый, то сильно меньше))

Если массив еще и на диске лежит, то еще сильно меньше.

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

Что касается того же SQLite и возможности отключать fsync на коммит, то БД должна поддерживать этот режим ослабления дурабельности напрямую, на уровне структур данных. Т.е. должны быть явные consistency points, как внутри файловых систем. Иначе даже при просто краше приложения можно потерять не просто последние насколько не-fsync-нутых транзакций, а вообще всю БД.

Я не смотрел конкретно в SQLite, но не уверен, что он умеет в consistency points, отвязанные от коммитов. Надо проверять))

LMDB корраптнется, если fsync отключить. Мемория (SWMRStore) откатит всё до последнего consistency point.

Короче, кроме консистентности есть еще дурабельность. И тут всё упрется в то, как быстро мы можем атомарно сбрасывать состояние из памяти на NVmem.

aist1 ★★ ()
Ответ на: комментарий от byko3y

Вдогонку, про каузальную консистентность (СС).

Проблема со всеми уровнями консистентности ниже snapshot в том, что потребитель информации не может определить, на сколько она корректна в момент чтения. Тут можно придумать эвристику типа «читаем в цикле несколько раз в экспонециальным увеличением таймаута, если значения не равны», но это всего лишь эвристика.

Можно пробовать эскалировать принятие решения о корректности данных на пользователя и полагаться на его гибкость и достаточность контекста для принятия надежного решения, но это тоже... такое... В одном из моих прошлых проектов пользователи сильно жаловались, когда видели некорректные результаты на дашборде, возникавшие из-за того, что над Druid публиковал сегменты одного датасета асинхронно по мере их фактического появления. И пришлось переделать так, чтобы он эти все сегменты публиковал одномоментно (типа, read committed).

Фактически, применимость EC/СС определяется тем, возможно ли делегирование клиенту принятия решения о корректности данных. Кодить такие вещи ручными эвристиками? Я — пас. Переносить это на пользователей? Тут нужен тщательный анализ на этапе дизайна приложения. Во многих случаях — да, но что это будет стоить? Овербукнутый полет может дорого обойтись в плане репутации. Овербукнутый item на Амазоне — ну зарефандили и всё. Временная неконсистентность данных на дашбордах на NYSE — и опа, потери на миллиарды фантиков из-за паники. Кого-то точно наденут на швабру по самую перекладину.

Что касается CC, я сейчас не уверен, но вроде как она делается на асинхронной репликации, т.е. её можно поднять на любой СУБД с поддержкой асинхронного мультимастера, плюс, возможно, какие-то расширения. Единственное, что она годится только для относительно небольших операционных БД, так как каждый участник (датацентр) должен иметь полную копию данных.

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 1)
Ответ на: комментарий от aist1

Вот, скажем, хранилище дает тебе K->V. А твоему приложению нужен multimap, или счетчик, или очередь...
CRDT — это просто способ создавать новые типы данных над EC-хранилищем методом структурной композиции. Можно и без CRDT, но будет грустно

Мне кажется, что говоря про CRDT ты имеешь в виду конкретные алгоритмы конвергентных CRDT, а точнее сам механизм слияния/синхронизации изменений в нескольких узлах, аля git или более простой rsync. Атомарный глобальный счетчик на CRDT не делается вообще никак, потому что он не будет CRDT — вот это мне в твоих сообщениях и непонятно.

Каузальная консистентность неплохо реализуется при условии, что каждый участник может хранить всю БД у себя локально

Для обеспечения причинной целостности достаточно хранить у себя ту часть данных, с которыми будут устанавливаться связи. То есть, если оператор оформляет заказ, то ему нужны только сведения о конкретном клиенте и сведения о конкретном товаре (остатке/доступности) — всё остальное ему глубоко безразлично. Даже ему сведения о клиенте безразличны, а волнуют только вопросы резервирования. И даже они не будут волновать, если резервирование происходит по факту, то есть, продавец приходит и забирает товар — произошло «резервирование», и тогда продавец может зарегистрировать заказ на туалетной бумаге и положить ее в папку с остальными заказами. Примерно так работали и работают многие люди, безо всяких CRDT и целостности БД.

Если же мы делаем онлайн резервирование, то нам достаточно реализовать единственный сервер, который будет вести учет «товар прибыл, товар резервирован, товар продан». Причем, ему не нужна глобальная целостность — достаточно ее реализовать на уровне единицы товара: «единица продана», «единица резервирована», «единица доступна». Это 2 бита информации — рядом с ним нужно будет еще разместить уникальный локальный идентификатор и идентификатор продавца. Такой сервер даже для крупной торговой сети с сотней тысяч заказов в день можно будет реализовать на питоне, пишущем в текстовой файлик. Бесплатно дарю вам эту идею, можете идти делать свою ERP и захватывать мир.

Однако, если говорить именно про математическое «большинство приложений», то там будет нужна строгая консистентность

Что это за «большинство приложений» такое?

Современное железо свободно обрабатывает сотни миллионов запросов к ассоциативному массиву в секунду

Если массив динамический и конкуррентно обновляемый, то сильно меньше

Я сейчас уже не вспомню точно, на сколько я набенчил свои ассоциативные массивы в высокококонкурентном сценарии. Да, что-то сравнимое с сотнями тысяч мускуля, однако, в упомянутом случае мускуля речь не шла про конфликты обновления данных — в таких сценариях мускуль дай бог 10-20 тысяч запросов в секунду выдаст.

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

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

Что касается того же SQLite и возможности отключать fsync на коммит, то БД должна поддерживать этот режим ослабления дурабельности напрямую, на уровне структур данных. Т.е. должны быть явные consistency points, как внутри файловых систем

Кстати, в SQLite ничего подобного не завезли? Меня вот бесит, что либо fsync на каждый чих, либо вообще никаких гарантий.

byko3y ★★★ ()
Ответ на: комментарий от aist1

Проблема со всеми уровнями консистентности ниже snapshot в том, что потребитель информации не может определить, на сколько она корректна в момент чтения. Тут можно придумать эвристику типа «читаем в цикле несколько раз в экспонециальным увеличением таймаута, если значения не равны», но это всего лишь эвристика

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

Я даже больше скажу: уровень целостности данных «снимок» тоже не гарантирует, что потребитель получит корректную информацию. Потому что товар уже продан, а в снимке он еще на складе. А при акценте на причинную целостность, то есть, на целостность тесно связанных сущностей, клиент получает возможность получить актуальные сведения по интересующим товарам вместо бесполезного снимка всей БД в прошлом.

А я вот, например, до сих пор не знаю, как в РСУБД решить проблему проверки инвариантов без применения максимального уровня целостности (блокировки таблиц целиком), если эта проверка не встроенна в эту СУБД, вроде проверок уникальности индекса или внешних ключей. Например, у меня есть нечеткое сравнение наименований и мне нужно убедиться, что похожего товара нет в базе. Индексы здесь бесполезны, потому что ни в одну СУБД не встроена нечеткая проверка уникальности. Иерархичная же организация подобного индекса позволяет производить блокировку отдельных ветвей.

В такой связанно-иерархической организации получается, что даже на распределенной системе невозможно овербукнуть полет, потому что существует координатор, который, грубо говоря, обслуживает запросы по всем самолетам вылетающим из одного аэропорта — и не нужно никакой глобальной целостности и снимков. Я подозреваю, что NYSE примерно так и работает. Эта мания хранить всё в центральном хранилище, подогреваемая SAP и Oracle, лишь приводит к неоправданно завышенным требованиям к системе, и по итогу к vendor-lock-у на те немногие программные и аппаратные решения, которые способны этим требования удовлетворить. Вроде SAP HANA на машине с 8 Тб (терабайт) оперативы — это вполне реально существующие современные сервера для крупного бизнеса.

Что касается CC, я сейчас не уверен, но вроде как она делается на асинхронной репликации, т.е. её можно поднять на любой СУБД с поддержкой асинхронного мультимастера, плюс, возможно, какие-то расширения. Единственное, что она годится только для относительно небольших операционных БД, так как каждый участник (датацентр) должен иметь полную копию данных

Мне кажется, что ты описываешь здесь какую-то очень конкретную систему, подразумевая именно ее одну под целым набором методов разработки БД. Так-то причинная целостность может быть реализована и синхронно, и асинхронно, и без мастера вообще (то есть, систему нельзя ужать до одного узла, работоспособность ее обеспечивается только комбинацией этих узлов) — и тогда ни у кого нет полной копии данных. А зачем она нужна?

byko3y ★★★ ()
Последнее исправление: byko3y (всего исправлений: 3)
Ответ на: комментарий от fsb4000

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

EugeneBas ★★ ()
Ответ на: комментарий от byko3y

Атомарный глобальный счетчик на CRDT не делается вообще никак, потому что он не будет CRDT — вот это мне в твоих сообщениях и непонятно.

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

1. У нас есть базовая модель памяти: RAM, DAM, BAM, K/V и т.д. и модели консистентности для этой памяти, и мы от всего этого скачем дальше.

2. У нас есть приложения, и там есть алгоритмы и структуры данных. И нам нужно построить структуры данных уровня приложения, на основе примитивов, который дает нам базовая модель памяти.

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

4. Тем не менее, «жить можно», нужно просто хорошо понимать, как на различных приложениях скажется ослабленная консистентность. Иногда вполне вариант — это эскалировать решение о мементе корректности данных на пользователя (чтобы он условную «капу жал»). Иногда это — не вариант, так как пользователю физически не хватит времени или контекста на принятие правильного решения. Всё это должно быть определено на этапе дизайна, и только тогда можно завязываться на «асинхронную репликацию».

5. Раскрытие (4) на практике превращается в то, что мы начинаем разбивать приложение на «домены консистентности», где нужна сильная консистентность, а где можно смело её ослабить. И покрываем эти домены хранилищами с соотвествующими гарантиями. Clickhouse, на который ты ссылаешься иногда, хранит метаданные о процессе репликации в сильно-консистентном ZooKeeper.

6. Делая (5) мы стремимся минимизировать состояние, которому, кровь из носу, нужна сильная консистентность. Вот, например, атомарным счетчикам нужна exactly-once in-order. Если счетчики идемпотентные, то можно at-least-once in-order.

7. Меня лично, в первую очередь, интересует как раз этот сегмент — scale-up strongly consistent persistent/durable generic data structures. Ослаблять сильную консистентность технически проще (асинхронная репликация), чем усиливать слабую.

8. Для многих практических задач, действительно, достаточно СС, но надо для каждой конкретной задачи нужно смотреть отдельно, если это не известно заранее. Методом аналогии я бы не действовал. Одно маленькое, с виду незначительное, требование может всё «поломать».

Т.е. когда ты дизайнишь систему сверху вниз в плане иерархии консистентности, и имеешь на руках мультимодельное сильно-консистентное высокопроизводительное (в рамках физических возможностей) хранилище, то ты всегда можешь «откатиться наверх» (потеряв в скорости, но сохранив корректность). А вот усилить изначально слабое хранилище будет гораздо сложнее. Что-то на уровне «написать свою собственную БД». С чем и сталкиваются энтузиасты микросервисов с состоянием.

Что это за «большинство приложений» такое?

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

Даже параллелить не нужно, достаточно просто писать последовательно.

И читать. А если надо произвольно?)

Кстати, в SQLite ничего подобного не завезли?

Насчет SQLite мне нужно даблчекать. Я посмотрел примерно, и не убедился, что оно всегда будет работать, предполагая надежность нижележащей ФС. Теоретически, там WAL, и если есть корректный чекпоинт и корректный WAL, то можно восстановить всё, что есть в WAL. Я вот не уверен насчет корректности этих структур данных после любых сбоев при выключенном fsync. Я даблчекну потом. Разработчикам опенсорсных БД «на слово» я не верю.

Меня вот бесит, что либо fsync на каждый чих, либо вообще никаких гарантий.

Если ты скипаешь VFS и напрямую работаешь с блочным устройством, то можно попробовать отключить системный fsync вообще и самому сбарсывать свой кэш на устройство. Но для консумерских SSD нужен будет UPS. Серверное железо батарейку уже так или иначе имеет.

Если работать через VFS и блочный кэш, что что там будет без fsync при даже просто краше процесса — хз.

aist1 ★★ ()
Ответ на: комментарий от byko3y

Нужно хранить связанные сущности связанными, а между независимыми сущностями целостность не важна.

Транзитивные зависимости. Если они есть, то с шардингом будут проблемы.

А я вот, например, до сих пор не знаю, как в РСУБД решить проблему проверки инвариантов без применения максимального уровня целостности (блокировки таблиц целиком)

Без snapshot consistency — никак.

Я даже больше скажу: уровень целостности данных «снимок» тоже не гарантирует, что потребитель получит корректную информацию. Потому что товар уже продан, а в снимке он еще на складе.

Это во время коммита обнаружится, так как будет write conflict. CC в SC достигается за счет select for update.

aist1 ★★ ()
Ответ на: комментарий от aist1

Меня лично, в первую очередь, интересует как раз этот сегмент — scale-up strongly consistent persistent/durable generic data structures. Ослаблять сильную консистентность технически проще (асинхронная репликация), чем усиливать слабую

Это «проще» возникает из-за того, что из сильносогласованной системы нужно «убирать», а в слабосогласованную — добавлять сущности. Вроде как убирать проще, чем добавлять, да?

Как упоминалось, MySQL/PostgreSQL/SQLite с режиме асинхронной записи при отказе компьютера полностью теряют БД на этом узле. Отсюда, на самом деле, возникла мода на NewSQL RAM-only СУБД, потому что один хрен содержимое диска при отказе уже не понадобится. А тогда запись на диск в MySQL/PostgreSQL/SQLite оказывается бесполезной обузой, и вообще добрая половина их фич не нужна. Они же все проектировались с упором на дисковые операции и имеют кучу бесполезных и ресурсоемких фич, которые изначально были нужны только для оптимизации работы с диском.

Потому первая важная цена этого «проще» — огромная потеря производительности. Добавить дополнительную сущность в быструю слабосогласованную систему оказывается намного эффективнее по использованию ресурсов, чем убрать фичи из сильносогласованной. Речь идет не про «разы», а про «порядки».

Как я написал еще несколько сообщений назад — в таком случае еще «проще» делать максимальную согласованность в виде упомянутого тобой SW-MR с полной упорядоченностью операций. Короче говоря, SQLite. Убираем эти гарантии — и «проще», довольно быстро становится уже не таким простым, и при этом производительности особо не прибавляется.

А вот усилить изначально слабое хранилище будет гораздо сложнее. Что-то на уровне «написать свою собственную БД». С чем и сталкиваются энтузиасты микросервисов с состоянием

Или просто использовать уже готовую. Настоящая и очень большая проблема возникает при возникновении требования доступности и стабильности работы при отказе. Потому вторая большая и важная цена твоему «проще» — отсутствие гарантий доступности и стабильности системы с ослабленной согласованностью. Распределенная слабо согласованная система тоже ведь не обязательно безупречна в этом плане, но, как правило, слабая согласованность рано или поздно заставляет об этом думать — а думать про доступность и отказоустойчивость при необходимости в онных придется при заходе с любой стороны, но при заходе со стороны слабой согласованности эти гарантии, как правило, частично есть из коробки.

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

 — ACID;
 — согласованность снимка;
 — не теряем пользовательские данные;
 — с производительностью разберемся как-то попозже;

которое в итоге вылилось в:

 — система еле ползает и нет никаких способов это исправить не удваивая бюджет и сроки разработки;
 — при ослаблении требований согласованности получилась даже не «согласованность в конечном счёте/eventual consistency», а вообще хрен знает что, где периодически пользовательские данные растворяются в небытии, вплоть до целых исчезающих вникуда таблиц.

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

1
2
3
4
5
6
7
8

А при чем тут CRDT? Вроде отвечал же на цитату про CRDT, не?

Что это за «большинство приложений» такое?

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

Не путай программу на локалхосте в оперативной памяти с БД на удаленном хосте, связь с которым иногда теряется. Иначе уже слишком средняя температура по слишком большой больнице у тебя получается. Мы вроде обсуждали СУБД, а ты внезапно прыгнул на обычные приложения, которые, действительно, в среднем по больнице сильно склонны требовать синхронной предсказуемой памяти.

Даже параллелить не нужно, достаточно просто писать последовательно.

И читать. А если надо произвольно?

It depends. Может быть и параллельно.

byko3y ★★★ ()
Ответ на: комментарий от aist1

Нужно хранить связанные сущности связанными, а между независимыми сущностями целостность не важна

Транзитивные зависимости. Если они есть, то с шардингом будут проблемы

Конечно будет. Но редко когда они будут сильно критичными.

А я вот, например, до сих пор не знаю, как в РСУБД решить проблему проверки инвариантов без применения максимального уровня целостности (блокировки таблиц целиком)

Без snapshot consistency — никак.

Каким образом snapshot consistency поможет мне избежать одновременного добавления двух недопустимо подобных записей? Я не просто так привел этот пример — это крайний случай, в котором MVCC полностью бесполезно.

Я даже больше скажу: уровень целостности данных «снимок» тоже не гарантирует, что потребитель получит корректную информацию. Потому что товар уже продан, а в снимке он еще на складе

Это во время коммита обнаружится, так как будет write conflict. CC в SC достигается за счет select for update

Вообще-то select for update — это уже уровень serializable, а не snapshot. Он может эмулироваться и на snapshot, но это все равно serializable.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

А тогда запись на диск в MySQL/PostgreSQL/SQLite оказывается бесполезной обузой, и вообще добрая половина их фич не нужна.

Это только потому, что сейчас RAM столько, сколько раньше дисков не было. На моем настольном компе 128GB RAM и 16 ядер. Еще лет 10 назад это был очень хорошего уровня сервер (особенно по части CPU). OLTP DB, если в них не пихают чего не надо и чистят вовремя, будут небольшие. И даже 100GB — это уже для них много. Это аналитические и гибридные БД могут до петабайтов разрастаться.

И можно всё держать в RAM и параллельно писать в лог, иногда асинхронно делая снэпшоты, чтобы лог трункейтнуть.

Но если говорить про современное железо (2020+), то оно уже по скорости сопоставимо с RAM. Мой Samsung 970 Pro уверенно держит в районе 200К 4K IOPS в устоявшемся режиме QD32. Это где-то 900MB/s, и это уже дохрена. Ты пойди еще такой поток обработай. А в свою настольную тачку я могу вставить 7 таких.

Опять же, появляется NVRAM, который тоже можно добавлять в иерархию памяти. Со временем, он придет в кэши консумерских SSD-шек, так что ситуация с дюрабельной записью улучшится.

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

Как я уже выше говорил, «100-миллионные» числа пиковых RQ/s, которые можно получить на RAM и хэш-таблицах сильно упадут и из-за необходимости поддерживать конкурентные обновления, и из-за транзакционной семантики, и из-за самих структур данных. Динамические структуры данных строятся на деревьях, а там сразу скорость в разы меньше, чем у хэш-мэпа, и это как минимум. Т.е. пиковые числа — это хорошо, но что будет для конкретной задачи? Сейчас появляется новый класс вычислительно-интенсивных задач — ИИ — и там свои нюансы. Если над динамическими данными нужно гонять аналитику, то нужен как минимум SI, причем чтобы читатели не мешали писателям.

— система еле ползает и нет никаких способов это исправить не удваивая бюджет и сроки разработки;

Валидный поинт, я его полностью разделяю. Я сам с этим столкнулся, и в итоге написал себе Меморию — фреймворк для разработки движков хранения и обработки данных для современного железа (на основе эффективных реконфигурируемых персистентных структур данных).

В отличие от меня, разработчики того же Pg вынуждены писать на С, так как из-за своего механизма исключений не могут плавно перейти на С++, и вынуждены тянуть совместимость со старыми задачами. Эта клиент-серверная архитектура разрабатывалась 40+ лет назад под жесткие диски. И потом её костыляли и костыляли, и костыляли. У него есть, разумеется, своя ниша и надолго. Но к современным иерархиям памяти он не приспособлен просто на уровне архитектуры. (Я так еще понимаю, что они не хотят напарываться на патентные мины, но это уже другая история)

— при ослаблении требований согласованности получилась даже не «согласованность в конечном счёте/eventual consistency», а вообще хрен знает что, где периодически пользовательские данные растворяются в небытии, вплоть до целых исчезающих вникуда таблиц.

А я всем говорю: «Ребята, EC — это, на самом деле, очень сложно. То, что у вас тут — это не EC.» RDBMS консистентность ослаблять не умеют. Они умеют ослаблять изоляцию, и только так, как в стандарте.

Понимаешь, почему я такой распальцованный и оптимистичный? У меня под 100%-ным контролем strictly serializable реконфигурируемый мультимодельный движок с конфигурируемой приложением дурабельностью. Я могу сам в нем допрограммировать то, что надо, если надо и когда надо. Необходимая гибкость предусматривается изначально дизайном фреймворка и продвинутыми техниками С++ (метапрограммирование). Дай мне железку, и я под неё сконфигурирую data layer, оптимально её утрилизирующий.

Тогда как если ты возьмешь тот же PG, то у тебя на руках черный ящик с древней архитектурой для позапрошлого поколения железа, который хрен научишь тому, что тебе надо. Вот если бы PG «открылся бы», стал бы фреймворком, из компонентов которого можно было бы собирать свои СУБД под свои нагрузки, то это была бы другая история. Они там, хотя бы, storage смогли от процессинга абстрагировать уже?

Т.е. вот если вернуться к твоему вопросу из шапки про продвинутые техники. Вот у меня есть площадка для реализации продвинутых техник программирования на С++ для выжимания из вновь появляющихся вычислительных архитектур по-максимуму. От функциональщины там ФСД/ПСД, но не для RAM только, а для более разнообразной иерархии памяти.

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 2)
Ответ на: комментарий от byko3y

Вообще-то select for update — это уже уровень serializable, а не snapshot.

Да, тут надо пояснить. Считается, что констрейнты (C in ACID) нельзя соблюсти полностью без сериализации транзакций. Т.е. один только SI не прокатит, так как есть write skew, для частичного отстранения от которого нужен select for update.

Я не буду спорить, что S4U+SI это это еще не строгая сериализуемость. В голове где-то крутится контрпример, но не выходит наружу. Я просто не уверен, что S4U позволяет избавиться от write skew полностью.

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 1)
Ответ на: комментарий от anonymous

Ты просто не шаришь не фига. Все что рассказывает Аист объясняют в любом мало-мальски приличном вузе (очевидно, что не в СНГ) на курсе распределенных систем. Все это хорошо изучено еще, скорее всего, до твоего рождения.

anonymous ()
Ответ на: комментарий от anonymous

Ахаха! Анонимус прогуливал курсы, но не те, которые стоит прогуливать))

На самом деле тут таки сложный материал. Дело в том, что у нас в программировании сейчас есть очень сильный сдвиг в алгоритмы в ущерб структурам данных. Если мы с последними и сталкиваемся, то преимущественно в виде (операционных) баз данных, которые нам даются в виде черных ящиков: всё очень сильно упрятано за не очень (мягко говоря) удобными интерфейсами. Расширить номенклатуру структур данных или нельзя вообще, или очень сложно. Т.е. оно для нас или работает, или нет. И тогда надо как-то впихнуть потребности приложения в возможности БД. Что далеко не всегда возможно, опять же, мягко говоря.

И вот byko3y столкнулся как раз с этой проблемой: не работает. В смысле, очень медленно. И ничего тут практически не сделаешь. Если сами разработчики DBMS не могут довести свои детища до современного уровня, то нам-то как быть? А народу, который костыляет свои собственные DBMS, сейчас довольно много. Это, как минимум, все микросервисы с состоянием. А так же блокчейны. Много еще всякой гибридной аналитики. ML тоже много чего требует. Т.е. площадка огромная и, в целом, еще далеко не насыщенная. В 90-х все лепили свои ОС, в нулевых пер NoSQL, в 10-х — аналитические дата-платформы, а сейчас хорошо идут распределенные гибридные БД для ML/AI.

И вот мессадж, который я тут в этой теме толкаю, состоит в том, что железо-то современное может очень много, и его потенциал далеко еще не раскрыт. Потому что софт довольно таки ригидный и сильно не успевает за железом. Вот это я и хочу сделать, используя продвинутые техники программирования на С++ и свойства персистентных структур данных. Да, и я уже не с «пустыми руками» о таких вещах говорю.

Мессадж этот будет проще всего услышать тем, кто сталкивался с необходимостью делать свои продвинутые «нереляционные схемы» над разными хранилищами. Например, запилить большие файлы над K/V Cassandra...

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 1)
Ответ на: комментарий от aist1

Как я уже выше говорил, «100-миллионные» числа пиковых RQ/s, которые можно получить на RAM и хэш-таблицах сильно упадут и из-за необходимости поддерживать конкурентные обновления, и из-за транзакционной семантики, и из-за самих структур данных

Во-о-от, зачем тебе конкурентные обновления? Потому что твой носитель медленный, операция выполняется долго, и хотелось бы, чтобы за время этой операции могли выполняться другие операции. А если у тебя операция выполняется ураганно быстро, то исчезает проблема конфликтов параллельных операций вместе с параллельными операциями. Именно по такому сценарию работает LMDB, и именно поэтому он на своих задачах уделывает завязанный на транзакции и диск SQLite на один-два порядка, даже если SQLite работает в асинхронном режиме.

Задачу организации одновременного доступа на запись к разделяемому ресурсу нельзя эффективно решить. Зачастую, оптимизация решения этой задачи как раз и сводится к тому, чтобы исключить одновременный доступ, например, банально изолировать доступ по записям в таблицах и по таблицам в базе. По этой причине фундаментальных решений два: не иметь несколько операций изменений одного ресурса вообще, либо производить операции изменений всегда на разных сущностях, вроде CRDT.

Но если говорить про современное железо (2020+), то оно уже по скорости сопоставимо с RAM. Мой Samsung 970 Pro уверенно держит в районе 200К 4K IOPS в устоявшемся режиме QD32. Это где-то 900MB/s, и это уже дохрена. Ты пойди еще такой поток обработай. А в свою настольную тачку я могу вставить 7 таких

Однако, реализовывать строгую целостность на такой памяти тяжело, потому что даже этот Samsung 970 Pro синхронно может обработать от силы 10 тысяч операций в секунду. То есть, примерно с такой задержкой можно делать операцию «атомарно прочитать и обновить». Делаешь асинхронный доступ — теряешь согласованность данных.

А я всем говорю: «Ребята, EC — это, на самом деле, очень сложно. То, что у вас тут — это не EC.» RDBMS консистентность ослаблять не умеют. Они умеют ослаблять изоляцию, и только так, как в стандарте

Так что ж получается, идти по пути ослабления целостности нифига не проще? Ну типа да, я согласен с тем. что из слабой целостности нельзя сделать сильную — но систему со слабой согласованностью можно использовать в составе системы с более сильной целостностью, причем, этот сильноцелостный узел может быть очень простым и неэффективным, потому что не он определяет итоговые свойства.

byko3y ★★★ ()
Ответ на: комментарий от aist1

Считается, что констрейнты (C in ACID) нельзя соблюсти полностью без сериализации транзакций

C в ACID — это consistency. Ограничения на логические связи между данными (инварианты) вообще не рассматриваются в модели ACID.

один только SI не прокатит, так как есть write skew, для частичного отстранения от которого нужен select for update

Кто такой SI?

Я не буду спорить, что S4U+SI это это еще не строгая сериализуемость. В голове где-то крутится контрпример, но не выходит наружу. Я просто не уверен, что S4U позволяет избавиться от write skew полностью.

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

Однако, он не сможет сделать сериализуемость на уровне новых добавляемых записей. Это тот пример, который у тебя не вышел наружу. Элементарно две транзакции добавили две недопустимо похожих записи — и никакой select for update от этого не спасет — только блокировать таблицу целиком. При том, что на уровне уникальности индекса оптимизации в серверных СУБД имеются, и потому им не нужно блокировать всю, а вот сам ты через SQL ничего подобного сделать не можешь.

byko3y ★★★ ()
Ответ на: комментарий от aist1

И вот мессадж, который я тут в этой теме толкаю, состоит в том, что железо-то современное может очень много, и его потенциал далеко еще не раскрыт. Потому что софт довольно таки ригидный и сильно не успевает за железом

Самое смешное то, что технологии железа тоже неслабо отстали, даже GPGPU во много раз медленнее ASIC-ов, то есть, околоидеальных исполнителей. А софт отстал минимум на 20 лет от уровня известных технологий, и даже если смотреть на последние языки программирования — они все родом из 80-90-х, в том числе Go и Rust. Минимальные плюшки и сахарок в расчет не берем. И даже современные технологии ИИ родом из 90-х или даже конца 80-х — нового с тех пор почти ничего не появилось.

В 90-х все лепили свои ОС, в нулевых пер NoSQL, в 10-х — аналитические дата-платформы, а сейчас хорошо идут распределенные гибридные БД для ML/AI

Не совсем так. В 70-80-х вообще все лепили свои ОС, потому что в условиях ограниченности ресурсов накладных расходы от унифицированной ОС были недопустимы. NoSQL были первыми БД, потому корректнее было говорить «в девяностых все резко помешались на SQL», что начало проходить уже в нулевых. Вот с бигдатой ты точно описал, и ниша по прежнему слабо окучена, даже не смотря на то, что покемонов в ней уже выше крыши.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

C в ACID — это consistency.

Да, но консистентность определяется выполнением констрейнтов, а не как-то абстрактно.

Кто такой SI?

Snapshot Isolation.

Элементарно две транзакции добавили две недопустимо похожих записи

Приведи пример)

aist1 ★★ ()
Ответ на: комментарий от byko3y

Самое смешное то, что технологии железа тоже неслабо отстали, даже GPGPU во много раз медленнее ASIC-ов, то есть, околоидеальных исполнителей.

Так кто нам что-то запретит?) Вот моя игрушечка. Рядом на столе еще валяется Arty A7-100T. В незкоммиченных пока что — площадка для разработки акселераторов на основе RISC-V для обработки данных.

Я там на основе Rocket Chip для Arty A7, кастомную прошивку сделал, и там можно акселераторы добавлять. Потом в планах и Alveo U50, как время появится.

Этот Rocket Chip, кстати, как раз пример тех продвинутых языковых практик, о которых я говорю. Там HDL DSL над Scala (Chisel3) и фреймворк для Hardware Construction. Ты задаешь конфигурацию SoC, которую хочешь получить под заданную плату. Через это делается design space exploration. В Мемории точно такая же идея, только для структур данных.

aist1 ★★ ()
Ответ на: комментарий от byko3y

Именно по такому сценарию работает LMDB, и именно поэтому он на своих задачах уделывает завязанный на транзакции и диск SQLite на один-два порядка, даже если SQLite работает в асинхронном режиме.

Вот что бывает, когда приходится «показывать половину работы»)))

SWMRStore в Мемории работает по точно такому же принципу, как и LMDB и, вообще говоря, с неё и слизан изначально. Основное отличие от LMDB там в том, что будут consistency points, есть история коммитов, есть поддержка 2PC (rollback last commit), но нет многопроцессного режима. Ну и будет режим прямого обращения к нижележащему устройству, минуя mmap, через io_uring или SPDK.

Но там еще есть LMDBStore, который хранит блоки контейнеров в LMDB и позволяется организовать таким образом IPC через mmap.

И да, весь смысл в том, что SWMR/LMDB-подобная схема дает мне очень борзое strictly serializable MVCC хранилище сразу с развитой системой типов сверху (что по определению и есть база данных).

То есть, примерно с такой задержкой можно делать операцию «атомарно прочитать и обновить».

Но ты эту операцию можешь делать сразу для 32 незивисимых переменных. Всё там нормально, если есть линеаризуемость, а она есть, и если можно «пойти вширь». На аналитике и достаточно больших объемах данных — обычно можно. Сканирование, например, хорошо параллелится, если структура таблицы позволяет разбить её на равные сегменты. У LMDB, например, не позволяет. В Мемории позволяет. K/V тоже хорошо шардится, обычно.

но систему со слабой согласованностью можно использовать в составе системы с более сильной целостностью,

Да, конечно. Просто растет зоопарк хранилищ, между которыми нужно интеграцию поддерживать. Кроме того, со строгой сериализуемостью не всё хорошо. Оно или сильно медленно (Pg), или не отказоустойчиво (LMDB), или не умеет в объемы данных (ZooKeeper), или не поддерживает нужные структуры данных (всё остальное). Такие проекты, как atomix.io не на пустом месте появляются.

aist1 ★★ ()
Ответ на: комментарий от aist1

C в ACID — это consistency.

Да, но консистентность определяется выполнением констрейнтов, а не как-то абстрактно

Слушай, а мне кажется, что ты прав. Ну то есть есть разные интерпретации, но вообще-то они появились потому, что всякие Oracle, MS SQL, MySQL, PostgreSQL и прочие чаще предпочитают не поддерживать Consistency, чем поддерживать ее. А вместо этого за «consistency» выдают «согласованность тухлых данных снимка».

Это история вроде криков про поддержку ANSI SQL в Oracle RDBMS, хотя по факту 2 из 4 режимов изоляции стандарта оно не поддерживает в принципе вообще никак (dirty read и read committed).

Элементарно две транзакции добавили две недопустимо похожих записи

Приведи пример

CREATE TABLE Persons (
    PersonID int
);

Обе транзакции выполняют:

INSERT INTO Persons (PersonID) 
SELECT 1
FROM dual
WHERE NOT EXISTS(SELECT * 
                 FROM Persons  
                 WHERE (PersonID = 1));

При одновременном их выполнении в таблице оказывается две записи с PersonID = 1, поскольку в начале обоих транзакций select * from Persons where (PersonID = 1) был пустым множеством.

Правда, это не Write Skew, это просто несериализуемые транзакции — результат их одновременного выполнения отличается от последовательного выполнения. «Select for update» по всем прочитанным записям полностью устраняет феномен Write Skew и потому соответствует уровню Repeatable Reads из ANSI SQL, которое ниже уровня Serializable.

byko3y ★★★ ()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от aist1

Самое смешное то, что технологии железа тоже неслабо отстали, даже GPGPU во много раз медленнее ASIC-ов, то есть, околоидеальных исполнителей

Так кто нам что-то запретит?) Вот моя игрушечка. Рядом на столе еще валяется Arty A7-100T. В незкоммиченных пока что — площадка для разработки акселераторов на основе RISC-V для обработки данных

О, уважуха.

FPGA тоже намного менее эффективны, чем ASIC. Иногда FPGA выигрывает у GPGPU, иногда GPGPU выигрывает у FPGA, иногда они примерно на одном уровне. При этом ASIC укатывает их всех. Конечно, если бы GPGPU не стали популярными, то FPGA бы правило миром.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

Да, годный пример. БД тут нужно «помогать», указав, что PersonID unique. Но тогда, скорее всего, будет блокировка при вставке в таблицу :) Потому что MVCC в RDBMS при наличии индексов — хитрая штука. Индексы не обязательно будут мультиверсионными.

В Мемории индекс был бы мультиверсионным (поскольку там всё на CoW-деревьях, включая и индексы), и был бы сразу write-write conflict во время коммита, а не во время выполнения вставки в таблицу. По итогам, одну из транзакций бы отменили — и всё.

В SWMRStore/LMDB/SQLite писатели сразу сериализованы, поэтому проблемы не возникнет. В SWMRStore/LMDB они еще и максимально быстрые, так как там лог-структурированное wait-free хранилище. У SQLite в режиме WAL «всё сложно».

Я, кстати, посмотрел его доки внимательнее. У него есть checkpoints, при которых и делается flush в «асинхронном» режиме, но вот я только совсем не уверен, что обратное накатывание WAL будет атомарно. Об этом я не нашел ни слова)) Почему я «на слово» разработчикам БД не верю. О самом главном — ни слова))

aist1 ★★ ()
Ответ на: комментарий от byko3y

FPGA тоже намного менее эффективны, чем ASIC. Иногда FPGA выигрывает у GPGPU, иногда GPGPU выигрывает у FPGA, иногда они примерно на одном уровне.

GPGPU и есть ASIC, просто «на стероидах». Дело здесь такое. FPGA очень дорогие поштучно, у них низкие частоты, и низкая (относительно ASIC) степень интеграции из-за того, что большую часть кристалла занимает interconnect. ASIC-и имеют в 5-10 раз большую частоту и во столько же раз меньшую цену, но они application-specific. Поэтому, FPGA порвет GPGPU как Тузик — грелку, если дизайн плохо ложится на PU GPU. ASIC-и обычно очень неэффективны за пределами задачи, для которой они разрабатывались.

... то FPGA бы правило миром.

А они и правят)) Ты сначала делаешь на FPGA, и только если тебе нужно «много чипов» (масштаб), ты выпекаешь ASIC. Всё мелкотиражное или сидит на MCU, или на FPGA. Сейчас, правда, ASIC можно выпечь и мелким тиражем, если кремниевый процесс не нужно твикать под дизайн. Но оно все равно долго и дорого.

Если говорить про текущее поколение FPGA (к которому относится и мой U50), то у них нет Network on Chip, поэтому делать на них акселераторы приложений в виде массивов PU не особо эффективно (относительно тех же GPU). Новейшие FPGA выделенный NoC уже содержат, и очень интересно было бы на их возможности посмотреть :)

В общем, начинаем с FPGA, и потом, если оно оказалось стоящее, выпекаем ASIC. В Мемории самой по себе (еще без процессинга) есть очень много всего, что можно поддержать аппаратно. Например, тегированная память для аппаратной защиты данных. Или аналоги битовых операций для словарей больше 2 символов, на них там много что построено, но на CPU оно сейчас реализуется плохо. Поддержка различных техник сжатия для сжатых структур данных. И т.п.

Акселераторы — это ведь не обязательно именно высокопроизводительные вычисления (GPGPU). Это еще и энергоэффективные. Я бы хотел видеть элементы Мемории (тегированная защищенная память, символьные операции и т.п.) в MCU (не во всех, ессно, они нужны).

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 3)
Ответ на: комментарий от aist1

SQLite atomic WAL checkpointing

Проверил код wal.c SQLite. Дело, короче, такое. Накатывание WAL на файл БД, действительно, не атомарное. НО, если произойдет крэш во время чекпоинта, то чекпоинт можно будет просто повторить после крэша. Что и произойдет, если БД будет открыта с наличествующим WAL-файлом.

Если при крэше во время чекпоинта WAL будет потерян, то будет повреждение файла БД.

Я такую схему считаю устойчивой к крэшам. В ситуациях, когда предварительно (перед чекпоинтом) fsync-нутый WAL может потеряться при крэше, может еще много чего произойти и с самим файлом БД, от чего уже не защитишься на уровне самой БД.

aist1 ★★ ()
Последнее исправление: aist1 (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Небольшое уточнение - в данном случае персональную функцию тянут методы, которые отмечены noexcept. Работает примерно так - где-то бросается исключение, происходит проход по стеку вызовов, для каждого фрейма вызывается персональная функция, которая решает что делать с этим исключением. Звучит странно - нам исключения не нужны вовсе, но unwind интерфейс тянем. В таких слуаях надо собирать с флагом -fno-excptions

gcc 1.cc -fno-exceptions

Естественно, что если заюзаем throw’ий метод, то собрать не удастся из-за отсутсвия необходимых зависимостей. Ну а тот пример со string_view собрался с одной зависимостью от libc.

kvpfs ()
Ответ на: комментарий от kvpfs

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

Ну так чтобы «продумать отлов исключений» надо знать, что может вылететь? Из сигнатуры это не видно, в доках тоже не всегда всё пишут (и следить за актуальностью документации приходится вручную, а значит они могут врать). В исходниках для полной уверенности смотреть придётся достаточно глубоко. И никаких гарантий, что при обновлении зависимостей или даже рефакторинга своего кода «продуманность» потеряется нет.

Впрочем, подход «ничего не ловим пока не поймём, что надо» в среднем работает после того как будут собраны основные грабли (хорошо если при тестировании, а не на пользователях). Код при этом, как правило, действительно получается «чище» плюс уменьшается время первой реализации.

DarkEld3r ★★★★★ ()
Ответ на: комментарий от DarkEld3r

Исключения - это лишь более продвинутый сишный abort(), если это осознаётся, то и проблем не будет. Сишка аборты в релизе просто тупо вырезает (и хз - может так и не протестил тот кейс, где аборт бы сработал), цпп - даёт средства для перехвата исключений в релизе. А желающие отказаться от кодов возврата в пользу исключений максимально - ну пусть страдают, сами виноваты.

kvpfs ()
Ответ на: комментарий от s-warus

развитием 386 на 64 рулила AMD и в 64битном режиме от них избавились, был бы это intel и сегментные регистры появились бы и там

И они там есть.

когда программировал на ассемблере меня удивило что большая часть кода команд 86 и z80 совпадало хотя ассемблер-мемоники команд разные

На какие примеры совподающих кодов Вы обратили внимание?

vM ()
Ответ на: комментарий от aist1

Ты сначала делаешь на FPGA, и только если тебе нужно «много чипов» (масштаб), ты выпекаешь ASIC. Всё мелкотиражное или сидит на MCU, или на FPGA. Сейчас, правда, ASIC можно выпечь и мелким тиражем, если кремниевый процесс не нужно твикать под дизайн. Но оно все равно долго и дорого

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

byko3y ★★★ ()
Ответ на: комментарий от byko3y

Ну, там много чего еще можно. Гибкость там сейчас постоянно увеличивается. Тут свои чипы выпекают студенты-дипломники CE. У университетов есть контракты с заводами, по которым они дают студням порезвиться на поляне, на не совсем еще тухлом техпроцессе, типа 40нм.

Сейчас развивается software-hardware co-design, когда ты не только софт делаешь под железку, но и железку тоже дизайнишь под софт и его потребности. ФААНГи уже вовсю в этом деле. Про FB, правда, не слышно, чтобы они свой чип делали, но оно не за горами, я так думаю. Кремний сейчас демократизируется активно.

Короче, кто-то вот всё еще спорит про OOP vs FP, а кто-то уже co-design осваивает. Оно может казаться, что всё пока еще более чем не нужно. Но вот те же Маки идут с кучей акселераторов рядом с CPU, и мобильные чипы — тоже. И всё это надо будет как-то уметь в приложениях использовать. Потому что придет бодрая молодежь, и подвинет уставших от жизни обладателей пивных животиков с хлебных мест подальше на поддержку легаси.

Я не к тому, что надо срочно бежать покупать Alveo U50 или что у них там еще есть подороже и позабористей. Но вот, например, я, разбираясь в теме акселераторов, (пере-)открыл для себя тегированную память. И что именно она нужна для защиты памяти. А та же страничная защита — так себе защита. Слишком крупноблочная.

Софтовые примочки типа тех, что в Rust или JVM, они, конечно много как помогают. Но это только видимость защиты памяти, а не защита. И co-design тут состоит в том, что гранцулярность и словарь тегирования должен разрабатываться под структуры данных, а структуры данных — под то, что у будут в тегированной памяти. Т.е. теги — это еще один слой данных, просто поддерживаемый аппаратно.

aist1 ★★ ()