Почему подписки загружают процессор на 100% - PullRequest
0 голосов
/ 21 июня 2020

Я получаю статистику от hasura следующим образом:

FrontEnd (nuxt. js)

<script>
import subUsers from '~/apollo/subscriptions/stats/users'
import users from '~/apollo/queries/stats/users'

export default {
  apollo: {
    users: {
      query: users,
      update: data => data.users_aggregate.aggregate.count,
      subscribeToMore: {
        document: subUsers,
        updateQuery: (previousResult, { subscriptionData }) => {
          return {
            users_aggregate: subscriptionData.data.users_aggregate
          }
        }
      }
    }
  }
}
</script>

Hasura:

query users {
  users_aggregate {
    aggregate {
      count
    }
  }
}
subscription users {
  users_aggregate {
    aggregate {
      count
    }
  }
}

In таблица user У меня около 500000 пользователей

А из-за подписок у меня все ядра процессора загружены на 100% enter image description here

htop

Ответы [ 2 ]

1 голос
/ 22 июня 2020

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

drop table if exists user_aggregate;
drop trigger if exists user_aggregate_trigger on user_info;
drop function if exists user_aggregate();

create table user_aggregate (
    id int not null primary key,
    user_aggregate int not null
);

create or replace function user_aggregate()
returns trigger
as $$
begin
    insert into user_aggregate (id, user_aggregate)
    values (1, (select count(id) from user_info))
    on conflict (id) do
    update set user_aggregate = excluded.user_aggregate;
    return new;
end
$$ language plpgsql;

create trigger user_aggregate_trigger
after insert or delete on user_info
for each row execute procedure user_aggregate();

insert into user_aggregate (id, user_aggregate)
values (1, (select count(id) from user_info))
on conflict (id) do
update set user_aggregate = excluded.user_aggregate;

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

1 голос
/ 21 июня 2020

Hasura реализует подписку через интервальный опрос, что в основном означает, что ваш запрос выполняется каждую 1 секунду. Вы можете прочитать подробности об архитектурных решениях здесь:

Поскольку вы выполняете запрос агрегирования более 500 тыс. Строк каждый во-вторых, ну ...

Так что же делать? В Postgres есть решение, которое называется материализованными представлениями. Вы создаете одно такое представление на основе желаемого агрегата, а затем говорите PG обновлять его только тогда, когда это имеет смысл. Итак, в вашем случае вы должны обновлять его каждый раз, когда пользователь добавляется или удаляется. Затем вы подписываетесь на свое представление, и его стоимость практически равна нулю (поскольку представление запоминает результат запроса до обновления).

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