Использование LinkedBlockingQueue и сброс в MySQL - PullRequest
3 голосов
/ 03 января 2012

Подойдет ли связанный блокирующий запрос для следующего:

1. insert strings (maximum 1024 bytes) into the queue at a very high rate
2. every x inserts or based on a timed interval, flush items into mysql

Во время сброса я смотрел на API: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/LinkedBlockingQueue.html

Мне было интересно, что сток - это хороший выбор, так как я должен агрегировать перед промывкой.

Итак, я бы опустошил элементы в очереди, затем повторил и агрегировал, а затем записал в mysql.

Подойдет ли это для писателей со скоростью до 10K в секунду?

Нужно ли рассматривать какие-либо проблемы с блокировкой / синхронизацией или это уже решено?

Я буду хранить эту очередь связанных блокировок как значение в параллельной хэш-карте.

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

Ответы [ 2 ]

3 голосов
/ 03 января 2012

Бит немного зависит от того, является ли вставщик для каждой очереди или для всех очередей.Если я понимаю вашу спецификацию, я думаю, что сработает что-то вроде следующего.

Writer добавляет элемент в одну из LinkedBlockingQueue коллекций на вашей карте.Если размер очереди больше X (если вы хотите ее для каждой очереди), то это сигнализирует поток вставки MySQL.Примерно так должно работать:

queue.add(newItem);
// race conditions here that may cause multiple signals but that's ok
if (queue.size() > 1000) {
    // this will work if there is 1 inserter per queue
    synchronized (queue) {
        queue.notify();
    }
}
...

Затем вставщик ожидает в очереди и выполняет что-то вроде следующего цикла:

List insertList = new ArrayList();
while (!done) {
    synchronized (queue) {
        // typically this would be while but if we are notified or timeout we insert
        if (queue.size() < 1000) {
            queue.wait(MILLIS_TIME_INTERVAL);
        }
    }
    queue.drainTo(insertList);
    // insert them into the db
    insertList.clear();
}

Это становится немного сложнее, если есть 1поток делает вставки во всех очередях.Наверное, вопрос в том, почему у вас вообще есть ConcurrentHashMap?Если у вас есть 1 средство вставки, которое, например, вставляет в несколько таблиц или что-то еще, то вам понадобится механизм, чтобы сообщить вставке , какие очередь (и) должны быть опустошены.Это может просто пройти через все очереди на карте, но это может быть дорого.Вы бы синхронизировались на каком-либо объекте глобальной блокировки или, возможно, на объекте карты вместо очереди.

О, и, как упоминал @Peter Lawrey, вы быстро исчерпаете память, если ваша база данных будет медленнее, чем пишущие, поэтомуубедитесь, что для очередей задана правильная емкость, поэтому они ограничивают авторов и уменьшают рабочую память.

Надеюсь, это поможет.

1 голос
/ 03 января 2012

Для каждой очереди вам нужен поток и соединение, поэтому я бы не создавал слишком много очередей. Вы можете выполнять более 10 000 операций записи в секунду при условии, что ваш сервер MySQL может справиться с этим (вы узнаете об этом только при тестировании). LinkedBlockingQueue является потокобезопасным, и при условии, что все ваши очереди созданы перед запуском, вам не нужна блокировка / синхронизация. .

Если вы вставляете длинные строки длиной до 1024 символов со скоростью 10 Кбит / с, скорее всего вам не хватит памяти. (до 36 ГБ в час) Вместо этого я бы добавил в базу данных только новые строки.

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