Вращающаяся эффективность коллекции MongoDB - PullRequest
0 голосов
/ 01 июля 2018

У меня есть коллекция MongoDB с примерно 20M объектами. Ночью я удаляю данные за несколько финансовых месяцев и заменяю их импортом из CSV, который использует PyMongo 3.0, что-то через Django. Этот импорт занимает все больше времени по мере роста базы данных, а сервер и процесс начинают время от времени зависать. Одно только удаление (6M строк) на наших серверах AWS занимает ~ 14 минут. Я проиндексировал удаление по дате, которое является соответствующим полем.

Запрос, который я использую для удаления:

db.getCollection("x").remove({date: {$gte: ISODate('2018-04-01')}})

Код верхнего уровня, интегрированный с Pymongo, в котором может быть небольшая утечка памяти:

        while keep_fetch:
            raw_data = input_adapter.get_bulk() # in practice pulling 100,000 lines.
            if raw_data is None:
                raise Exception("bulk of data didn't return due to error,remove all last inserted docs")
            if raw_data == {} or raw_data == [] :
                log.debug("no more data to fetch")
                keep_fetch = False
                break
            #check for maintenance before insert first bulk
            if first_bulk == True: # first run-through, execute a delete if there is data.
                first_bulk = False
                #clean data in db to avoid duplicates
                if 'maintain_before_insert' in dir(output_adapter):
                    # Call function that cleans a time period's data from the database, and does other maintenance.
                    if output_adapter.maintain_before_insert() == False:
                        raise Exception("collection maintenance failed") 
            #Run an input adapter that formats the data into a list for insertion into Mongo.
            list_docs=input_adapter.format_data( raw_data )
            #get last date for next task to start from
            last_date = max(list_docs, key=lambda x:x['date'])['date']           
            output_adapter.store_bulk( list_docs ) # Mongo insert; it uses unmodified insert_many on the collection
            gc.collect()

Мне любопытно, как я могу ускорить процесс. Я попытался выполнить массовое удаление без каких-либо улучшений. Мне любопытно, что индексы с истекшим сроком годности, но я не знаю, могут ли индексы с истекшим сроком действия остановиться, когда наш импорт устареет (после 3 полных месяцев просрочки он снова уменьшится до 2 и увеличится в размере на один день ночью)

Увеличение размера сервера AWS не влияет на скорость процесса. Мы используем сервер Django / Python для отправки запросов на удаление и вставку, и процессы вставки и удаления, похоже, занимают примерно одинаковое количество времени.

На сервере нет файла подкачки; Возможно, это проблема с настройкой сервера, и поэтому она больше подходит для ServerFault, но, поскольку это возможно, возникла ошибка кода, которую я задал здесь.

Я провел значительное количество исследований и попробовал несколько возможностей. Поможет ли обновление нашей версии PyMongo?

Данные процесса, Процесс 1

Показатели производительности при вставке одного (~ 675 МиБ) файла CSV: Загрузка файла из S3 bucket: .45 секунд Удаление записей (апрель-незаконченный июнь): 6 200 000 записей удалено в 14:18 Хранение записей: 100 000 записей вставляются каждые 11-12 секунд между [примечание: первые 100 000 записей загружаются в память Python перед удалением, поэтому цифры не являются точными] 20:15:21 и 20:32:11, всего Добавлено 16:50 и 6798155 записей

Размер таблицы после обработки: Количество: 19 367 660; Размер: 7,5 ГиБ, Размер хранилища: 3,6 ГиБ, Индексы: 2, Общий размер индекса: 486,3 МБ

Данные процесса, Процесс 2

Показатели производительности при вставке одного (~ 225 МиБ) файла CSV: Загрузка файла из S3 bucket: .5 секунд Удаление записей (апрель-незаконченный июнь): 2 399 827 записей удалено в 2:51 Хранение записей: 100 000 записей вставляются каждые 15 минут между [примечание: первые 100 000 записей загружаются в память Python перед удалением, поэтому цифры не являются точными] 20:37:10 и 20:43:37, всего Добавлено 6:27 и 2 417 669 записей

Размер таблицы после обработки: Количество: 6,332,293; Размер: 2,5 ГиБ, Размер хранилища: 1,1 ГиБ, Индексы: 3, Общий размер индекса: 264,3 МБ

Данные процесса, Процесс 3

Показатели производительности при вставке одного (~ 20 МиБ) файла CSV: Загрузка файла из S3 bucket: .03 секунд Удаление записей (апрель-незаконченный июнь): 341 317 записей удалено за 22 секунды Хранение записей: 100 000 записей вставляются каждые 21 секунду между [примечание: первые 100 000 записей загружаются в память Python перед удалением, поэтому цифры не являются точными] 20:44:46 и 20:45:17, всего Добавлено 0:31 и 349 100 записей

Размер таблицы после обработки: Количество: 811,200; Размер: 145,7 МБ, Размер хранилища: 75,6 МБ, Индексы: 3, Общий размер индекса: 23,4 МБ

Данные процесса, Процесс 4

Показатели производительности при вставке одного (~ 20 МиБ) файла CSV: Загрузка файла из S3 bucket: .5 секунд Удаление записей (апрель-незаконченный июнь): 352 010 записей удалено в: 09 Хранение записей: 100 000 записей вставляются каждые 8 ​​секунд между [примечание: первые 100 000 записей загружаются в память Python перед удалением, поэтому цифры не являются точными] 20:46:05 и 20:46:38, всего Добавлено 0:33 и 357 040 записей

Размер таблицы после обработки: Количество: 821,924; Размер: 217,7 МБ, Размер хранилища: 95,3 МБ, Индексы: 3, Общий размер индекса: 22,9 МБ

Примечание

Производительность кажется крайне нелинейной при удалении. Это выглядит очень похоже на то, что я должен как-то пакетировать удаления перед повторной индексацией, а я нет; могу ли я как-то «заблокировать» эту коллекцию для удаления и добавления (она не используется кроме этого процесса) или создать одну транзакцию, которая не позволяет индексу пересчитать промежуточный процесс, чтобы впоследствии он мог пересчитать его?

Запрошенная информация:

1) Наши серверы - это экземпляры EC2, работающие 18.04 на стороне Django / Python и 14.04 на стороне Mongo. Версия Mongo - 3.4.3, двигатель Wired Tiger.

2) Я проверил вывод объяснения (), и вывод JSON выглядит следующим образом:

    "winningPlan" : {
        "stage" : "FETCH", 
        "inputStage" : {
            "stage" : "IXSCAN", 
            "keyPattern" : {
                "date" : -1.0
            }, 
            "indexName" : "date_-1", 
            "isMultiKey" : false, 
            "multiKeyPaths" : {
                "date" : [

                ]
            }, 
            "isUnique" : false, 
            "isSparse" : false, 
            "isPartial" : false, 
            "indexVersion" : 2.0, 
            "direction" : "forward", 
            "indexBounds" : {
                "date" : [
                    "[new Date(9223372036854775807), new Date(1522540800000)]"
                ]
            }
        }

Мой вывод таков: индекс работает.

3) Поле 'date' проиндексировано, как и поле 'id'

4) Текущее оборудование на стороне Mongo - сервер Mongo t2.small или t2.medium. Обновление экземпляра с t1 до t2, по-видимому, мало повлияло на скорость удаления, хотя серверы среднего уровня не зависают, и это хорошо.

5) Том для каждого диска является облачным экземпляром gp2 AWS. Это теоретический предел в 160 МБ / с, строки, которые я добавляю, составляют 7,5 ГБ, а размер индекса составляет 486,3 МБ.

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