2015-06-23 2 views
2

У меня есть DynamoDB, работающий в облаке AWS, и я заполняю его данными на регулярных (запланированных) базах. В принципе, один раз в час я получаю файл, который необходимо обработать, и результаты должны быть сохранены в базе данных.DynamoDB - очень медленные операции записи

Я использую следующий класс для обработки соединения DB и выполнять партию пишет:

public class DynamoDBService { 

    private final AmazonDynamoDB amazonDynamoDB = new AmazonDynamoDBClient(); 
    private final DynamoDBMapper mapper = new DynamoDBMapper(amazonDynamoDB); 

    @Value("${aws_region}") 
    private String region; 

    @PostConstruct 
    public void init() { 
    log.info("Region: {}", region); 
    amazonDynamoDB.setRegion(RegionUtils.getRegion(region)); 
    } 

    /** 
    * 
    * @param records 
    */ 
    public void saveRecord(final Collection<Record> records) { 
    log.info("Saving records..."); 

    // create table if necessary here 

    List<Record> recordsToSave = new ArrayList<Record>(100); 

    for (Record record : records) { 

     recordsToSave.add(record); 

    } 

    // save the records 
    List<FailedBatch> failedBatch = mapper.batchWrite(recordsToSave, new ArrayList<Record>()); 
    // process failed writes here 

    log.info("All records have been saved."); 
    } 
} 

Проблема заключается в том, что пишет мучительно медленно. Я прочитал документацию и увеличил пропускную способность (так что теперь она должна поддерживать более 300000 операций записи/час), но для обработки одного списка требуется приблизительно 15 минут. 8000 записей.

Я читал, что оптимальное количество записей в одной пакетной операции составляет 25 и размер одной записи ниже 1кб. Я тестировал его как на своем локальном компьютере (который, как я знаю, будет медленнее из-за трафика), так и в рабочей среде AWS, но результаты были довольно медленными. Есть ли способ, которым этот процесс может быть оптимизирован?

+0

Какова ваша обеспеченная пропускная способность для записи и что потребляется, когда вы это делаете? Вы получаете дросселирование на любом из этих вызовов (может быть превышена пропускная способность одного раздела) (http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html#GuidelinesForTables.DataUpload)? Вы пишете все эти записи в одном потоке (может быть привязано IO)? Вы пытались увеличить размер пула соединений? – mkobit

+0

Я настоятельно рекомендую запустить ваш код через профайлер (например: [JProfiler] (https://www.ej-technologies.com/download/jprofiler/files)), чтобы сузить проблему. Основываясь на предоставленной информации, это может быть что угодно - использование отдаленного региона (увеличение задержки), запись дросселирования, горячий хэш-ключ, проблемы с преобразованием ваших записей или что-то еще. Информация от профилировщика позволит вам узнать, где сосредоточить свое исследование. Кроме того, как выглядят ваши записи/таблица? Если у вас много записей с одним и тем же hashkey (или плохо определенным LSI/GSI), это может быть преступником. – Krease

ответ

3

Во-первых, чтобы у вас не было нескольких экземпляров DynamoDBMapper/client в нескольких потоках, сделайте как клиент Mapper, так и клиент AmazonDynamoDB статическим. Во-вторых, вы должны самозажиматься с помощью Guava RateLimiter или аналогичного. Установите скорость, равную количеству записей в секунду, которые вы предоставили в своей таблице, и приобретите 25 разрешений перед каждым вызовом batchWrite, если ваши элементы меньше 1 КБ. В-третьих, вы можете запускать вызовы mapper.batchWrite параллельно. 300000 записей в час составляют около 83 записей в секунду. Это означает, что у вашей таблицы, вероятно, есть 1 раздел, если объем данных, хранящихся в вашей таблице, меньше 10 ГБ (я предполагаю, что это правда). В-четвертых, вы можете уменьшить dynamodb.timeout в конфигурации клиента. Это может быть полезно, поскольку операция BatchWrite столь же скрыта, как и наиболее скрытая индивидуальная PutRequest в пакете. Вы также можете попробовать уменьшить или отключить повторы SDK.

Обратите внимание, что максимальное количество операций записи в секунду, поддерживаемых в разделе, равно 1000. Возможно, вы так много времени уделяли в прошлом, что вы разделили таблицу на IOPS. Если у вас есть схема Hash + Range, и вы пишете много элементов на один и тот же хэш-ключ, но разные клавиши диапазона, все эти записи переходят в один и тот же раздел. Таким образом, несмотря на то, что сумма всей емкости записи в вашей таблице может составлять 83 записи в секунду, возможно, у вас есть ситуация, когда у вас много разделов, а уровень подготовки на уровне раздела недостаточно для поддержки вашей нагрузки.

В этом случае возможны два подхода. Вы можете начать разделение хеш-ключей и использовать key1, key2, key3 и т. Д. В качестве хеш-ключей одного и того же логического «ключа» и использовать хеширование и модульное деление на клавише диапазона ваших элементов, чтобы решить, какой раздел хэш-ключа должен иметь элемент быть написано. Второй и предпочтительный вариант - оценить вашу схему, чтобы обеспечить равномерное распределение ваших записей в пространстве ключей хэш-диапазона.