Я использую сегментированные счетчики (https://cloud.google.com/appengine/articles/sharding_counters) в моем приложении GAE из соображений производительности, но мне трудно понять, почему оно работает так медленно и как его ускорить.
Предыстория
У меня есть API, который захватывает набор из 20 объектов за раз, и для каждого объекта он получает общее количество от счетчика, чтобы включить его в ответ.
Метрики
При включенном Appstats и чистом кеше я заметил, что получение итогов для 20 счетчиков составляет 120 RPC с помощью datastore_v3.Get, что занимает 2500 мс.
Мысли
Похоже, что вызовов RPC довольно много, а для чтения всего 20 счетчиков требуется совсем немного времени. Я предполагал, что это будет быстрее, и, возможно, здесь я ошибаюсь. Это должно быть быстрее, чем это?
Дальнейшая проверка
Я еще немного углубился в статистику, взглянув на эти две строки в методе get_count:
all_keys = GeneralCounterShardConfig.all_keys(name)
for counter in ndb.get_multi(all_keys):
Если я закомментирую строку get_multi, я увижу, что существует 20 вызовов RPC от datastore_v3.Get общей продолжительностью 185 мс.
Как и ожидалось, это оставляет get_multi виновником 100 вызовов RPC от datastore_v3. Получить взятие свыше 2500 мс. Я проверил это, но здесь я запутался. Почему вызов get_multi с 20 ключами вызывает 100 вызовов RPC?
Обновление №1
Я проверил Traces в консоли GAE и увидел дополнительную информацию. Они там тоже показывают разбивку вызовов RPC - но в прицелах говорят "Пакетировать добирается, чтобы уменьшить количество удаленных вызовов процедур". Не уверен, как это сделать без использования get_multi. Думал, что сделал работу. Любой совет здесь?
Обновление №2
Вот несколько снимков экрана, на которых показана статистика, которую я просматриваю. Первая — моя базовая линия — функция без каких-либо встречных операций. Второй — после вызова get_count только для одного счетчика. Это показывает разницу в 6 RPC datastore_v3.Get.
После вызова get_count на одном счетчике
Обновление №3
По просьбе Патрика я добавляю скриншот информации из консольного инструмента трассировки.
get_multi
ndb не является простым выполнением одного вызова RPC. Если вы посмотрите, как get_multi() реализован, вы увидите, что он использует преимущества AutoBatcher. По умолчанию ndb должен быть готов объединить до 1000Get
s вместе, поэтому он должен обработать их все за вас. - person Patrick Costello   schedule 08.01.2016datastore_v3.Get
, она должна показать вам, сколько ключей задействовано в каждом вызове. В качестве примечания я бы отключил appstats, прежде чем делать это, так как Appstats также записывает в хранилище данных, поэтому отследить любые ошибки может быть сложнее. Не могли бы вы сообщить нам, как выглядят эти следы? - person Patrick Costello   schedule 08.01.2016