একই ফাংশনে একযোগে কল: ডেডলকগুলি কীভাবে ঘটছে?


15

আমার ফাংশনটি new_customerওয়েব অ্যাপ্লিকেশন দ্বারা প্রতি সেকেন্ডে কয়েকবার (তবে প্রতি সেশনে কেবল একবার) ডেকে আনা হয়। এটি প্রথমে যা করে তা হ'ল customerটেবিলটি লক করা ('উপস্থিত না থাকলে একটি সন্নিবেশ করানো' - এটির একটি সহজ রূপ upsert)।

দস্তাবেজ সম্পর্কে আমার উপলব্ধি হ'ল new_customerপূর্ববর্তী সমস্ত কল শেষ না হওয়া পর্যন্ত অন্যান্য কলগুলিতে কেবল সারি করা উচিত:

লক টেবিলটি কোনও বিবাদমান লকগুলি প্রকাশের প্রয়োজন হলে অপেক্ষা করে একটি টেবিল-স্তরের লক গ্রহণ করে।

এর পরিবর্তে এটি কেন কখনও কখনও অচল হয়ে পড়ে?

সংজ্ঞা:

create function new_customer(secret bytea) returns integer language sql 
                security definer set search_path = postgres,pg_temp as $$
  lock customer in exclusive mode;
  --
  with w as ( insert into customer(customer_secret,customer_read_secret)
              select secret,decode(md5(encode(secret, 'hex')),'hex') 
              where not exists(select * from customer where customer_secret=secret)
              returning customer_id )
  insert into collection(customer_id) select customer_id from w;
  --
  select customer_id from customer where customer_secret=secret;
$$;

লগ থেকে ত্রুটি:

2015-07-28 08:02:58 বিএসটি বিবরণ: প্রক্রিয়া 12380 ডাটাবেস 12141 এর 16438 সম্পর্কের উপর এক্সক্লুসিভ লকের জন্য অপেক্ষা করছে; প্রক্রিয়া দ্বারা ব্লক করা হয়েছে 12379।
        প্রক্রিয়া 12379 ডাটাবেস 12141 এর 16438 সম্পর্কিত এক্সক্লুসিভ লকের জন্য অপেক্ষা করে; প্রক্রিয়া দ্বারা ব্লক করা 12380।
        প্রক্রিয়া 12380: নতুন_কাস্টমারের নির্বাচন করুন (ডিকোড ($ 1 :: পাঠ্য, 'হেক্স'))
        প্রক্রিয়া 12379: নতুন_কাস্টমারের নির্বাচন করুন (ডিকোড ($ 1 :: পাঠ্য, 'হেক্স'))
2015-07-28 08:02:58 বিএসটি ইঙ্গিত: ক্যোয়ারী বিশদের জন্য সার্ভার লগ দেখুন।
2015-07-28 08:02:58 বিএসটি চুক্তি: এসকিউএল ফাংশন "new_customer" বিবৃতি 1
2015-07-28 08:02:58 বিএসটি বিবৃতি: নতুন_কাস্টমারের নির্বাচন করুন (ডিকোড ($ 1: পাঠ্য, 'হেক্স'))

সম্পর্ক:

postgres=# select relname from pg_class where oid=16438;
┌──────────┐
 relname  
├──────────┤
 customer 
└──────────┘

সম্পাদনা:

আমি একটি সহজ-ইশ প্রজননযোগ্য পরীক্ষার কেস পেতে সক্ষম হয়েছি। আমার কাছে এটি এক ধরণের রেসের শর্তের কারণে বাগের মতো দেখাচ্ছে।

স্কিমা:

create table test( id serial primary key, val text );

create function f_test(v text) returns integer language sql security definer set search_path = postgres,pg_temp as $$
  lock test in exclusive mode;
  insert into test(val) select v where not exists(select * from test where val=v);
  select id from test where val=v;
$$;

বাশ স্ক্রিপ্ট দুটি ব্যাশ সেশনে একই সাথে চলবে:

for i in {1..1000}; do psql postgres postgres -c "select f_test('blah')"; done

ত্রুটি লগ (সাধারণত 1000 কলের উপরে কয়েক মুখ্য অচলতা):

2015-07-28 16:46:19 BST ERROR:  deadlock detected
2015-07-28 16:46:19 BST DETAIL:  Process 9394 waits for ExclusiveLock on relation 65605 of database 12141; blocked by process 9393.
        Process 9393 waits for ExclusiveLock on relation 65605 of database 12141; blocked by process 9394.
        Process 9394: select f_test('blah')
        Process 9393: select f_test('blah')
2015-07-28 16:46:19 BST HINT:  See server log for query details.
2015-07-28 16:46:19 BST CONTEXT:  SQL function "f_test" statement 1
2015-07-28 16:46:19 BST STATEMENT:  select f_test('blah')

সম্পাদনা 2:

@ টাইপারউবটি ফাংশনের বাইরের সাথে একটি বৈকল্পিকের পরামর্শlock table দিয়েছে:

for i in {1..1000}; do psql postgres postgres -c "begin; lock test in exclusive mode; select f_test('blah'); end"; done

আকর্ষণীয়ভাবে এটি অচলাবস্থাগুলি দূর করে।


2
একই লেনদেনে, সেই ফাংশনে প্রবেশের আগে, এমনভাবে customerব্যবহার করা হয় যা কোনও দুর্বল লক ধরে ফেলবে? তাহলে এটি লক আপগ্রেড সমস্যা হতে পারে।
ড্যানিয়েল ভ্যারিট

2
আমি এটি ব্যাখ্যা করতে পারি না। ড্যানিয়েলের একটা কথা থাকতে পারে। এটি pgsql- জেনারেল উপর উত্থাপন মূল্যবান হতে পারে। যে কোনও উপায়ে, আপনি কি আসন্ন পোস্টগ্রেস 9.5-এ ইউপিএসআরটি বাস্তবায়ন সম্পর্কে সচেতন? Depesz এটি একবার দেখুন।
এরউইন ব্র্যান্ডসটেটার

2
আমার অর্থ একই লেনদেনের মধ্যে, কেবল একই অধিবেশন নয় (যেমন লক্সটি টিএক্স শেষে প্রকাশিত হয়)। @ অ্যালেক্সের উত্তরটি আমি যা ভাবছিলাম তা হ'ল, তবে যদি টিএক্স শুরু হয় এবং ফাংশনটি দিয়ে শেষ হয়, যা অচলাবস্থার ব্যাখ্যা দিতে পারে না।
ড্যানিয়েল ভ্যারিট

1
@ আরউইন আপনি নিঃসন্দেহে পোস্টসকিএল-বাগগুলিতে পোস্ট করে যে উত্তর পেয়েছেন তাতে আগ্রহী হবেন :)
জ্যাক বলছেন টপান্সওয়ার্স.অক্সিজ

2
সত্যিই খুব আকর্ষণীয়। অনুধাবন করে যে এটি plpgsql তেও কাজ করে, যেমনটি আমি মনে করি অনুরূপ পিএলপজিএসএইচএল ক্ষেত্রে প্রত্যাশার সাথে কাজ করে।
এরউইন ব্র্যান্ডসেটেটার

উত্তর:


10

আমি এটি পিএএসকিউএল-বাগগুলিতে পোস্ট করেছি এবং টম লেনের উত্তরটি ইঙ্গিত করে যে এটি এসকিউএল ল্যাঙ্গুয়েজ ফাংশনগুলি প্রক্রিয়াজাতকরণের যান্ত্রিক দ্বারা ছদ্মবেশযুক্ত, এটি একটি লক এসকেলেশন সমস্যা। মূলত, দ্বারা উত্পন্ন লক insertপ্রাপ্ত হয় সামনে টেবিলের উপর একচেটিয়া লক :

আমি বিশ্বাস করি যে এটির সাথে সমস্যাটি হ'ল কোনও এসকিউএল ফাংশন পুরো ফাংশন বডি একবারে একবারের জন্য পার্সিং করবে (এবং সম্ভবত এটিও পরিকল্পনা করছে; এখনই কোডটি পরীক্ষা করার মতো মনে করবেন না)। এর অর্থ হ'ল INSERT কমান্ডের কারণে আপনি ফাংশন বডি পার্সিংয়ের সময় "পরীক্ষা" টেবিলের উপর RowExclusiveLock অর্জন করেন, LOCK কমান্ড আসলে কার্যকর হওয়ার আগে। সুতরাং LOCK একটি লক বর্ধনের প্রচেষ্টা উপস্থাপন করে এবং ডেডলকগুলি প্রত্যাশিত।

এই কোডিং কৌশলটি plpgsql এ নিরাপদ হবে তবে কোনও এসকিউএল-ভাষা ফাংশনে নয়।

এসকিউএল-ল্যাঙ্গুয়েজ ফাংশনগুলিকে পুনর্নির্বাচিত করার বিষয়ে আলোচনা হয়েছে যাতে একবারে একটি করে বিবৃতি পার্সিং হয় তবে সেই দিক দিয়ে ঘটে যাওয়া কিছু নিয়ে আপনার দম আটকে রাখবেন না; এটি কারও পক্ষে উচ্চ অগ্রাধিকারের বিষয় বলে মনে হচ্ছে না।

শুভেচ্ছা, টম লেন

এটিও ব্যাখ্যা করে যে কেন একটি মোড়ানো পিএলপজিএসকিএল ব্লকে ফাংশনের বাইরে টেবিলটি লক করা ( @ সাইপারকিউ দ্বারা প্রস্তাবিত ) অচলাবস্থা রোধ করে।


3
ফাইন পয়েন্ট: ypercube আসলে প্লেইন SQL এর যে একটি লক পরীক্ষিত একটি সুনির্দিষ্ট লেনদেনে বাহিরে একটি ফাংশন, যা না একটি হিসাবে একই plpgsql ব্লক।
এরউইন ব্র্যান্ডসটেটার

1
বেশ ঠিক আছে, আমার খারাপ। আমি মনে করি যে আমরা চেষ্টা করেছি এমন আরও একটি জিনিস নিয়ে আমি বিভ্রান্ত হয়ে পড়েছিলাম (যা অচলাবস্থা রোধ করে না)।
জ্যাক বলছেন topanswers.xyz

4

ধরে নিই যে আপনি নতুন_কাস্টমোরকে কল করার আগে আপনি অন্য একটি বিবৃতি চালাচ্ছেন এবং যারা লক অর্জন করে যা EXCLUSIVE(মূলত গ্রাহকের সারণীতে কোনও ডেটা সংশোধন) এর সাথে দ্বন্দ্ব করে , ব্যাখ্যাটি খুব সহজ simple

কেউ একটি সাধারণ উদাহরণ দিয়ে সমস্যা পুনরুত্পাদন করতে পারে (এমনকি কোনও ফাংশন সহ) না:

CREATE TABLE test(id INTEGER);

প্রথম অধিবেশন:

BEGIN;

INSERT INTO test VALUES(1);

২ য় অধিবেশন

BEGIN;
INSERT INTO test VALUES(1);
LOCK TABLE test IN EXCLUSIVE MODE;

1 ম অধিবেশন

LOCK TABLE test IN EXCLUSIVE MODE;

প্রথম সেশনটি সন্নিবেশ করানো হলে এটি ROW EXCLUSIVEএকটি টেবিলের লকটি অর্জন করে । ইতিমধ্যে 2 সেশনের চেষ্টাও ROW EXCLUSIVEলক পায় এবং লকটি অর্জন করার চেষ্টা করে EXCLUSIVEEXCLUSIVEলক দ্বন্দ্বের সাথে যেহেতু এটি প্রথম পর্বে অপেক্ষা করতে হবে ROW EXCLUSIVE। শেষ অবধি, প্রথম অধিবেশনটি হাঙ্গরগুলিতে ঝাঁপ দেয় এবং একটি EXCLUSIVEলক পাওয়ার চেষ্টা করে , কিন্তু যেহেতু লকগুলি ক্রমে অর্জিত হয়, তাই এটি দ্বিতীয় সেশনের পরে সারি করে। এটি, পরিবর্তে, 1 মের জন্য অপেক্ষা করে, একটি অচলাবস্থা তৈরি করে:

DETAIL:  Process 28514 waits for ExclusiveLock on relation 58331454 of database 44697822; blocked by process 28084.
Process 28084 waits for ExclusiveLock on relation 58331454 of database 44697822; blocked by process 28514

এই সমস্যার সমাধান হ'ল সাধারণত লেনদেনের প্রথম জিনিস হিসাবে যত তাড়াতাড়ি সম্ভব লকগুলি অর্জন করা। অন্যদিকে, পোস্টগ্রেএসকিউএল কাজের চাপের জন্য খুব বিরল কিছু ক্ষেত্রে কেবলমাত্র তালাবন্ধ প্রয়োজন, তাই আপনি উপস্থাপনটি করার পদ্ধতিটি পুনর্বিবেচনা করার পরামর্শ দিই (এই নিবন্ধটি দেখুন http://www.depesz.com/2012/06/10 / কেন-আপসেট-এত জটিল / )।


2
এটি সমস্ত আকর্ষণীয়, তবে ডিবি লগের বার্তাটি এমন কিছু পড়তে পারে: Process 28514 : select new_customer(decode($1::text, 'hex')); Process 28084 : BEGIN; INSERT INTO test VALUES(1); select new_customer(decode($1::text, 'hex'))যখন জ্যাক সবে পেয়েছিল: Process 12380: select new_customer(decode($1::text, 'hex')) Process 12379: select new_customer(decode($1::text, 'hex'))- ইঙ্গিত দেয় যে ফাংশন কলটি উভয় লেনদেনের মধ্যে প্রথম কমান্ড (যদি আমি কিছু মিস করছি না)।
এরউইন ব্র্যান্ডসটেটার

ধন্যবাদ, এবং আপনি যা বলেন তার সাথে আমি একমত, তবে এটি এই ক্ষেত্রে কারণ হিসাবে দেখা যাচ্ছে না। আমি আরও সংখ্যার পরীক্ষার ক্ষেত্রে প্রশ্নটি যুক্ত করেছি (যা আপনি নিজেরাই চেষ্টা করতে পারেন) এটি পরিষ্কার could
জ্যাক বলছেন topanswers.xyz

2
প্রকৃতপক্ষে দেখা যাচ্ছে যে আপনি লক বর্ধনের বিষয়ে ঠিক ছিলেন - যদিও প্রক্রিয়াটি সূক্ষ্ম
জ্যাক বলছেন টপান্সওয়ার্স.অক্সিজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.