PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Опашка за задания като SQL таблица с множество потребители (PostgreSQL)

Използвам postgres и за FIFO опашка. Първоначално използвах ACCESS EXCLUSIVE, който дава правилни резултати при висок паралел, но има лошия ефект, че е взаимно изключващ се с pg_dump, който придобива заключване на ACCESS SHARE по време на неговото изпълнение. Това кара моята next() функция да се заключи за много дълго време (продължителността на pg_dump). Това не беше приемливо, тъй като ние сме 24x7 магазин и клиентите не харесваха мъртвото време на опашката посред нощ.

Реших, че трябва да има по-малко ограничително заключване, което все пак ще бъде едновременно безопасно и няма да се заключва, докато pg_dump работи. Моето търсене ме доведе до тази публикация SO.

След това направих малко проучване.

Следните режими са достатъчни за функция на FIFO опашка NEXT(), която ще актуализира състоянието на задание от на опашка за изпълнение без никакъв паралел се проваля, а също и да не блокира срещу pg_dump:

SHARE UPDATE EXCLUSIVE
SHARE ROW EXCLUSIVE
EXCLUSIVE

Запитване:

begin;
lock table tx_test_queue in exclusive mode;
update 
    tx_test_queue
set 
    status='running'
where
    job_id in (
        select
            job_id
        from
            tx_test_queue
        where
            status='queued'
        order by 
            job_id asc
        limit 1
    )
returning job_id;
commit;
UPDATE 1 job_id -------- 98 (1 row)

Ето един шел скрипт, който тества всички различни режими на заключване при висок едновременност (30).

#!/bin/bash
# RESULTS, feel free to repro yourself
#
# noLock                    FAIL
# accessShare               FAIL
# rowShare                  FAIL
# rowExclusive              FAIL
# shareUpdateExclusive      SUCCESS
# share                     FAIL+DEADLOCKS
# shareRowExclusive         SUCCESS
# exclusive                 SUCCESS
# accessExclusive           SUCCESS, but LOCKS against pg_dump

#config
strategy="exclusive"

db=postgres
dbuser=postgres
queuecount=100
concurrency=30

# code
psql84 -t -U $dbuser $db -c "create table tx_test_queue (job_id serial, status text);"
# empty queue
psql84 -t -U $dbuser $db -c "truncate tx_test_queue;";
echo "Simulating 10 second pg_dump with ACCESS SHARE"
psql84 -t -U $dbuser $db -c "lock table tx_test_queue in ACCESS SHARE mode; select pg_sleep(10); select 'pg_dump finished...'" &

echo "Starting workers..."
# queue $queuecount items
seq $queuecount | xargs -n 1 -P $concurrency -I {} psql84 -q -U $dbuser $db -c "insert into tx_test_queue (status) values ('queued');"
#psql84 -t -U $dbuser $db -c "select * from tx_test_queue order by job_id;"
# process $queuecount w/concurrency of $concurrency
case $strategy in
    "noLock")               strategySql="update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "accessShare")          strategySql="lock table tx_test_queue in ACCESS SHARE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "rowShare")             strategySql="lock table tx_test_queue in ROW SHARE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "rowExclusive")         strategySql="lock table tx_test_queue in ROW EXCLUSIVE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "shareUpdateExclusive") strategySql="lock table tx_test_queue in SHARE UPDATE EXCLUSIVE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "share")                strategySql="lock table tx_test_queue in SHARE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "shareRowExclusive")    strategySql="lock table tx_test_queue in SHARE ROW EXCLUSIVE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "exclusive")            strategySql="lock table tx_test_queue in EXCLUSIVE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    "accessExclusive")      strategySql="lock table tx_test_queue in ACCESS EXCLUSIVE mode; update tx_test_queue set status='running{}' where job_id in (select job_id from tx_test_queue where status='queued' order by job_id asc limit 1);";;
    *) echo "Unknown strategy $strategy";;
esac
echo $strategySql
seq $queuecount | xargs -n 1 -P $concurrency -I {} psql84 -U $dbuser $db -c "$strategySql"
#psql84 -t -U $dbuser $db -c "select * from tx_test_queue order by job_id;"
psql84 -U $dbuser $db -c "select count(distinct(status)) as should_output_100 from tx_test_queue;"
psql84 -t -U $dbuser $db -c "drop table tx_test_queue;";

Кодът също е тук, ако искате да редактирате:https://gist.github.com/1083936

Актуализирам приложението си, за да използвам режим ЕКСКЛУЗИВ, тъй като това е най-рестриктивният режим, който а) е правилен и б) не е в конфликт с pg_dump. Избрах най-рестриктивния, тъй като изглежда най-малко рисковано по отношение на промяната на приложението от ДОСТЪП ЕКСКЛУЗИВ, без да съм Uber-експерт в заключването на Postgres.

Чувствам се доста комфортно с моята тестова платформа и с общите идеи зад отговора. Надявам се, че споделянето на това ще помогне за решаването на този проблем за други.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Кога да използваме наследени таблици в PostgreSQL?

  2. Как да импортирате Heroku PG дъмп в локална машина

  3. Предайте множество набори или масиви от стойности към функция

  4. Как да приложим функция към всеки елемент от колона на масив в Postgres?

  5. ActiveRecord::AdapterNotSpecified конфигурацията на базата данни не посочва адаптер