状況によっては、シリアライズされたアクセスを必要とする機能があります。これは、アドバイザリロックを使用する良いケースのようです。しかし、かなり重い負荷の下で、私はシリアル化されたアクセスが発生していないと私は機能に同時にアクセスを見ていることを発見している。Postgresのアドバイザリロック機能で同時実行が可能
この機能の目的は、イベントの「在庫管理」を提供することです。意味することは、イベントが過度に過多にならないように、特定のイベントに対するチケットの同時購入を制限することを意図しています。これらは、アプリケーション/データベース内で使用される唯一のアドバイザリロックです。
イベントには、eventTicketMax値よりも多くのチケットが存在することがあります。これは、アドバイザリロックのために可能であるようには思われません。少量(またはロック取得後にpg_sleepなどの手作業で導入された遅延)でテストすると、正常に動作します。
- ジャンゴ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;
は、ここに私の環境設定ですAmazonで9.3.10 RDS
チューニングを試した追加の変数:
- 設定CONN_MAX_AGE pgbouncerを削除し、私のテストではDB
に直接接続
はい、これはまさに問題です。トランザクションレベルのロックに切り替えると、問題は解決しました。ありがとうございました! –