Если коротко, да, отказ хранилища (Prometheus/Loki/Jaeger) принять телеметрию рано или поздно приведёт к её отбрасыванию, с этим ничего не поделать (падать он при этом не будет), но этот момент можно отсрочить:
Выставляем sending_queue, это спасает нас в случае кратковременных сбоев хранилища и позволяет поделать ретраи, но если падает сам OTelCol, то накопленная в нём телеметрия теряется (т.к. лежит в памяти)
Использовать file_storage extension. Это заставляет sending_queue сбрасывать телеметрию на диск, что спасает при падении OTelCol. Какое-то время (пока ёмкость очереди не переполнится) телеметрия теряться не будет, плюс некоторую телеметрию всё же можно будет посмотреть с помощью ZPages
Всегда можно слегка укрепить схему Application -> OTelCol -> Storage, используя промежуточное хранилище: Application -> OTelCol -> Kafka/RabbitMQ/NATS/.... -> OTelCol -> Storage. Да, это увеличивает число движущихся частей, но если нам оооооочень важно не терять телеметрию, то это вполне рабочий вариант
Далее, чтобы инстансы OTelCol не становились SPF-ами, нужно их запускать по следующей схеме:
Для отдельных Application ставим OTelCol в виде Sidecar. Он может, например, докидывать метаданные о поде в кубере, приложении и т.п., если оно само этого не делает, или, например, писать телеметрию в локальные файлики с logrotate, чтобы всегда можно было "как деды" зайти в контейнер и что-то там почитать-погрепать
Для каждого Host можно ставить OTelCol уровня хост-агента (K8S DaemonSet или Docker Swarm global deployment). Этот агент может докидывать метаданные о хосте, ОС и т.п., ну и, опять же, писать всю телеметрию в файлики (как в первом пункте, но теперь уже для всего хоста). Ну и плюсом может собирать, собственно, телеметрию самого хоста (с тех же cAdvisor, node-exporter, или из собственных receiver-ов)
На предыдущих этапах не надо было заботиться об отказоустойчивости, т.е. если OTelCol падает (и это не просто ошибка конфига и подобные вещи, которые видно сразу), то уже пофиг.
А вот на уровне Gateway нам уже нужно накидать сочной отказоустойчивости. Как? Правильно -- поднять больше инстансов. И тут самая главная часть -- правильный роутинг при балансировке нагрузки. Например, важно чтобы трейсы с одинаковым trace-id летели на один и тот же OTelCol, на котором будет приниматься решение о tail-sampling. Если же отправить их на два разных, то один может записать трассу, а другой -- нет, и мы получим некрасивые разрывы и невалидные метрики.
Насчёт метки "по ключу были изменения": в Redis имеются keyspace и keyevent pub/sub каналы. keyspace говорит "на ключе А была применена операция Б" keyevent говорит "операция Б была применена на ключе А"
Т.е. можно отслеживать все операции над конкретным ключом через keyspace и все ключи, к которым была применена конкретная операция через keyevent
Также имеется система "кеширования на стороне клиента", когда Redis через pubsub отсылает уведомления о том, что "этот ключ был изменён". Подписался, и будет тебе счастье.
(Знаю, капец, как вовремя), но почему, собственно, не подходит? Сейчас в Redis можно загружать хранимые функции (не скрипты, а именно функции, которые являются объектами Redis, и будут сохраняться и реплицироваться). Так что такой мизер логики спокойно можно написать, добавив всего одну функцию.
К сожалению, не подскажу. Я заходил в параметры (preferences) QtCreator (где настраивается почти вся IDE), открывал CLang и крутил по всяким малоприятным (ну а что мы хотели от CLang) сайтам.
Это я делал для старого ПК, на ноуте (сейчас только с ним хожу, ибо давно не дома) изначально всё ок было.
Тебе ответ о том, были данные или нет, всё-равно придёт (или не придёт, если пакет потерялся, но тогда будет timeout-event). Просто на транспортном уровне это будет несколько дешевле.
Авторизация по токену существует кучу лет. Тот же OAuth2 был опубликован в 2012, а до этого как пример можно привести ключи от игр (продажа диска и была надёжным способом доставки).
И да, библиотек для этого куча, с различными интерфейсами, и даже под плюсы, и даже, думаю, можно что-то хорошее для Qt наковырять.
Тут вопрос скорее, как сделать это на Qt, и чисто повод для меня написать немного прикольного кода.
Если библиотека предоставляет несколько путей решения нетривиальных задач, значит, имея мозг, можно выбрать оптимальный из них в конкретном контексте.
Никто не должен пилить MV поверх Qt. В Qt реализован MVD подход, предполагающий отделение данных от их отображения и обработки.
Типизация позволяет в проекте больше хелловорда не запутаться во всех этих "правильных" либах питона, считающих своим долгом возвращать Any, чтобы ты лез в доку, и смотрел, что конкретно вернула тебе эта хренотень.
Не, ну по сравнению с питоновскими либами на десять функций Qt, конечно, очень сложен. Но этой штуке скоро тридцать лет, и на тех же плюсах можно писать код не беря вообще ничего, кроме стандартной либы и Qt. Но то, что кому-то лень потратить несколько часов и разобраться в объектной модели, не делает Qt плохой либой.
Мы на работе используем как mvd, так и mvc подходы. Но у нас много кастомных виджетов и отрисовки, поэтому специально под mvc ничего допиливать не пришлось.
Лямбду можно использовать. Только надо не забыть несколько пунктов:
task — move-only класс. Поэтому просто захватит всё по значению — не вариант.
Не забываем про mutable, т.к. handleNextMessage изменяет состояние task (вызывает task.promise().finish()).
Штука с возвращаемым значением — плохой вариант. Причина проста — зачастую непросто определить, когда функция завершит выполнение и вернёт значение. Избежать можно двумя путями:
Qt::DirectConnection — вызывать callable сразу из потока, который дёрнул QMetaObject::invokeMethod. Нам не подходит, т.к. Active object предполагает разделение вызова операции, и её выполнения.
Qt::BlockingQueuedConnection — callable исполняется в том потоке, который владеет context (указатель this в вызове QMetaObject::invokeMethod), а поток, вызвавший метод будет заблокирован до конца выполнения callable. Крайне отвратительный подход.
Резюмируя, можно создать вот такую конструкцию, которая избавит нас от строковых литералов, избавит нас от макросов, и при этом будет достаточно красивой:
Ну и теперь у нас прекратит собираться. Причина тому — попытка moc обернуть handleNextMessage в метасистему. Поэтому нужен новый подход в передаче данных. Есть два способа исправить это:
Пусть handleNextMessage принимает task по ссылке из лямбды.
Убрать пометку "slots" с handleNextMessage. Макроса Q_INVOKABLE тоже быть не должно. Но т.к. это приватный метод, и никто, нигде и никогда его вызывать не должен, то это разумно. Ну и можно принимать task хоть по значению (ибо всё равно move-only), хоть по r-value ссылке.
Ну и если возникнет идея обернуть этот callable в какой-нибудь std::bind для красоты — не вариант, потому что std::move_only_function нам пока не дали.
Зачастую это так. Как минимум, потому что тебе не нужен тест на то, что "результат вот этой функции -- действительно число". Тебе это прямо в сигнатуре функции дано.
Соответственно, остаётся проверять исключительно логику кода, а не его типы.
Прикол с таймером для "отдышаться" лишний. Это точно никому не нужно. Если что, в крайнем случае у тебя ядро процессора будет долбиться в сотку с максимальным фпс. Но лагать ничего не будет.
Ну а какая разница, кто ограничил. Вот не пашет, и всё.
Ну вот на моей работе (не могу показать по понятным причинам) использовали qmake. Но, правда сказать, там всё было плохо скорее от расдолбайства разрабов....но вообще, CMake - это унификация. А унификация - это хорошо.
mingw не поддерживает некоторые модули, например, QWebEngine. По крайней мере, так было у меня чуть больше года назад, и я не видел новости, чтобы что-то заработало. Так что тут лучше msvc.
На Cmake собственно перешёл сам Qt. Его активно развивают. Для простых проектов всё ещё можно использовать qmake, но имхо Cmake банально мощнее.
Для такого в доке лежит вот такой раздел: https://opentelemetry.io/docs/collector/resiliency/
Если коротко, да, отказ хранилища (Prometheus/Loki/Jaeger) принять телеметрию рано или поздно приведёт к её отбрасыванию, с этим ничего не поделать (падать он при этом не будет), но этот момент можно отсрочить:
Выставляем sending_queue, это спасает нас в случае кратковременных сбоев хранилища и позволяет поделать ретраи, но если падает сам OTelCol, то накопленная в нём телеметрия теряется (т.к. лежит в памяти)
Использовать file_storage extension. Это заставляет sending_queue сбрасывать телеметрию на диск, что спасает при падении OTelCol. Какое-то время (пока ёмкость очереди не переполнится) телеметрия теряться не будет, плюс некоторую телеметрию всё же можно будет посмотреть с помощью ZPages
Всегда можно слегка укрепить схему Application -> OTelCol -> Storage, используя промежуточное хранилище: Application -> OTelCol -> Kafka/RabbitMQ/NATS/.... -> OTelCol -> Storage. Да, это увеличивает число движущихся частей, но если нам оооооочень важно не терять телеметрию, то это вполне рабочий вариант
Далее, чтобы инстансы OTelCol не становились SPF-ами, нужно их запускать по следующей схеме:
Для отдельных Application ставим OTelCol в виде Sidecar. Он может, например, докидывать метаданные о поде в кубере, приложении и т.п., если оно само этого не делает, или, например, писать телеметрию в локальные файлики с logrotate, чтобы всегда можно было "как деды" зайти в контейнер и что-то там почитать-погрепать
Для каждого Host можно ставить OTelCol уровня хост-агента (K8S DaemonSet или Docker Swarm global deployment). Этот агент может докидывать метаданные о хосте, ОС и т.п., ну и, опять же, писать всю телеметрию в файлики (как в первом пункте, но теперь уже для всего хоста). Ну и плюсом может собирать, собственно, телеметрию самого хоста (с тех же cAdvisor, node-exporter, или из собственных receiver-ов)
На предыдущих этапах не надо было заботиться об отказоустойчивости, т.е. если OTelCol падает (и это не просто ошибка конфига и подобные вещи, которые видно сразу), то уже пофиг.
А вот на уровне Gateway нам уже нужно накидать сочной отказоустойчивости. Как? Правильно -- поднять больше инстансов. И тут самая главная часть -- правильный роутинг при балансировке нагрузки. Например, важно чтобы трейсы с одинаковым trace-id летели на один и тот же OTelCol, на котором будет приниматься решение о tail-sampling. Если же отправить их на два разных, то один может записать трассу, а другой -- нет, и мы получим некрасивые разрывы и невалидные метрики.
Насчёт метки "по ключу были изменения": в Redis имеются keyspace и keyevent pub/sub каналы.
keyspace говорит "на ключе А была применена операция Б"
keyevent говорит "операция Б была применена на ключе А"
Т.е. можно отслеживать все операции над конкретным ключом через keyspace и все ключи, к которым была применена конкретная операция через keyevent
Также имеется система "кеширования на стороне клиента", когда Redis через pubsub отсылает уведомления о том, что "этот ключ был изменён". Подписался, и будет тебе счастье.
(Знаю, капец, как вовремя), но почему, собственно, не подходит?
Сейчас в Redis можно загружать хранимые функции (не скрипты, а именно функции, которые являются объектами Redis, и будут сохраняться и реплицироваться). Так что такой мизер логики спокойно можно написать, добавив всего одну функцию.
К сожалению, не подскажу. Я заходил в параметры (preferences) QtCreator (где настраивается почти вся IDE), открывал CLang и крутил по всяким малоприятным (ну а что мы хотели от CLang) сайтам.
Это я делал для старого ПК, на ноуте (сейчас только с ним хожу, ибо давно не дома) изначально всё ок было.
Manjaro имба.+респект
Можно взять std::numeric_limits<double>::epsilon().
Зашёл в коменты, чтобы как раз это и найти)
std::numeric_limits<T>::epsilon есть в C++ вроде как ещё до C++11
Так это из-за шланг-анализатора. Если настройки под свой ноут покрутить, то всё ок.
Ну так всегда лучше использовать стандартные алгоритмы. Тут человек явно для примера всё пишет.
Тебе ответ о том, были данные или нет, всё-равно придёт (или не придёт, если пакет потерялся, но тогда будет timeout-event). Просто на транспортном уровне это будет несколько дешевле.
Авторизация по токену существует кучу лет. Тот же OAuth2 был опубликован в 2012, а до этого как пример можно привести ключи от игр (продажа диска и была надёжным способом доставки).
И да, библиотек для этого куча, с различными интерфейсами, и даже под плюсы, и даже, думаю, можно что-то хорошее для Qt наковырять.
Тут вопрос скорее, как сделать это на Qt, и чисто повод для меня написать немного прикольного кода.
Если библиотека предоставляет несколько путей решения нетривиальных задач, значит, имея мозг, можно выбрать оптимальный из них в конкретном контексте.
Никто не должен пилить MV поверх Qt. В Qt реализован MVD подход, предполагающий отделение данных от их отображения и обработки.
Типизация позволяет в проекте больше хелловорда не запутаться во всех этих "правильных" либах питона, считающих своим долгом возвращать Any, чтобы ты лез в доку, и смотрел, что конкретно вернула тебе эта хренотень.
Не, ну по сравнению с питоновскими либами на десять функций Qt, конечно, очень сложен. Но этой штуке скоро тридцать лет, и на тех же плюсах можно писать код не беря вообще ничего, кроме стандартной либы и Qt. Но то, что кому-то лень потратить несколько часов и разобраться в объектной модели, не делает Qt плохой либой.
Мы на работе используем как mvd, так и mvc подходы. Но у нас много кастомных виджетов и отрисовки, поэтому специально под mvc ничего допиливать не пришлось.
Лямбду можно использовать. Только надо не забыть несколько пунктов:
task — move-only класс. Поэтому просто захватит всё по значению — не вариант.
Не забываем про mutable, т.к.
handleNextMessageизменяет состояние task (вызывает task.promise().finish()).Штука с возвращаемым значением — плохой вариант. Причина проста — зачастую непросто определить, когда функция завершит выполнение и вернёт значение. Избежать можно двумя путями:
Qt::DirectConnection — вызывать callable сразу из потока, который дёрнул QMetaObject::invokeMethod. Нам не подходит, т.к. Active object предполагает разделение вызова операции, и её выполнения.
Qt::BlockingQueuedConnection — callable исполняется в том потоке, который владеет context (указатель this в вызове QMetaObject::invokeMethod), а поток, вызвавший метод будет заблокирован до конца выполнения callable. Крайне отвратительный подход.
Резюмируя, можно создать вот такую конструкцию, которая избавит нас от строковых литералов, избавит нас от макросов, и при этом будет достаточно красивой:
Метод print
Ну и теперь у нас прекратит собираться. Причина тому — попытка moc обернуть handleNextMessage в метасистему. Поэтому нужен новый подход в передаче данных. Есть два способа исправить это:
Пусть handleNextMessage принимает task по ссылке из лямбды.
Убрать пометку "slots" с handleNextMessage. Макроса Q_INVOKABLE тоже быть не должно. Но т.к. это приватный метод, и никто, нигде и никогда его вызывать не должен, то это разумно. Ну и можно принимать task хоть по значению (ибо всё равно move-only), хоть по r-value ссылке.
Ну и если возникнет идея обернуть этот callable в какой-нибудь std::bind для красоты — не вариант, потому что std::move_only_function нам пока не дали.
Да. Забыл про эту штуку. Сейчас обновлю статью.
Полагаю, это вопрос к первой части.
QQueue требует, чтобы тип был копируемый, а QPromise у нас некопируемый. Поэтому используется stl-очередь, поддерживающая move-only типы.
В коде явно видно, что сначала задача перемещается (std::move()) в очередь в методе print, а затем также перемещается обратно в методе run().
Зачастую это так. Как минимум, потому что тебе не нужен тест на то, что "результат вот этой функции -- действительно число". Тебе это прямо в сигнатуре функции дано.
Соответственно, остаётся проверять исключительно логику кода, а не его типы.
Прикол с таймером для "отдышаться" лишний. Это точно никому не нужно. Если что, в крайнем случае у тебя ядро процессора будет долбиться в сотку с максимальным фпс. Но лагать ничего не будет.
"Как в Angry Birds" делается тремя событиями (pressed уже обрабатывается в коде): https://www.sfml-dev.org/tutorials/2.5/window-events.php#the-mousebuttonpressed-and-mousebuttonreleased-events и https://www.sfml-dev.org/tutorials/2.5/window-events.php#the-mousemoved-event . На pressed надо запоминать координату нажатия, на moved - рисовать стрелку между координатой нажатия и текущей координатой мыши, а на released -- создавать объект и давать ускорение.
Ну а какая разница, кто ограничил. Вот не пашет, и всё.
Ну вот на моей работе (не могу показать по понятным причинам) использовали qmake. Но, правда сказать, там всё было плохо скорее от расдолбайства разрабов....но вообще, CMake - это унификация. А унификация - это хорошо.
Моё личное мнение
mingw не поддерживает некоторые модули, например, QWebEngine. По крайней мере, так было у меня чуть больше года назад, и я не видел новости, чтобы что-то заработало. Так что тут лучше msvc.
На Cmake собственно перешёл сам Qt. Его активно развивают. Для простых проектов всё ещё можно использовать qmake, но имхо Cmake банально мощнее.