web-dev-qa-db-ja.com

キャッシュフォームテーブルのサイズが非常に大きい

キャッシュテーブルのサイズは先月10 GB以上に増加していたため、切り捨てて一時的に修正しました。前回確認したところ、1GB程度でした。したがって、数か月後には再び10GBに達します。これはどのように処理されるべきですか?

このサイトではすべてのcronジョブを無効にしていることに注意してください。これが理由である場合、どのcronを有効にする必要がありますか?

13
GoodSp33d

{cache_form}テーブルは少しおかしく、他のキャッシュテーブルとは少し異なる方法で動作します。

drupal_flush_all_caches() を見ると、{cache_form}がクリアされていないことがわかります。これは、進行中のフォームが中傷されるのを防ぐためです。

system_cron() 関数は、他のキャッシュテーブルとともに{cache_form}から古いデータを削除します。

すべてのDrupalサイトで実際に cron を実行する必要があります。{cache_form}テーブルが正確な場合、{watchdog}および{session}テーブルも同様です。他の多くのモジュールがハウスキーピングを実行します独自のアクティビティの一部 hook_cron() 関数。

また、問題のキューをざっと見回したい場合もあります。 {cache_form}にはいくつかのバグがあり、1つに遭遇している可能性があります。

24
mpdonadio

経験則:ウェブサイトのハウスキーピングでは、cronを定期的に実行する必要があります。

MPDへのコメントで、cronを設定して定期的に実行しているにもかかわらず、cache_formテーブルが急速に成長していると述べました。

これに対する1つの解決策は、cronをより頻繁に実行することです。6時間ごとに言うか、それともそれ以下ですか?あなたがそれをする余裕がない場合は、さらに読んでください。

代替ソリューション:

mymodule_cron() {
    cache_clear_all(NULL, 'cache_form');
}

Elysia Cron をインストールすると、モジュールのcron関数を個別に実行できるようになります。 Elysia cronの頻度を維持して、モジュールを6時間ごとに実行できます。 cache_formテーブルが6時間ごとにプルーニングされるようにします。

このプルーニングプロセス中、6時間以内のエントリは削除されません。その理由は、すべてのエントリが削除された場合、エントリの削除時に送信されたフォームが奇妙に動作する可能性があるためです。

https://api.drupal.org/api/drupal/includes!form.inc/function/form_set_cache/7 のコードを見てください。

function form_set_cache($form_build_id, $form, $form_state) {
  // 6 hours cache life time for forms should be plenty.
  $expire = 21600;

コメントを読むと、彼らはそれがたくさんあるべきだと仮定していて、あなたの場合にはそれはあなたにとってあまりにもたくさんなりつつあります。したがって、トリックはcache_formテーブルをより頻繁にクリアし、$ expireの値をより低い値に減らすことです。デフォルト値の6〜6時間よりも頻繁にcache_formエントリをクリアしたい場合は、TTL。

cacheboject をインストールしてhook_cacheobject_presaveを実装すると、TTLを2時間または3時間に変更できます。

mymodule_cacheobject_presave()($object, $cid, $bin) {
  // Extend the expiry period for prototype forms used in ajax enabled forms.                                                                  
  $cache_ttl = 1 ; // Change it to any number of hours
  if ($bin == 'cache_form') {
    $object->expire = REQUEST_TIME + $cache_ttl * 3600;
  }
}

このアプローチの欠点の1つは、フォームが2時間(設定したRTL値)以内に送信されない場合、フォームデータが失われ、フォームの期限切れの問題が発生する可能性があることです。

6
Gokul N K

Safe cache_form Clear モジュールを使用します。

まず、テーブルを適切なサイズにプルーニングしてから、それを維持します。

プロジェクトページからの抜粋:

限られた数のアイテムをcache_formテーブルから安全に削除します。

モジュールがインストールされたら、最初にPrune cache_form:テーブルサイズが一定になるまでdrush safe-cache-form-clearを実行します。これにより、6時間より古いすべてのレコードが削除されたことが示されます。

その後、cronで実行し続けます。

これは、サブスクライバ用のモジュール この目的のためにAcquiaによって文書化されています です。 Acquiaのドキュメントページには、優れた追加情報が記載されています。

1
Kay V

この問題の回避策として、モジュール https://www.drupal.org/project/session_cache_form を作成しました

1
impol

作業中のサイトでパフォーマンスの問題が発生していたときに、キャッシュを修正した後、これに遭遇しました。ここの記事を読むことができます: https://thinktandem.io/blog/2017/11/22/debugging-with-new-relic-blazemeter-strace-more/

私のブログ投稿から、キューとcron設定を追加し、次に Elysia Cron のようなものを使用して、すべてがうまく連携するようにすることができます。

/**
 * Implements hook_cron_queue_info()
 */
function THE MODULE_cron_queue_info() {
  // Set up the worker queue.
  $queues['THE MODULE_queue'] = array(
    'worker callback' => 'THE MODULE_queue_process',
    'time' => 600,
  );
  return $queues;
}

/**
 * Implements hook_cron()
 */
function THE MODULE_cron() {
  // Load up our worker queue.
  $queue = DrupalQueue::get('THE MODULE_queue');

  // Set up the query for expired results.
  $sql = "SELECT cid FROM {cache_form} WHERE expire < :time";
  $query = db_query($sql, array(':time' => REQUEST_TIME));
  $results = $query->fetchAll(PDO::FETCH_ASSOC);

  // Split this into chunks for safety and speed.
  $chunks = array_chunk($results, 5000);
  foreach ($chunks as $chunk) {
    // Add the chunk to the queue worker.
    $queue->createItem($chunk);
  }
}

/**
 * Worker callback defined in hook_cron_queue_info().
 *
 * @param array $data
 *   The array of cids we want to delete.
 */
function THE MODULE_queue_process($data) {
  db_delete('cache_form')
    ->condition('cid', $data, 'IN')
    ->execute();
}
1
John O