2

プレーヤー統計用のカスタムPHPスクリプトがいくつかあるフラッシュゲームを埋め込んだDrupal7.2Webサイトを実行しています。CentOS 5.6 / 64ビット、PostgreSQL 8.4.8、およびPHP5.3を使用します。これは、4GBのRAMを搭載したクアッドオプテロンです。

ピーク時(オンラインで約500人のプレーヤーがいるとき)、私のWebサイトはポストマスタープロセスが多すぎてダウンしていました。pgsql-generalメーリングリストのアドバイスに従って、次の/etc/pgbouncer.iniを使用してpgbouncer1.3.4をインストールしました。

[databases]
pref = host=/tmp user=pref password=XXX dbname=pref

[pgbouncer]
logfile = /var/log/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid
listen_port = 6432
unix_socket_dir = /tmp

auth_type = md5
auth_file = /var/lib/pgsql/data/global/pg_auth

pool_mode = transaction
;pool_mode = session

server_check_delay = 10

max_client_conn = 200
default_pool_size = 16

log_connections = 0
log_disconnections = 0
log_pooler_errors = 1

そして、postgresql.confでshared_buffers = 1024MBを増やし、max_connections=50を減らしました。

これは役に立ちましたが、準備されたPDOステートメントが見つからないという問題がよくあります。

SQLSTATE[26000]: Invalid sql statement name: 7 ERROR: prepared statement "pdo_stmt_00000016" does not exist
  • おそらくpgbouncerがprepare()とexecute()の間の接続を切り替えるためです。

pgbouncerをセッションモードに切り替えることができません-私のWebサイトがハングします。

PDO :: ATTR_EMULATE_PREPARES=>trueを追加してみました-私のWebサイトもハングします。

各prepare()およびexecute()呼び出しの周りにbeginTransaction()とcommit()を追加しましたが、次のエラーが頻繁に発生します。

SQLSTATE[25P02]: In failed sql transaction: 7 ERROR:  current transaction is aborted, commands ignored until end of transaction block

以下は、そのエラーで失敗する私のコードの抜粋です-それは非常に簡単で、5つのSELECTステートメントを呼び出すだけです:

function fetch_top() {
        $table       = '';
        $top         = '';

        try {
                # throw exception on any errors
                $options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
                $db = new PDO(sprintf('pgsql:host=%s port=%u; dbname=%s',
                        DBHOST, DBPORT, DBNAME), DBUSER, DBPASS, $options);

                # last week's winner
                $db->beginTransaction();
                $sth = $db->prepare("
select u.id,
        u.first_name,
        u.avatar,
        u.female,
        u.city,
        m.money,
        u.login > u.logout as online
from pref_users u, pref_money m where
        m.yw=to_char(current_timestamp - interval '1 week', 'IYYY-IW') and
        u.id=m.id
order by m.money desc
limit 1
");
                $sth->execute();
                $winner = $sth->fetch(PDO::FETCH_OBJ);
                $db->commit();

                $db->beginTransaction();
                $sth = $db->prepare('
select count(id) from (
    select id,
           row_number() over(partition by yw order by money desc) as ranking
    from pref_money
) x
where x.ranking = 1 and id=?
');
                $sth->execute(array($winner->id));
                $winner_medals = $sth->fetchColumn();
                $db->commit();

                # current week leader
                $db->beginTransaction();
                $sth = $db->prepare("
select u.id,
        u.first_name,
        u.avatar,
        u.female,
        u.city,
        m.money,
        u.login > u.logout as online
from pref_users u, pref_money m where
        m.yw=to_char(current_timestamp, 'IYYY-IW') and
        u.id=m.id
order by m.money desc
limit 1
");
                $sth->execute();
                $leader = $sth->fetch(PDO::FETCH_OBJ);
                $db->commit();

                $db->beginTransaction();
                $sth = $db->prepare('
select count(id) from (
    select id,
           row_number() over(partition by yw order by money desc) as ranking
    from pref_money
) x
where x.ranking = 1 and id=?
');
                $sth->execute(array($leader->id));
                $leader_medals = $sth->fetchColumn();
                $db->commit();

                # fetch top players
                $db->beginTransaction();
                $sth = $db->prepare("
select u.id,
        u.first_name,
        u.female,
        u.city,
        m.money,
        u.login > u.logout as online
from pref_users u, pref_money m where
        m.yw=to_char(current_timestamp, 'IYYY-IW') and
        u.id=m.id
order by m.money desc
limit 7
");
                $sth->execute();
                $i = 0;
                while ($player = $sth->fetch(PDO::FETCH_OBJ)) {
                        $top .= user_link($player) . ($i++ > 0 ? '' : '&nbsp;&raquo;') . '<br />';
                }
                $db->commit();

                # create the HTML table
                $table = sprintf('.... skipped for brevity ....');
        } catch (Exception $e) {
                exit('Database problem: ' . $e->getMessage());
        }

        return $table;
}

何か助けてください?アレックス

4

3 に答える 3

1
  1. 使用するように構成pgbouncerするtransaction pooling
  2. PREPAREed ステートメントを作成する PL 関数を作成する
  3. PL 関数でpg_prepared_statementsシステム ビューをチェックし、不足しているステートメントがある場合はすべての準備済みステートメントを生成します。
  4. SQL コマンドの実行を次のように変更します。
    1. BEGIN
    2. SELECT create_prepared_statements();
    3. /* Do whatever it is that you would normally do */
    4. COMMIT

このまだ作成されていない PL 関数を呼び出す必要がある理由は、接続がどのバックエンドにディスパッチされているか、または話しているバックエンドが新たに生成され、 ed ステートメントcreate_prepared_statements()がないかどうかがわからないためです。PREPARE

'ed ステートメントの使用方法に応じて、 'ed ステートメントを自動的に生成してキャッシュする 's または PL 関数PREPAREを調べてください。PL/pgsql 関数をより積極的に使用することをお勧めしますが、それが維持するのが最も簡単な方法だからです。VIEWPREPARE

于 2011-06-23T19:29:51.840 に答える
1

トランザクションプーリング

このモードで準備済みステートメントを機能させるには、PgBouncer がそれらを内部的に追跡する必要がありますが、これは行いません。したがって、このモードで PgBouncer を使い続ける唯一の方法は、準備済みステートメントを完全に無効にすることです。

于 2011-06-23T19:08:56.427 に答える
1

私は PDO を使用しませんが、セッション モードで pgBouncer で準備済みステートメントを使用するとうまくいきます。preapred ステートメントが正しく機能するためには、「server_reset_query = DISCARD ALL」を設定するだけです。pool_mode を session に設定し、上記の変数も設定できますか?

于 2011-06-24T06:08:38.930 に答える