mysql長接続

6412 ワード

PHPのMySQLは持続的に接続して、すばらしい目標、悪い口コミを持っていて、往々にして敬遠させられます.これはいったいなぜですか.間近で観察してみると、こいつも大変だったな、Apacheの顔色を見るには、MySQLの指揮を聞かなければならない.
Apacheモジュールとして動作するPHPにとって、MySQLの永続化接続を実現するには、まずApacheというwebサーバがKeep-Aliveをサポートしているかどうかにかかっています.
Keep-Alive
Keep-Aliveって何?httpプロトコルの一部です.Keep-Aliveのないhttpリクエストを復習しましょう.お客様がブラウザに有効なurlアドレスを入力すると、ブラウザはsocketを利用してurl対応のwebサーバにTCPリクエストを送信します.このリクエストが成功するには、一度に3回手を握ってから確定しなければなりません.成功した後、ブラウザはsocket TCP接続リソースを利用してwebサーバにhttpプロトコルを要求し、送信後はwebサーバがhttp戻りヘッダとbodyを送信するのを待っていたが、送信後はブラウザがsocket接続を閉じ、http戻りヘッダとbodyの解析を行い、最後にブラウザに表示されたのはきれいなページだった.この中に何か問題がありますか?TCP接続には3回の握手が必要です.つまり、3回要求してTCP要求が成功したかどうかを確定し、TCPを閉じることができますか?往復4回のリクエストで完了!httpリクエストのたびに3回握手、4回バイバイというのは疲れませんが、どのくらいの時間とリソースがsocket接続閉鎖に浪費されているのか、一度にsocket TCP接続で何度もhttpリクエストを送信できますか?そこでKeep-Aliveが誕生し、http/1.0ではクライアント自身がリクエストヘッダにConnection:Keep-aliveを追加して実現する必要があります.ここではhttp 1のみを考慮します.1で、Apacheを設定するだけで、デフォルトではKeep-Alive永続接続モードになります(ApacheはKeep-Aliveをサポートするには1.2+が必要です).httpd.confではKeepAiveコンフィギュレーションアイテムが見つかり、果敢にOnに設定され、MaxKeepAliveRequestsは果敢に0に設定されています(永続TCPが最も許容されるリクエスト数は、小さすぎるとTCPが期限切れになっていない場合に、最大接続に達しやすくなります.次に接続するのは新しいTCP接続です.ここでは0を設定すると制限されません).そしてmysql_pconnectの最も重要なオプションKeepAliveTimeoutは15(15秒を示す)に設定されています.
はい、Apacheを再起動して、テストして、急いで行のものを書きます:
 
 

很简单,获取当前PHP执行者(Apache)的进程号,用浏览器浏览这个页面,看到什么?对,有看到一串进程号数字,15秒内,连续刷新页面, 看看进程号有无变化?木有吧?现在把手拿开,交叉在胸前,度好时间,1秒,2秒,3,...15,16。好,过了15秒了,再去刷新页面,进程号有没有变 化?变了!又是一个新的Apache进程了,为什么15秒后就变成新的进程了?记得我们在Apache里设置的KeepAliveTimeout吗?它的 值就是15秒。现在我们应该大致清楚了,在web服务器默认打开KeepAlive的情况下,客户端第一次http成功请求后,Apache不会立刻断开 socket,而是一直监听来自这一客户端的请求,监听多久?根据KeepAliveTimeout选项配置的时间决定,一旦超过这一时间,Apache 就会断开socket了,那么下次同一客户端再次请求,Apache就会新开一个进程来相应。所以我们之前15内不停的刷新页面,看到的进程号都是一致 的,表明是浏览器请求给了同一个Apache进程。

浏览器是怎么知道不需要重新进行TCP连接就可以直接发送http请求呢?因为http返回头里就会带上Connection:keep- alive,Keep-alive:15两行,意思就是让客户端浏览器明白,这次socket连接我这边还没关闭呢,你可以在15内继续使用这个连接,并 发送http请求,于是乎浏览器就知道应该怎么做了。

PHP怎么做

那么,PHP的MySQL连接资源是怎么被hold住的呢,这需要查看PHP的mysql_pconnect的函数代码,我看了下,大概的做法就 是mysql_pconnect根据当前Apache进程号,生成hash key,找hash表内有无对应的连接资源,没有则推入hash表,有则直接使用。有些代码片段可以说明(具体可查看PHP5.3.8源码 ext/mysql/PHP_mysql.c文件690行PHP_mysql_do_connect函数)

#1.  hash key user=php_get_current_user();//    PHP   (Apache)         //hashed_details  hash key hashed_details_length = spprintf(&hashed_details, 0, "MySQL__%s_", user); #2.         ,   hash ,   persistent_list,          if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_length+1, (void **) &le)==FAILURE) { ... ... Z_TYPE(new_le) = le_plink; new_le.ptr = mysql; if (zend_hash_update(&EG(persistent_list), hashed_details, hashed_details_length+1, (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)==FAILURE) { ... ... } } else { ... ... mysql = (PHP_mysql_conn *) le->ptr;//       sql     ... ... }

zend_hash_findの方がわかりやすいですが、原型はzend_hash_find(hashテーブル、key名、key長、value);見つかったらvalueに値があります.
MySQLのwait_timeoutとinteractive_timeout
Keep-Aliveって言ったら、MySQL家までお邪魔して、mysql_pconnect、どうしてMySQLの設定を迂回することができますか.影響mysql_pconnectの最も重要な2つのパラメータはwaitです.timeoutとinteractive_timeout、それらは何ですか?まず、上のコードをPHPコードに変更しましょう.
 
 

以上的代码没啥好解释的,让我们用浏览器浏览这个页面,看到什么?看到两个显眼的数字。一个是MySQL线程号,一个是Apache进程号,好 了,15秒后再刷新这个页面,发现这两个id都变了,因为已经是新的Apache进程了,进程id是新的,hash key就变了,PHP只好重新连接MySQL,连接资源推入persistent list。如果15内刷新呢?Apache进程肯定不变,MySQL线程号会变吗?答案得问MySQL了。首先这个MySQL_thread_id是什么 东西?shell方式登录MySQL后执行命令'show processlist;',看到了什么?

mysql> show processlist; +-----+------+-----------+------+--------+-----+------+-----------------+ | Id | User | Host | db | Command| Time| State| Info | +-----+------+-----------+------+--------+-----+------+-----------------+ | 348 | root | localhost | NULL | Query | 0| NULL | show processlist| | 349 | root | localhost | NULL | Sleep | 2| | NULL | +-----+------+-----------+------+--------+-----+------+-----------------+

重要な情報を発見しました.このprocesslistリストは走っているスレッドを記録しています.Infoがshow processlistとして列挙されている行を無視します.その行はあなたが現在shellでSQL MySQLにログインしているスレッドです.PHPがMySQLに接続するスレッドはIdが349の行で、もし読者が自分でテストをするならば、このId=349があなたのテスト環境の中で別の値であることを知っているべきで、私達はこの値とホームページの中で出力するMySQL_thread_id($conn)を比較しますね.彼らは同じです.次に最も重要なのはCommand列とTime列を観察することです.Command=Sleepは何を示していますか.mysql_を示すpconnect接続後ずっとsleepにいて、Timeフィールドは私たちに教えて、このスレッドSleepはどのくらい経って、それではSleepはどのくらいこのスレッドが無効になりますか?それがwait_timeoutまたはinteractive_timeoutがしなければならない仕事は、彼らのデフォルト値はすべて8時間で、ああ、長すぎるので、webサーバーがKeepAliveサポートをオフにすると、そのprocesslistは簡単に爆発して、そのToo many connectionsの間違いを爆発させました.max_connectiosnsはいくら配置しても役に立たない.この2つのパラメータを観察するために、MySQLプロファイルmy.cnfでこの2つの値を設定し、[MySQLd]ノードを見つけて、中で2行以上設定します
interactive_timeout = 60 wait_timeout = 30

構成が完了したら、MySQLを再起動し、shellはMySQLにログインし、show processlistは現在のスレッドのみを発見できます.mysqlが付いているものを実行しますpconnectのPHPページ、MySQL端show processlistに戻ると、CommondがSleepのスレッドが1つ増え、show processlist(方向キーに+enterキー)が止まらずTime列の変化を観察していることがわかります2,5,10...14!,突然あのSleepスレッドがkillに落ちて、どうしたんですか.まだ30秒も経っていません.Apache keepaliveのパラメータを修正するのを忘れて、KeepAliveTimeOutを15から120に変更し(観察のためだけに変更)、Apacheを再起動します.そのページをリフレッシュして、いいですね.ショーを続けます.5..10..14,15,..20...26....28,29!スレッドがkillされたのは、今回はwait_timeoutが機能し、ブラウザ側は30秒停止し、30内にブラウザがリフレッシュされると、このTimeはまた0から計時を開始します.この接続はinteractive connection(MySQL shellログインその接続はinteractive connection)ではないのでwait_を採用しましたtimeoutの値.mysql_pconnectの4番目のパラメータは変更します
下のページを更新して、MySQLのあちらはshow processlistをブラシすることを始めて、今度はTime>30もkillされないで、>60やっとkillされて、説明はMySQL_を設置しましたCLIENT_INTERACTIVEは、MySQLからinteractive connectionと見なされますが、今回のPHPのMySQL接続が120秒以内に更新されていない場合、いつ廃棄されるかは、SQL MySQLのinteractive_によって異なります.timeoutの構成値.
まとめ
PHPのmysql_pconnectが効果を達成するには、まずApacheがkeep aliveをサポートしていることを保証しなければならない.次にKeepAliveTimeOutはどのくらい設定すべきか.自分のサイトのアクセス状況に応じて調整しなければならない.時間が短すぎて、keep aliveは意味がない.時間が長すぎると、空きクライアントの接続のために多くのサーバー資源を犠牲にする可能性が高い.結局、holdはsocketリスニングプロセスを監視するのにcpuメモリを消費します.最後にApacheのKeepAliveTimeOutはMySQLのtime out構成と平衡点があるように構成されており、以上の観察に連絡してmysql_pconnectは4番目のパラメータを持っていません.ApacheのKeepAliveTimeOutが設定した秒数がwait_timeoutは小さくて、それは本当にmysqlに対してpconnectが機能するのは、MySQLの構成ではなくApacheです.このときMySQLのwait_timeoutが大きく、コンカレント量が大きい場合は、廃棄されたconnectionが山積みになる可能性が高い.MySQL側がタイムリーに回収しなければ、Too many connectionsになる可能性が高い.しかしKeepAliveTimeOutが大きすぎると、また前の質問に戻るので、Apacheのようです.KeepAliveTimeOuはあまり大きくないですが、MySQLより.wait_timeoutはやや大きいか、等しいのが良い案で、keep aliveが期限切れになった後、廃棄されたMySQL接続がタイムリーに回収されることを保証することができます.