Pull to refresh
29
0
Roman Kudryashov @not_bad

User

Send message

Спасибо.

cadvisor туда же - он попросту в таком сетапе становится не нужен.

При деплое в k8s что-то другое используется для мониторинга контейнеров?

это логично, потому что эти метрики считают разные типы памяти...

Да, к сожалению пока не нашёл такой вариант метрик памяти контейнера и приложения, который измеряет один и тот же тип памяти и при этом корректно отображается на графике

Интересен был именно такой набор инструментов, возможно потому, что в работе не сталкивался с Zabbix

Не сталкивался с проблемой высокого потребления CPU, но нашёл issue, где также есть варианты решения

Мужики, добавил автоэкспирацию записей в кэше с пояснением в статье :) Джуны могут спать спокойно :)

А то потом джуны копируют этот код и оно пролазит в продакшен.

И? Баг? Так и поделом такой компании, без синьоров и тестеров :)

Конечно, эти варианты возможны, но не считаю, что

  • утверждение о маловероятности опровергнуто

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

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

Справедливое замечание, поменял

С очисткой кеша, при обновлении записи в монге, тоже вопрос не простой. А что если приложение навернётся сразу после обновления документа в монге, но до того как кеш в редиске будет удалён? Очевидно не хватает "авто-протухания" кеша через какое-то время.

Конкретно здесь:

pub async fn update_planet(
    &self,
    planet_id: &str,
    planet: Planet,
) -> Result<Planet, CustomError> {
    let updated_planet = self
        .mongodb_client
        .update_planet(ObjectId::from_str(planet_id)?, planet)
        .await?;

    let cache_key = self.get_planet_cache_key(planet_id);
    self.redis_connection_manager.clone().del(cache_key).await?;

    Ok(updated_planet)
}

маловероятно, что что-то может пойти не так. Для порядка можно перенести формирование строки ключа в начало метода. Для "продакшн" приложения, возможно, и стоит рассмотреть вариант с автоэкспирацией.

Вполне возможно, что не для всех backend задач есть библиотеки или существующие недостаточно развиты. Пока что я сталкивался только со вторым, при этом в части случаев мейнтейнеры были готовы доработать крейты. Кроме того, для многих задач (например, GraphQL, ORM) есть 2 или более поддерживаемых библиотек.

По поводу переключения (в моём случае основными языками были Java/Kotlin), в первые месяцы действительно сложно.

Думаю, это могло бы быть справедливо, если бы результаты вызовов этих `await`'ов были логически независимы. Но, например, в этом случае:

pub async fn update_planet(
    &self,
    planet_id: &str,
    planet: Planet,
) -> Result<Planet, CustomError> {
    let updated_planet = self
        .mongodb_client
        .update_planet(ObjectId::from_str(planet_id)?, planet)
        .await?;

    let cache_key = self.get_planet_cache_key(planet_id);
    self.redis_connection_manager.clone().del(cache_key).await?;

    Ok(updated_planet)
}

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

минимум комментариев про саму статью.

К сожалению, да, большая часть комментариев не имеет отношения к теме статьи


Работают ли подписки, если публикумые данные собираются с нескольких бэкендов? Сможет ли сервер федерации обработать такой кейс?

Apollo Gateway не поддерживает подписки: https://github.com/apollographql/federation/issues/426


Мне известно о следующих альтернативах Apollo Gateway:



Разработчиками первых двух заявляется, что они поддерживает подписки; последняя не поддерживает (https://github.com/nautilus/gateway/issues/108)


Планирую заменить Apollo Gateway в проекте на GraphGate, как только (или если) он станет production-ready, и протестировать указанный кейс


Полагаю также, что от всех указанных альтернатив следует ожидать заметно большую производительность по сравнению с Apollo Gateway

Повторюсь.

Это совсем не обязательно. Ваши кейсы здесь никому не интересны

Спасибо, что представили существо вопроса


  1. Используйте все указанные выше подходы
  2. Изучите документацию к выбранному фреймворку и используйте представленные там подходы к security

Я бы предложил поменять схему данных, после чего запрос станет:


{
    getPosts(filter: {status: PUBLISHED}, page: {number: 1, size: 10}) {
        author {
            name
        }
    }
}

Далее, предположим у кого-то появится желание положить сервер таким запросом:


{
    getPosts(filter: {status: PUBLISHED}, page: {number: 1, size: 10}) {
        author {
            posts {
                author {
                    posts {
                    # и т. д.
                    }
                }
            }
        }
    }
}

Предотвратить такую циклическую цепочку вызовов невозможно, если только не поменять типы, удалив поле Author.posts или Post.author.


Поэтому первое с чего стоит начать — это ограничение глубины запроса (разумеется, GraphQL, а не SQL. В качестве хранилища может быть что угодно: SQL, NoSQL, in-memory и т. д., о чём GraphQL знать не нужно). В данном простейшем случае можно установить его например 3, чего должно быть достаточно для получения всех нужных данных. Соответственно, клиенту при выполнении запроса выше придёт сообщение о его невалидности.


Также можно указать, что поле Author.posts принимает аргумент количества постов, тогда запрос станет:


{
    getPosts(filter: {status: PUBLISHED}, page: {number: 1, size: 10}) {
        author {
            posts(first: 10) {
                title
            }
        }
    }
}

Вроде обращение Author.posts и избыточно, но по крайней мере не критично для перформанса.


Если этих простейших шагов окажется недостаточно, то можно использовать более продвинутые техники (например, Query Cost Analysis) (см. https://www.apollographql.com/blog/securing-your-graphql-api-from-malicious-queries-16130a324a6b/ и другие источники).

Каким образом в GraphQL гарантировать, что через апи нельзя выбрать лишнего

А что вы понимаете под "выбрать лишнего"? В моём понимании это гарантирует синтаксис. В статье есть пример запроса:


{
  getPlanets {
    name
    type
  }
}

В ответ на это GraphQL сервер пришлёт исключительно 2 запрашиваемых поля для каждого элемента возвращаемого списка.


запросы, которые получаются не уложат базу

Для этого есть несколько инструментов:


  • ограничение сложности и глубины запроса
  • решение проблемы N+1
  • пагинация (для query, возвращающих массивы/списки с большим количеством элементов, создайте параметры pageNumber, pageSize)

Первые два вопроса освещены в статье. Да и в целом по ним достаточно материала


Если есть простой способ этого добиться

Имплементация вышеуказанного — в целом решаемая задача

Я правильно понимаю что у вас нет внятной аргументации и ответов и поэтому вы пытаетесь о чем-то догадаться?

Нет, вы ошибаетесь, аргументация есть. Оптимально, когда задаваемые вопросы касаются темы статьи ("GraphQL на Rust"). Также по мере возможностей отвечаю на более абстрактные вопросы, в том числе совпадающие с поисковой выдачей гугла по запросу "graphql drawbacks"


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

А вот это уже клевета. Не уверен, что это разрешено правилами сайта

Угу, туториалы они такие туториалы. Но когда пишешь или смотришь на чужие реализации отличные от туториалов то все почему-то не так радужно…

Я правильно понял, что у вас не получилось реализовать GraphQL API в рабочем проекте без проблем с перформансом?


Это то, что содержится в вашем же определении выделенном кавычками.

Так вы же попытались там опровергнуть моё определение, предложив своё. Вот мне и стало интересно, откуда оно?


Чем вам это поможет в бессмысленных попытках натянуть сову на глобус?

О чём вы?


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

Где вы увидели обвинение? Я только уточнил

По запросу "graphql drawbacks" гугл выдаёт почти то же самое, что привели вы. Совпадение?


Там зубодробительная логика на стороне бекенда получается.

Это ваш личный опыт реализации GraphQL API или в вашей компании? Дело в том, что множество материалов, включая прочитанную (?) вами настоящую статью, это не подтверждают


Идеология graphql в инверсии контроля, а не «запрашивать те данные которые нужны». Вы перекладываете контроль за тем что и как вам нужно на строну клиента.

Это вольная трактовка или есть источники/ссылки, подтверждающие что это и есть иделогия?


Вы перекладываете контроль за тем что и как вам нужно на строну клиента.
Пока у вас приложение внутреннее — все ок.
Как только вы интерфейс выставляете наружу, то выясняется что доверять клиенту нельзя. Отсюда и вопрос доступа, и вопрос лимита на запросы и т.п.

"GraphQL позволяет клиенту выбирать нужные ему данные с точностью до полей, но при этом всё ещё нужно обеспечивать безопасность приложения" — no comment


Как разумную альтернативу здорового человека я предлагаю использовать RPC и его вариации в виде JSON-RPC, XML-RPC, gRPC.

Как разумный здоровый человек я воздержусь от обсуждения RPC как способа frontend-backend взаимодействия в комментариях к статье "GraphQL на Rust"


Доп. вопрос: какую библиотеку вы использовали для реализации GraphQL API?

Я не считаю идеологию кривой. Запрашивать ровно те данные, которые нужны клиенту, при меньшем количестве сетевых запросов — вполне нормальный подход. Может наоборот, REST кривой в этом аспекте?


По поводу примеров:


  • если я правильно понял "гранулярность доступа", то с этим всё ок. Сама спека ничего не говорит об этом, при этом конкретные реализации могут имплементировать данную функциональность. Что и было показано в статье (раздел "Авторизация"), когда для мутации определён "гард". Аналогично гард может быть указан для любого поля какой-либо структуры. В других фреймворках это будет реализовано по-другому
  • кэширование — не знаю, что вы имеете в виду. Вот пара ссылок: eng/ru, судя по которым не кажется, что кэширование в GraphQL — это rocket science. Да, сделано по-другому, чем в REST, но это ведь не значит криво?
  • rate limit — сходу не нашёл примеров реализации, но стоит отметить, что эта проблема не столь актуальна как в REST. В GraphQL вызовы одной и той же query могут содержать разные наборы полей, поэтому большее значение имеет возможность ограничения глубины и сложности запроса, что, полагаю, реализовано в большинстве GraphQL библиотек и также было показано в статье

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity