2016-05-05 5 views
5

मुझे एक समस्या का सामना करना पड़ रहा है जहां मेरे पास एक ऐसा कार्य है जिसका उद्देश्य कुछ परिस्थितियों पर निर्भर धारावाहिक पहुंच की आवश्यकता है। यह सलाहकार ताले का उपयोग करने के लिए एक अच्छा मामला लग रहा था। हालांकि, काफी भारी भार के तहत, मुझे लगता है कि धारावाहिक पहुंच नहीं हो रही है और मैं फ़ंक्शन के समवर्ती उपयोग को देख रहा हूं।पोस्टग्रेस सलाहकार लॉक के भीतर लॉक समवर्ती निष्पादन

इस फ़ंक्शन का उद्देश्य किसी ईवेंट के लिए "सूची नियंत्रण" प्रदान करना है। मतलब, यह किसी दिए गए कार्यक्रम के लिए समवर्ती टिकट खरीद को सीमित करना है, जैसे कि ईवेंट ओवरलोड नहीं किया जाता है। यह एप्लिकेशन/डेटाबेस के भीतर उपयोग किए जाने वाले एकमात्र सलाहकार ताले हैं।

मुझे लगता है कि कभी-कभी ईवेंट टिकटमैक्स मान की तुलना में किसी ईवेंट में अधिक टिकट होते हैं। ऐसा लगता है कि सलाहकार ताले के कारण यह संभव नहीं होना चाहिए। कम मात्रा के साथ परीक्षण करते समय (या लॉक प्राप्त करने के बाद pg_sleep जैसे मैन्युअल रूप से पेश की गई देरी), चीजें अपेक्षा के अनुसार काम करती हैं।

  • Django 1.8.1 (django.db.backends.postgresql_psycopg2 डब्ल्यू/CONN_MAX_AGE 300)
  • PGBouncer 1.7.2 (सत्र मोड)
  • Postgres:

    CREATE OR REPLACE FUNCTION createTicket(
         userId int, 
         eventId int, 
         eventTicketMax int 
        ) RETURNS integer AS $$ 
         DECLARE insertedId int; 
         DECLARE numTickets int; 
        BEGIN 
          -- first get the event lock 
          PERFORM pg_advisory_lock(eventId); 
    
          -- make sure we aren't over ticket max 
          numTickets := (SELECT count(*) FROM api_ticket 
           WHERE event_id = eventId and status <> 'x'); 
    
          IF numTickets >= eventTicketMax THEN 
           -- raise an exception if this puts us over the max 
           -- and bail 
           PERFORM pg_advisory_unlock(eventId); 
           RAISE EXCEPTION 'Maximum entries number for this event has been reached.'; 
          END IF; 
    
          -- create the ticket 
          INSERT INTO api_ticket (
           user_id, 
           event_id, 
           created_ts 
          ) 
          VALUES (
           userId, 
           eventId, 
           now() 
          ) 
          RETURNING id INTO insertedId; 
    
          -- update the ticket count 
          UPDATE api_event SET ticket_count = numTickets + 1 WHERE id = eventId; 
    
          -- release the event lock 
          PERFORM pg_advisory_unlock(eventId); 
    
         RETURN insertedId; 
        END; 
        $$ LANGUAGE plpgsql; 
    

    यहाँ मेरी वातावरण सेटअप है 9.3.10 अमेज़न आरडीएस पर

अतिरिक्त चर जो मैं ट्यूनिंग की कोशिश की:

  • सेटिंग CONN_MAX_AGE 0 pgbouncer निकाला जा रहा है और डीबी

को सीधे जोड़ने मेरी परीक्षण में करने के लिए

  • , मैं देखा है कि ऐसे मामलों में जहां एक घटना ओवरसोल्ड था में, टिकट बहुत अलग वेबसर्वर से खरीदे गए थे मुझे नहीं लगता कि साझा सत्र के बारे में कोई मजाकिया व्यवसाय है लेकिन मैं निश्चित रूप से नहीं कह सकता।

  • उत्तर

    3

    जैसे ही PERFORM pg_advisory_unlock(eventId) के रूप में क्रियान्वित किया जाता है, एक और सत्र कि ताला हड़पने सकता है, लेकिन # 1 सत्र के सम्मिलित रूप में अभी तक प्रतिबद्ध नहीं है, यह खत्म हो गया-बुकिंग में जिसके परिणामस्वरूप सत्र # 2 की COUNT(*) में गिना जा नहीं होगा, ।

    यदि सलाहकार लॉक रणनीति को ध्यान में रखते हैं, तो आपको सत्र-स्तर के विपरीत लेनदेन-स्तर सलाहकार ताले (pg_advisory_xact_lock) का उपयोग करना चाहिए। उन ताले COMMIT समय पर स्वचालित रूप से जारी किए जाते हैं।

    यह भी ध्यान दें कि लेनदेन अलगाव स्तर महत्वपूर्ण है। डिफ़ॉल्ट पोस्टग्रेस REPEATABLE READ का उपयोग करता है और यह एक त्वरित नज़र से लगता है कि Django उस से नहीं निकलता है। आपके लेनदेन शुरू होने पर राज्य के बजाए अंतिम प्रतिबद्ध राज्य को प्रतिबिंबित करने के लिए आपके COUNT(*) के लिए यह महत्वपूर्ण है।

    +0

    हां, यह बिल्कुल समस्या है। लेनदेन स्तर ताले पर स्विचिंग ने इस मुद्दे को हल किया है। धन्यवाद! –

    संबंधित मुद्दे