ActiveRecordのestablish_connectionに気をつけろ
Rails3.1.3の話。
別DBにつなぐときの、ActiveRecordのestablish_connectionに気をつけろ。やつは1クラスごとに独自にdatabase.ymlのpool設定分のコネクションプールを作るぞッ。プールの意味ない!!
マスターDB1台で運用しているときは全然問題ない。コネクションプールは大変賢く働いてくれる。だが、2台目を運用し始めたとき、安易にestablish_connectionでつなぐと簡単に too many connections で、落ちる。
たとえば、ワーカー10個で、establish_connectionで別DB「hoge_db」に接続することにしたクラスが10個あったとしよう。その別DBへの接続設定(database.yml)で 「pool: 5」 としたとしよう。
そしてワーカーを立ち上げたとき、hoge_dbへのコネクション数はみるみるふくれあがり、ワーカー数(10)×establish_connection利用のクラス数(10)×pool設定数(5)で、実に500 100個のコネクションを張るぞ!
対応策としては、下記の4とおりが考えられる。
A、別DBのdatabase.yml設定はpoolを1に設定する。 (急場しのぎ。応急処置レベル。ちなみに0にはできないらしい)
B、コネクションプールをやめる 【参考】http://d.hatena.ne.jp/hxmasaki/20100812/1281588958
C、別DBへのコネクションプールを引き受けるクラスを作って継承する。 【参考】http://d.hatena.ne.jp/rudeboyjet/20101221/p1
D、適宜Rails.configuration.database_configuration の設定を変えて運用してみる。 【参考】http://yaplog.jp/gmodev/archive/71
いま、急場しのぎでAの対応をしている。根本解決として有望なのは、CかDかなぁと思う。どちらにしてもよく検証しないとなぁ。
Bは、ケースによってはアリだけど、僕のケースでは採用できないかな、と。
どっかに落ちてないのかな、解決済みのアイテムが。。。
【追記:2012/4/30】
Dの解決方法は、結局 establish_connection してるので、今回の地獄を解決してくれない。ので、Cの方法がたった一つの冴えたやり方っぽい。
【追記:2012/5/29】
コネクションはワーカー内でスレッドとか使って並列DBアクセスとかしない限りpool値分の接続を作ったりとかはしない模様。
Linuxでバッチのログを書き出し中のファイルを消して死ぬかと思ったが助かった話
諸事情で結構でかいデータの処理をすることになった。
かかる時間とかをログに出して計測しようと思って、標準出力をリダイレクトさせて放置してたんですわ。
んで、まあ、うっかり消しちゃった。
絶賛書き出し中の、そのファイルを。
一瞬死ぬかと思ったんだけど、ちょっと前になにかで、「プロセスがつかんでいるファイルはプロセスが生きてる間は実際には消えない」、って話を思い出したんです。
で、ググったら、あった。
削除したファイルをlsofで復元する http://www.itmedia.co.jp/enterprise/articles/0611/30/news007.html
方法はすごい簡単で、
これでまずファイルの実体を探して cp でコピーすればすくい上げ完了。
$ cp /proc/プロセス番号/fd/ファイル番号 hoge.rescue
僕のケースでは、まだバッチがログを書き出し続けているので、これを tail -f で継続抽出することにした。
なので、こんな感じ。
$ cp /proc/プロセス番号/fd/ファイル番号 hoge.rescue && tail -f /proc/プロセス番号/fd/ファイル番号 >> hoge.rescue &
末尾に「&」をつけてバックグラウンド実行させて、ssh抜けても大丈夫なようにした。
あとはこのファイルをまた間違って消さないようにしないとな!
なんにせよ、助かった。
ありがとう!
mysql2 アダプタなら、IDにBIGINTを使っても大丈夫。
諸事情でRailsのActiveRecordで使ってるテーブルのidがbigintだったりして、心臓が止まるかと思いました。
使ってるシステムは「Rails3 + mysql2」で助かった、というお話。
「rails bigint」でググるとでてくるんですが、Railsでidにbigintを使うと値が32ビットを超えたときに32ビット整数に丸められてしまうという問題があるわけです。
古いエントリですが、↓このへん。
http://d.hatena.ne.jp/troopergreen/20080409
http://d.hatena.ne.jp/ryu00026/20070320/1174412910
これはRails2時代の gem "mysql" アダプタで接続した場合の挙動です。
Rails3時代の今は、gem "mysql2" アダプタが標準で、これは上記の問題は克服されている模様。
アダプタのソースを見てみると、
"mysql"アダプタ(mysql-2.8.1\ext\mysql_api/mysql.c)
/* insert_id() */ static VALUE insert_id(VALUE obj) { return INT2NUM(mysql_insert_id(GetHandler(obj))); }
"mysql2"アダプタ(mysql2-0.3.11\ext\mysql2\client.c)
static VALUE rb_mysql_client_last_id(VALUE self) { GET_CLIENT(self); REQUIRE_OPEN_DB(wrapper); return ULL2NUM(mysql_insert_id(wrapper->client)); }
となっていて、「INT2NUM」が「ULL2NUM」に置き換わってます。
(INT2NUMとかULL2NUMとかはrubyのビルド用のマクロみたい)
で、MySQL側の値も my_ulonglong を返してくるので安心。
http://dev.mysql.com/doc/refman/5.1/en/mysql-insert-id.html
nginxでロードバランサー。httpとhttpsの両方で使う
仕事でhttpとhttps両方使う必要がでてきた。
サーバー構成は複数のアプリサーバーをロードバランサーで処理振り分けをする、よくあるタイプ。
問題はhttpsで、複数あるアプリサーバーにそれぞれSSL証明書をインストールすると、手間もかかるがお金もかかるので控えたい。
そこで、サーバー1台をロードバランサーとして仕立て上げ、そのサーバーにだけSSL証明書をインストールし、処理の振り分け先のアプリサーバーはすべてhttpで処理するといいんじゃないか、と考えた。
apacheでも同じこと出来ると思うが、軽量高速と評判
のnginxを使う。
なんと言っても、設定の単純さが際立つ。
nginx.conf 設定例 user nginx; worker_processes 1; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid; events { worker_connections 1024; } http { upstream tests { server 127.0.0.1:8000; server 127.0.0.1:8001; server 127.0.0.1:8002; } server { listen 80; server_name _; location / { proxy_pass http://tests; index index.html index.htm; } } server { listen 443; server_name _; ssl on; ssl_certificate /etc/pki/tls/certs/localhost.crt; ssl_certificate_key /etc/pki/tls/private/localhost.key; # ssl_session_timeout 5m; ssl_protocols SSLv2 SSLv3 TLSv1; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; location / { proxy_pass http://tests; index index.html index.htm; } } }
以上で設定おわり。
あとは振り分け先ががんばればよい。
設定のキモは、upstream セクションの振り分け設定に、server セクション内location ディレクティブで proxy_pass で向けているところ。
SSL用の server セクションも、listenが443なのと、ssl系の設定が追加してあるだけで、location内でporxy_pass を設定しているのは同じ。
超簡単。
特に設定しなくても、upstream内の振り分けメンバーが落ちたらちゃんと振り分け先から外してくれるし、復帰したら振り分け先に戻してくれる。
感動した。
nginx公式サイトの設定例:
http://wiki.nginx.org/NginxLoadBalanceExample
重み付けもできる
http://wiki.nginx.org/NginxHttpUpstreamModule#upstream
-
-
- -
-
追記
abコマンドでたたいてみたら、http側でのテストではnginxのCPU負荷は5%くらいでとっても余裕、https側のテストではnginxのCPU負荷90%とか行った。
SSLすげえ重いな。
nginx側はDTIのServersMan@VPS、ab側は自宅のノートPCのVMWarePlayerだから、あんまり結果に意味ないと思うけど、abテストの結果をのっけておく。
httpへのabテスト # ab -n 1000 -c 100 http://*********/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Server Software: nginx/0.8.55 Server Hostname: ************** Server Port: 80 Document Path: / Document Length: 5 bytes Concurrency Level: 100 Time taken for tests: 9.370 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 258000 bytes HTML transferred: 5000 bytes Requests per second: 106.72 [#/sec] (mean) Time per request: 937.032 [ms] (mean) Time per request: 9.370 [ms] (mean, across all concurrent requests) Transfer rate: 26.89 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 11 252 789.6 47 4436 Processing: 21 270 834.5 54 9021 Waiting: 21 263 832.8 52 9021 Total: 36 522 1303.5 102 9042 Percentage of the requests served within a certain time (ms) 50% 102 66% 115 75% 125 80% 132 90% 3069 95% 3161 98% 6139 99% 6151 100% 9042 (longest request)
httpsへのテスト # ab -n 1000 -c 100 https://*********/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Server Software: nginx/0.8.55 Server Hostname: ************** Server Port: 443 SSL/TLS Protocol: TLSv1/SSLv3,DHE-RSA-AES256-SHA,1024,256 Document Path: / Document Length: 5 bytes Concurrency Level: 100 Time taken for tests: 25.925 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Total transferred: 258000 bytes HTML transferred: 5000 bytes Requests per second: 38.57 [#/sec] (mean) Time per request: 2592.517 [ms] (mean) Time per request: 25.925 [ms] (mean, across all concurrent requests) Transfer rate: 9.72 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 351 2361 825.5 2400 8492 Processing: 21 113 94.1 95 855 Waiting: 20 108 85.3 93 854 Total: 521 2475 813.1 2499 8592 Percentage of the requests served within a certain time (ms) 50% 2499 66% 2642 75% 2789 80% 2906 90% 3115 95% 3291 98% 4578 99% 6458 100% 8592 (longest request)
-
-
-
-
-
- -
-
-
-
-
追記その2(2012/2/29)
最近のSSLって同じドメインなら何台にインストールしても追加料金なしなのがあるんだねー。
なら無理にロードバランサ側でSSL仕込まないほうがいいな。
MySQL5.5のcreate temporary tableが激烈遅い
ひどい目にあったので書く。
ストアドプロシージャベースで構築されたWEBシステムを、MySQL5.5に載せて運用を始めたところ、本稼働後数時間でデータベースのレスポンスが激烈に悪くなった。
別に破綻するほどアクセスが殺到した訳でもなく、サーバーのスペックが悪いわけでもなく、スロークエリのログにはストアド名がでるけど肝心の内部のクエリまでは見えない。
困ってプロセスリストをのぞくとcreate temporary tableがいっぱい詰まってるのが観測された。
一時テーブルをもっと多用した別のシステムでもこんな状況は見たことがない、ってことでどうもMySQL5.5の問題なのかもと推測。一時テーブルの設定(tmp_table_sizeなど)を変更してみたり、いろいろチューニングを試みるけど効果なし。
で、特に公式サイトとかに必要な設定とか注意点の情報も無く、ぐぐっても対処法が見あたらなかった(2ちゃんに1件だけ同じ事例があった)ので、やむを得ずMySQL5.1にダウングレードしたら嘘のように収束した。
バージョンはMySQL5.5.13、ダウングレード先はMySQL5.1.58。
MySQL5.5はいろいろすごくなってるんだよね? 一時テーブルだけひどくなるとか無いよね。。。
きっと設定があるはず。
もしくは将来直るはず。
頼むよ。
2013/8/15 追記
どうやら、MySQL5.5からデフォルトのストレージエンジンがInnoDBになったためらしい。
create tamporary table時に従来のMyISAMを明示的に指定してあげたら改善した模様。
Debian ( wheezy/sid ) で パスワードが変えられない
Debianサーバーをwheezy/sidにアップグレードしてみた。
んで、作業用アカウントhogeとかつくって、パスワード設定するじゃないですか。
passwd hoge
こんな風に。
そしたら、
Current Kerberos password:
とか聞かれて、そんなの設定してないのに! と大変困った。
rootのパスとか、空のままとか、適当に入れても当然だめで、
passwd: Authentication information cannot be recovered passwd: password unchanged
こんな風に蹴っ飛ばされます。
んで、検索したら同じ症状で困ってる人がいて、解決方法としてはKerberos認証とめちゃえ、ということのようだった。
aptitude remove libpam-krb5
でスッキリ解決(なのか?)
今回助けてもらったネタ元:
Debian Unstable (Sid) – Unable to Change Root Password
http://www.uncompiled.com/2009/10/debian-unstable-sid-unable-to-change-root-password/
Linuxサーバー設定メモ(OSチューニング)
Linuxサーバー(主にCentOS)のOSチューニングについて、メモをまとめておく。
自分がセッティングするときに好んで仕込むおまじない。
■午前四時の高負荷の原因を止める。
mlocateとかmakewhatisとかは行われる処理はサーバーの仕事自体には関係ない。
なので実行させないようにする。
※やってることは実行属性を消してるだけなので、動かしたいときは755にでもしてあげればOK
chmod 0 /etc/cron.daily/mlocate.cron chmod 0 /etc/cron.daily/makewhatis.cron chmod 0 /etc/cron.weekly/makewhatis.cron
Debianだとman-dbとかapt-xapian-indexとか。
■スワップ抑制
メモリぎりぎりまでスワップを我慢させる設定。
低いほどスワップしにくくなる。
変更:60(デフォルト)-> 0
・すぐに反映 echo 0 > /proc/sys/vm/swappiness ・再起動した時にも有効にする vi /etc/sysctl.conf # swap control vm.swappiness = 0
■【DB向け】IOキューサイズ変更
ディスクIOのキューサイズは低いほどレスポンス重視、高いほどスループット重視。
変更: 128(デフォルト) -> 1024
※設定対象はDBのデータがあるディスクデバイス
・すぐに反映 echo 1024 > /sys/block/ディスクデバイス名/queue/nr_requests ・再起動したときにも有効にする vi /etc/rc.local 上のコマンドを書いておく。
■【DB向け】IOスケジューラ
MySQL5.1のInnoDB pluginを使う場合、IOスレッドが多いので、デフォルトのcfqのままでよい。
MySQL5.1やMySQL5.0のビルトインInnoDBを使う場合は、noopかdeadlineにするとディスクIOの効率が向上する。
※設定対象はDBのデータがあるディスクデバイス。
※2014/2/11追記:最近、DB向けにはcfqよりdeadlineやnoopのほうが高負荷に強いという話をみたので、ハードウェアによって最適な設定は違う模様。SSDとかの超高速なディスクが出てきたからかなぁ。
・すぐに反映 echo deadline > /sys/block/ディスクデバイス名/queue/scheduler ・再起動したときにも有効にする vi /etc/rc.local 上のコマンドを書いておく。
■【DB向け】ファイルへの最終アクセスタイムを記録しないようにする
ファイルシステムがext3の場合の設定。
noatimeオプションを設定してあげるとファイルへの高頻度アクセスの負荷が減る。
※設定対象はDBのデータがあるパーティション
・すぐに反映 mount -o remount,noatime /dev/パーティション名 マウントポイント名 ・再起動したときにも有効にする vi /etc/fstab /dev/パーティション名 マウントポイント名 ext3 defaults,noatime 2