web-dev-qa-db-ja.com

MySQLは何百ものスリーププロセスで「データベース接続の確立エラー」エラーを発生させます

私はubuntuサーバー12、mysql innodb_version 5.5.49でLAMPをWordpressプラットフォーム(仮想化された3つのWebサイト)で実行しています。約2年間問題なく実行されていますが、エラー「データベース接続の確立エラー」エラー。他の仮想化サイトにも「最大接続超過」エラーが時々発生します。新しいプラグインやデータベースの変更はありません。

Rootとしてmysqlにログインしてshow full processlist;を実行すると、サイトのプライマリログインの1つだけによって生成された150のスリーププロセスのリストが表示されます。もちろん、150は私のmax_connections制限なので、これらのプロセスはサーバー全体を下にドラッグしています。それぞれが稼働している時間を考えると、約6が生成されているようです毎秒

私の問題は、トラブルシューティングのアイデアが不足していることです。私は確かにDBA初心者です。これが私がこれまでに試したことです:

  • サイトへの現在のトラフィックを調べて、攻撃を受けているかどうかを確認しました。そこには普通のものはありません。念のため、DNSが指す場所を少し変更しましたが、プロセスはまだ生成されていました。これは攻撃またはSQLインジェクションを除外すると思います。
  • Wait_timeout = 60の設定を試みましたが、プロセスの生成率を考えると、これでも十分ではありませんでした。変わりはない。
  • 更新されたWP、すべて無効化WPプラグインと切り替えられたテーマ。変更なし。AFAIK、WPは永続的なdb接続も使用しないので、 WP問題です。

とりあえず、1つのサイトで実行できる最大プロセスをmax_connectionsの50%に制限したので、他のサイトは実際に実行されています。この時点でほぼ何でも試してみてください。洞察をデバッグしてください。

これは、私が簡単に有効にしたMySQLログファイルの出力です。

7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 669
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 667
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 591
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 568
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 561
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 553
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 541
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 461
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 439
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 393
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 359
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 301
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 299
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 297
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 13
7990364 Query   SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 1

以下はその結果です。

EXPLAIN SELECT COUNT(*) FROM wp_postmeta WHERE meta_key = '_loved' AND post_id = 669;
 1 | SIMPLE      | wp_postmeta | ref  | post_id,meta_key | post_id | 8       | const |    5 | Using where

show create table wp_postmeta;からの結果

| wp_postmeta | CREATE TABLE `wp_postmeta` (
  `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `post_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `meta_value` longtext COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`meta_id`),
  KEY `post_id` (`post_id`),
  KEY `meta_key` (`meta_key`(191))
) ENGINE=InnoDB AUTO_INCREMENT=3360 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |

また:

innodb_buffer_pool_size: 134217728 
*************************** 1. row ***************************
           Name: wp_postmeta
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 1388
 Avg_row_length: 247
    Data_length: 344064
Max_data_length: 0
   Index_length: 131072
      Data_free: 72351744
 Auto_increment: 3360
    Create_time: 2016-04-22 13:46:34
    Update_time: NULL
     Check_time: NULL
      Collation: utf8mb4_unicode_ci
       Checksum: NULL
 Create_options: 
        Comment: 
1 row in set (0.00 sec)

データベースのサイズは約5MBです。

これは小さなDBですが、正直なところ、これはWPコードの問題である可能性があると思います。個々のクエリに長時間かかることではありませんが、max_connectionsが満たされることはチェックするたびに、max_connectionsは常に最大になります。

3
user255406

(表示されているクエリのみの部分的な回答です。これが修正されれば、他の違反者を特定できる可能性があります。)

_SELECT COUNT(*)
FROM wp_postmeta
WHERE meta_key = '_loved' AND post_id = 669
_

このクエリの場合、最適なインデックスは_(post_id, meta_key)_ですが、_meta_key_は_utf8mb4_文字セットでvarchar(255)として定義されているため、標準の設定ではそのようなインデックスは大きすぎます。

代わりに使用できます

_ALTER TABLE wp_postmeta ADD INDEX(`post_id`, `meta_key`(100));
_

最適ではありませんが、テーブルからアクセスする行を少なくすることで、パフォーマンスが少し向上するインデックスを作成します。

_innodb_large_prefix_ の設定を確認して変更すると、最適なインデックスを作成しようとする場合があります(ただし、マニュアルに記載されているように、行の形式についていくつかの追加要件があります)。これは、index-only ref accessにつながり、インデックスを使用してクエリを最適化できるのと同じくらい高速です。

1
jkavalik

本当にmeta_keyに191文字を超える値がありますか?そうでない場合は、次の変更を行います。

CREATE TABLE `wp_postmeta` (
  `meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `post_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `meta_key` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,  -- note length
  `meta_value` longtext COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`meta_id`),
  KEY `meta_key` (post_id, `meta_key`)  -- note compound, no "prefixing"
) ENGINE=InnoDB AUTO_INCREMENT=3360 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

これにより、特定のクエリを完全にインデックスで実行できるため、クエリの実行が速くなります。

(WP ought変更するものは他にもありますが、安全に変更することはできません。)

また、max_connectionsを20に下げます。150のクライアントが互いにつまずき、全員が終了するまでに時間がかかるのは意味がありません。

また、Webサーバーに許可されるクライアントの数を減らします。この場合も、20が妥当な場合があります。

0
Rick James