Конфликт данных ndb становится все хуже и хуже

У меня немного странная проблема. У меня есть модуль, работающий на gae, который помещает множество небольших задач в очередь задач по умолчанию. Задачи обращаются к одному и тому же модулю ndb. Каждая задача получает доступ к набору данных из нескольких разных таблиц, а затем вызывает put.

Первые несколько задач работают нормально, но со временем я начинаю получать их на последнем put:

suspended generator _put_tasklet(context.py:358) raised TransactionFailedError(too much contention on these datastore entities. please try again.)

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

Вот некоторый псевдокод для моей задачи:

def my_task(request):
    stuff = get_ndb_instances() #this accessed a few things from different tables
    better_stuff = process(ndb_instances) #pretty much just a summation
    try_put(better_stuff)
    return {'status':'Groovy'}

def try_put(oInstance,iCountdown=10):
    if iCountdown<1:
        return oInstance.put()
    try:
        return oInstance.put()
    except:
        import time
        import random 
        logger.info("sleeping")
        time.sleep(random.random()*20)
        return oInstance.try_put(iCountdown-1)

Без использования try_put очередь проходит около 30% пути, пока не перестанет работать. С try_put он увеличивается, например, на 60%.

Может ли быть так, что задача удерживает соединения ndb после того, как она каким-то образом завершилась? Я не использую явным образом транзакции.

РЕДАКТИРОВАТЬ:

кажется, есть некоторая путаница в том, что я спрашиваю. Возникает вопрос: почему со временем конкуренция за ndb становится все хуже. У меня одновременно выполняется множество задач, и они обращаются к ndb таким образом, что это может вызвать конкуренцию. Если конкуренция обнаружена, то происходит случайная повторная попытка по времени, и это прекрасно устраняет конкуренцию. В течение некоторого времени. Задачи продолжают выполняться и завершаться, и чем больше успешно возвращается, тем больше конфликтов. Хотя процессы, использующие оспариваемые данные, должны быть завершены. Что-то происходит, что держит дескрипторы хранилища данных, чего не должно быть? В чем дело?

РЕДАКТИРОВАТЬ2:

Вот немного о ключевых структурах в игре:

Мои модели ndb находятся в иерархии, где у нас есть что-то вроде этого (направление стрелок указывает родительские дочерние отношения, то есть: тип имеет кучу дочерних экземпляров и т. д.)

Type->Instance->Position

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

Я вычисляю кучу позиций, а затем делаю try_put_multi (очевидным образом похож на try_put) и получаю конкуренцию. Довольно скоро я снова запущу код и получу полную трассировку для включения сюда.


person Sheena    schedule 16.02.2016    source источник
comment
У вас действительно есть голый try/except?   -  person Tim Hoffman    schedule 16.02.2016
comment
Какая ключевая структура используется, какую ошибку конкуренции вы получаете?   -  person Tim Hoffman    schedule 16.02.2016
comment
@TimHoffman: Нет. Этот код является укороченной версией настоящего кода.   -  person Sheena    schedule 01.03.2016
comment
@TimHoffman: что касается типа разногласий, я не получаю много информации, кроме исключения, которое я вставил в свой вопрос выше. Я отредактирую, чтобы поговорить о ключевых структурах.   -  person Sheena    schedule 01.03.2016
comment
@BrentWashburne: я не верю, что это дубликат. проблема в том, что конкуренция со временем становится все хуже, даже несмотря на то, что количество процессов, работающих с данными, имеет жесткий верхний предел.   -  person Sheena    schedule 01.03.2016
comment
Вы случайно не видите, что количество экземпляров приложения за это время увеличивается?   -  person Dan Cornilescu    schedule 01.03.2016
comment
@DanCornilescu: я снова запущу этот материал и получу эти числа   -  person Sheena    schedule 01.03.2016
comment
От тысяч Instances до нескольких Types =› большие группы сущностей, каждая группа поддерживает максимум ~ 1 запись в секунду. Какова частота задач, обновляющих Instances для одного и того же родителя Type (т. е. одной и той же группы)? У вас есть threadsafe: true в конфигурации .yaml?   -  person Dan Cornilescu    schedule 01.03.2016


Ответы (1)


Конкуренция будет усиливаться со временем, если вы постоянно превышаете 1 запись/транзакцию на группу объектов в секунду. Ответ заключается в том, как работает Megastore/Paxo и как Cloud Datastore обрабатывает конфликты в серверной части.

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

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

Рандомизированный метод сна — это неправильный способ обработки ситуаций ответа на ошибку. Вместо этого вам следует изучить экспоненциальное отставание с дрожанием (пример).

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

person Dan McGrath    schedule 28.12.2016