メンチカツ

ロースカツが好きです

Amazon RDS for MySQL で Too many connections

長時間実行してるバッチアプリケーションで、RDSのMySQL
「Too many connections」て言うようになって困っていました。

MySQLの同時接続数 max_connections の設定値が足りないのかなと
思いきや、information_schema.PROCESSLIST の中身を見たら

mysql> SELECT * FROM information_schema.PROCESSLIST WHERE USER='user' and Command='Sleep' and TIME > 1000\G

*************************** 1. row ***************************
     ID: 66825542
   USER: user
   HOST: ip-01-23-45-67.ap-northeast-1.compute.internal:xxxxx
     DB: db
COMMAND: Sleep
   TIME: 4306
  STATE:
   INFO: NULL
*************************** 2. row ***************************
     ID: 66825357
   HOST: ip-01-23-45-67.ap-northeast-1.compute.internal:xxxxx
     DB: db
COMMAND: Sleep
   TIME: 4325
  STATE:
   INFO: NULL

(省略)

213 rows in set (0.00 sec)

大漁!大漁にある!

バッチの中で接続の切断/破棄が正しくできていないようです。

正しく切断/破棄できるよう、根本の調査が必要なのですが
取り急ぎ、長々と眠っているプロセスをkillします。

mysql> kill 66825542;
ERROR 1095 (HY000): You are not owner of thread 66825542

oh,

門前払いをくらいました。
killコマンド、スーパーユーザーしか実行できないようです。

調べたところ、RDSでは mysql.rds_kill および mysql.rds_kill_query
という、killコマンドの代わりになるものが提供されてました。

早速実行してみます。

mysql> CALL mysql.rds_kill(66825542);
Query OK, 0 rows affected (0.00 sec)

おお!
無事消えました!

詳しくはこちらをどうぞ

kill mysql thread
https://forums.aws.amazon.com/message.jspa?messageID=337243

10.8 Mountain Lion から 10.9 Mavericksへアップグレードしたらapacheのphpサイトが死んだ

バーチャルホストで用意してある複数のサイトのうち、htmlのサイトは平気なのに
phpのサイトだけ

[notice] child pid XXX exit signal Segmentation fault (11)

これがでる。

クラッシュレポートを見てみると、libphp5.soの読み込みの途中で息絶えてた。
アップグレードで再インストールされたApachePHPのバージョンが合ってない?
と思いphpのバージョンを5.5へあげてみる。

curl -s http://php-osx.liip.ch/install.sh | bash -s 5.5

んで、LoadModule php5_moduleを以下に変えてみた。

/usr/local/php5-5.5.XXXX/libphp5.so

結果、動作するようになった!と思いきや、アプリケーション内で使用してる
aws-sdkのSimpleDBのとこで

Maximum function nesting level of XXX reached, aborting!

を返す。

Fixed circular to string method in simplexml #39
https://github.com/amazonwebservices/aws-sdk-for-php/pull/39

PHP 5.3.10では出ないけど、PHP 5.4.7で発生するエラーらしい。
Fixed案件なのでSDKのバージョンを上げれば解決なんですが、ここはPHP
バージョンを5.3に落とすことにした。

curl -s http://php-osx.liip.ch/install.sh | bash -s 5.3

そしてlibphp5.soを5.3に差し替え。ようやく動作するようになりました。
ここまでありつくのに、gdbで動作させたり、その準備でXcodeのコマンド
ラインツールいれたりと無駄にすごい時間を費やしてしまった。

MySQLでDELETE IF EXISTSでおこられた

おこなの?

PRIMARY KEY (`key`,`value`) 

のテーブル

key value
1 hoge
1 fuga
2 hoge
3 fuga
4 hogefuga

で、値が「hoge」「fuga」のデータの値を「hogefuga」に統一したい。

key value
1 hogefuga
2 hogefuga
3 hogefuga
4 hogefuga

って形にしたいとき、

--「hoge」を「hogefuga」に更新
update テーブル set value = "hogefuga" where value = "hoge";

--「fuga」かつ同じkeyで「hogefuga」持ってるデータを削除
delete from テーブル where value = "fuga" and exists(
    select t2.* from テーブル t2 where t2.value = "hogefuga" and t2.key = t1.key
);
-- >>> おこられるorz

なもんでこうして対応

--「hoge」を「hogefuga」に更新
update テーブル set value = "hogefuga" where value = "hoge";

--「fuga」かつ同じkeyで「hogefuga」持ってるデータを「deleted」に更新
update テーブル t1
inner join (
    select key from テーブル where value = "hogefuga"
) t2
on t1.key = t2.key
set value = "deleted" where value = "fuga";

--「deleted」データを削除
delete from テーブル where value = "deleted";

なんか回りくどい

Apache CXF:RequestHandler.handleRequestのMessageの値

すぐ忘れるのでメモ

    for (Entry<String, Object> m : message.entrySet()) {
      System.out.println(m.getKey()+":");
      System.out.println("    "+String.valueOf(m.getValue()));
    }

した結果が↓

org.apache.cxf.message.Message.PROTOCOL_HEADERS:
    {Accept=[*/*], accept-encoding=[gzip,deflate,sdch], accept-language=[ja,en-US;q=0.8,en;q=0.6], cache-control=[no-cache], connection=[keep-alive], Content-Length=[999], content-type=[multipart/form-data; host=[example.com], user-agent=[Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML,like Gecko) Chrome/26.0.1410.64 Safari/537.31]}
path_to_match_slash:
    /v1/service/method
HTTP_CONTEXT_MATCH_STRATEGY:
    stem
http.service.redirection:
    null
org.apache.cxf.request.url:
    http://example.com/example-services/v1/service/method
org.apache.cxf.request.uri:
    /example-service/v1/service/method
org.apache.cxf.resource.method:
    public javax.ws.rs.core.Response com.example.api.service.v1.impl.exapmleMethod(java.lang.String,java.lang.String)
HTTP.REQUEST:
    org.apache.catalina.connector.RequestFacade@176f3f86
HTTP.CONFIG:
    org.apache.catalina.core.StandardWrapperFacade@8b3826f
org.apache.cxf.transport.https.CertConstraints:
    null
Accept:
    */*
org.apache.cxf.message.Message.PATH_INFO:
    /example-service/v1/service/method
org.apache.cxf.message.Message.BASE_PATH:
    /example-service/
org.apache.cxf.message.Message.IN_INTERCEPTORS:
    [org.apache.cxf.transport.https.CertConstraintsInterceptor@413849df]
org.apache.cxf.message.Message.QUERY_STRING:
    accesskey=xxxxxxxxxxxxxxxxx&token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
HTTP.RESPONSE:
    org.apache.catalina.connector.ResponseFacade@5679f0ec
org.apache.cxf.security.SecurityContext:
    org.apache.cxf.transport.http.AbstractHTTPDestination$2@5fb8424e
org.apache.cxf.request.method:
    DELETE
org.apache.cxf.async.post.response.dispatch:
    true
org.apache.cxf.configuration.security.AuthorizationPolicy:
    null
org.apache.cxf.message.MessageFIXED_PARAMETER_ORDER:
    false
org.apache.cxf.transport.Destination:
    org.apache.cxf.transport.servlet.ServletDestination@3a093ffa
http.base.path:
    http://example.com/example-service
Content-Type:
    multipart/form-data; boundary=----WebKitFormBoundaryhogehoge
    org.apache.catalina.core.ApplicationContextFacade@354753da
jaxrs.template.parameters:
    {FINAL_MATCH_GROUP=[/]}

RDSのmysqldumpで「Got errno 28 on write」

mysqldumpで大量データのダンプを取っていたら、

mysqldump: Got errno 28 on write

と言われてエラーしてしまった。
ぐぐると、ディスクがパンパンだから/tmpをrmして!とか書いてある。

でもRDSなのでrmできない...

と思ったら、パンパンなのはmysqldumpを実施してるクライアントのディスクだった。
というわけで、言われたとおりクライアントの不要なログ消したら直った。
あらやだ。

AWS SDKで、S3のバケット指定がうまくいかない

バケット名にドット(ピリオド)いれてませんか?

static final String BUCKET = "hoge.org";
 
AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(accessKey, secretKey));
client.setEndpoint("s3-ap-northeast-1.amazonaws.com");
client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));

URL url = client.getUrl(BUCKET, "file");
// 期待してる値 => https://s3-ap-northeast-1.amazonaws.com/hoge.org/file
// ところが!! => https://hoge.org.s3-ap-northeast-1.amazonaws.com/file


バケット名にドット(ピリオド)が入っていると、ドメインとして
扱われてしまうようです(aws-java-sdk 1.6.3で確認)。

バケットをドメインじゃなくてパスとして扱うようにするには、以下のように
します。

//java
AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(accessKey, secretKey));
client.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true));

//php
$client = new AmazonS3();
$client->path_style = true;

Apache + mod_sslで無駄足ふんだメモ

だっふんだ

ssl.confの設定方法は素晴らしい資料が星の数ほどあるので触れません。
ここでは、その素晴らしい資料に目を通してもなお、設定でしくじって
2時間くらい費やした残念な人のメモを残します。
環境はEC2(Amazon Linux)です。


ホスト名を変えよう

[warn] RSA server certificate is a CA certificate (BasicConstraints: CA == TRUE !?)
[warn] RSA server certificate CommonName (CN) `ip-10-XX-XX-XX' does NOT match server name!?

ホスト名が申請したコモンネームと違うと、ログに上のような警告がでます。
同じにしときましょう。

【参考】Linuxのホスト名を変更する

セキュリティグループは大丈夫ですか

ポートあけてないの、気付くまでに相当かかりました。
443 Listenして気が済んだみたいなかんじになっていました。


このたったふたつで時間をかけてしまいました。
反省を込めてブログで晒しておきます。