मैं एक फीफो कतार के लिए भी पोस्टग्रेज का उपयोग करता हूं। मैंने मूल रूप से ACCESS EXCLUSIVE का उपयोग किया, जो उच्च संगामिति में सही परिणाम देता है, लेकिन pg_dump के साथ पारस्परिक रूप से अनन्य होने का दुर्भाग्यपूर्ण प्रभाव है, जो इसके निष्पादन के दौरान एक ACCESS SHARE लॉक प्राप्त करता है। यह मेरे अगले () फ़ंक्शन को बहुत लंबे समय (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-विशेषज्ञ होने के बिना ऐप को ACCESS EXCLUSIVE से बदलने के मामले में यह सबसे कम जोखिम भरा लगता है।
मैं अपने परीक्षण रिग और उत्तर के पीछे सामान्य विचारों के साथ बहुत सहज महसूस करता हूं। मुझे उम्मीद है कि इसे साझा करने से दूसरों के लिए इस समस्या को हल करने में मदद मिलेगी।