2015-11-06

[Lawson] おさいふ Ponta に移行してみました

2015/11/3
おさいふ Ponta をローソンでゲットしたので、会員登録を行おうとしました。最初のステップで届くメールが Gmail の迷惑メールフォルダに分類されましたが登録自体は問題なく完了しました。旧カードからの移行は障害中だったのであきらめました。

2015/11/4
次の日の晩、復旧のニュースを見たので早速移行申請し、2015/11/5 の昼頃見てみたら移行完了していました。

感想
Ponta 部分は特に変更なく、発行の敷居の低さに反して JCB デビット自体の機能は十分と思います。

おさいふ Ponta マイページから暗証番号の登録と J/Secure (JCB の本人認証サービス) の有効化が行えるので設定すると良いと思います。

ローソン店頭でおさいふ Ponta 決済をするときは、カードを出した時点でおさいふ Ponta で決済したい旨を伝えなかった場合は、Ponta カードのスキャンだけして返してくれました。

個別の移行手順
ローソンモバイル Ponta
Android 端末内蔵の FeliCa に登録するローソンモバイル Ponta の変更はローソンアプリからログアウトして、かざすフォルダのおさいふポンタを削除、ローソンアプリで新 Ponta ログイン、ログイン時にモバイル Ponta 登録オプションを有効にして更新できました。
参考: 5. 機種変更する場合はどうなりますか?

リクルートID
リクルートIDとの連携は旧 Ponta 側をコネクト解除して、新 Ponta 側とコネクトしました。これは即座に完了しました。
参考: Pontaコネクトを解除するにはどうすればよいですか。

JMB×Ponta会員
JMB×Ponta会員は旧 Ponta 側でログインし連係解除を行った後、3日目にようやく新カードでの連携に成功しました。ここの連携は日次バッチ?のようなので気長に待つ必要があるようです。
参考: Pontaカードを2枚持っているが、JMBとの登録カードを変更したい場合はどうすればよいですか?

2015-09-29

[isucon] ISUCON5 予選敗退しました

ISUCON5 予選に土曜日の日程で参加しました。チーム名は円山町、チームメンバーは @ymz_kotaro と2人です。主にアプリの改良を担当しました。午後6時半ごろのスコアは12000点ほどで予選敗退しました。

予選当日の流れは大体こんな感じでした。

午前11時~午後2時
何もいじらずにベンチマーク実行、タイムアウトでFAIL。
my.cnf の設定すべき個所に右往左往しながら innodb_buffer_pool = 1G を設定してようやくベンチマーク通過。
GoAccess で nginx のアクセスログを解析してアプリ宛にしかリクエスト来てないと判断し、nginx の設定は放置することとする。
Ruby 実装のまま MySQL にスロークエリログ 0.1 秒を仕込んで pt-query-digest 見る、インデックスなしのクエリを発見したのでひとまずインデックスを修正。
Go 実装に systemd の設定を切り替えてテスト、ベンチマークはエラー多数で FAIL。
エラー原因を目視確認しようとするが見つけられず。試しに一度 go build -o app を実行して再起動すると動くことを発見。
3回連続でベンチマーク正常を確認したのでGo実装を使うこととする。

午後2時~午後7時
Go実装のアプリにデバッグ用サーバー net/http/pprof を組み込んで再起動する。ベンチマークを流しながら go tool pprof で CPU プロファイルを取得し、top50 -cum で関数プロファイル、list GetIndex で行プロファイルを取得して遅い部分を解析
プロファイル上時間がかかっているように見える N+1 クエリを修正。
users テーブルへの書き込みがないので初期化時に全体をロードするいんちきオンメモリ化を施す。
全て修正完了したと思っていた N+1クエリについて、テンプレート関数経由でデータベースアクセスしている部分を発見したので修正。
テンプレートエンジンを高速化しようと試行錯誤するがいまいち早くならず終了。

午後7時時点でやり残したと思っていた点
html/template の使い方でリクエストごとにテンプレートを解析していたので何とかする
gorilla/muxjulienschmidt/httprouter に交換

翌日の反省点
クエリごとに毎回 relations テーブルと JOIN せずに、友達一覧を先にとって、各クエリで再利用したほうが有効なことが GoBoldチームさんのコード を見て気づく
ローカルストレージ遅いと聞いてからデータの安全性を犠牲にする感じの MySQL の設定を試していなかったことに気付く

リンク
ISUCON公式Blog
hidekiy/isucon5q - app.go

2015-08-01

Windows 10: EMET 5.2 有効下で Internet Explorer 11 が起動しない

Internet Explorer 11.0.10240.16384 と、EMET 5.2.5546.19547 の組み合わせで、Internet Explorer が起動時に音沙汰なくクラッシュします。

イベントビューアーの Windows ログ > Application には以下のようなログがありました。
障害が発生しているアプリケーション名: iexplore.exe、バージョン: 11.0.10240.16384、タイム スタンプ: 0x559f3a1c
障害が発生しているモジュール名: ntdll.dll、バージョン: 10.0.10240.16392、タイム スタンプ: 0x55a864a2
例外コード: 0xc0000409
障害オフセット: 0x00000000000963e0
障害が発生しているプロセス ID: 0x10c0
障害が発生しているアプリケーションの開始時刻: 0x01d0cbebdd651de2
障害が発生しているアプリケーション パス: C:\Program Files\Internet Explorer\iexplore.exe
障害が発生しているモジュール パス: C:\WINDOWS\SYSTEM32\ntdll.dll

EMET をアンインストールしても回避できますが、以下の公式サポートフォーラムに具体的な解決策がありました。
Emet 5.2 on windows10 10130 - Microsoft Community

EMET の設定画面を開いて、Configuration > Apps で、iexplorer.exe の EAF を無効化すると大丈夫みたいです。EAF+ は有効なままでも大丈夫でした。Default Action が Audit only になっていても EAF が有効だとクラッシュするようです。

この問題に関して、マイクロソフトにはクラッシュレポートが大量に送信されていると思うので、速やかに修正されると思います。問題の修正後はこの一時的な無効化を解除するため、デフォルトの設定にリセットすると安全と思います。

2015/10/7 追記
Windows 10 に正式に対応する EMET 5.5 Beta がリリースされていて、EAF を無効化しなくても Internet Explorer が起動するようになっていることを確認しました。

リンク
EMET 緩和策のガイドライン - アプリケーションごとに互換性のない緩和策が載っています
Enhanced Mitigation Experience Toolkit - EMET

2015-07-04

[Node.js] http client がリクエスト6回目以後ハングする

Node.js v0.10.x の http.globalAgent は、keepAlive = true, maxSockets = 5 になっているので、同一 Origin に対して5コネクション全てを腐らせるとハングします。

具体的には 公式ドキュメントの http.get のサンプルコード そのままで、複数回のリクエストを行うようにすると6回目以降必ずハングします。


var http = require('http');

setInterval(function () {
    http.get("http://www.google.com/index.html", function(res) {
        console.log("Got response: " + res.statusCode);
        // res.resume(); すれば OK
    }).on('error', function(e) {
        console.log("Got error: " + e.message);
    }); 
}, 1000);

この事情に関しては、Class: http.ClientRequest の章に丁寧に記述されているとおり、コールバック関数で受ける res は paused readable stream で、on data で内容を読むか、resume で捨てるかどちらかを必ず行う必要があります。

この状況の詳細なログを見るには、以下のように環境変数 NODE_DEBUG に http を入れるとデバッグログが出力されます。

$ node --version
v0.10.39

$ NODE_DEBUG=http node foobar.js

# 正しい場合の出力
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive

# ダメな場合の出力
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.

サンプルコードが間違っているという凶悪な状況だったので、この PR で修正してもらいましたが、今のドキュメントには反映されていないようなのでメモしておきました。

[raspberrypi] mackerel-agent を簡単に導入する

Raspbian を使っている場合、こちらの公式 GitHub mackerel-agent - Latest release
にて、以下のファイルをダウンロードします。バージョンは 2015/07/04 時点のものです。
mackerel-agent_0.17.1-1_all.deb
mackerel-agent_linux_arm.tar.gz

deb パッケージをインストールします

sudo dpkg -i mackerel-agent_0.17.1-1_all.deb

この状態だと設定ファイル類は正しく存在するのですが肝心のバイナリが i386 になっていて正常に動作しません。

$ file /usr/local/bin/mackerel-agent
/usr/local/bin/mackerel-agent: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

この状態で起動しようとしたとき、/var/log/mackerel-agent.log には以下のような出力がありました。

/usr/local/bin/mackerel-agent: 1: /usr/local/bin/mackerel-agent: <E0>^G^H4<F4>4: not found
/usr/local/bin/mackerel-agent: 1: /usr/local/bin/mackerel-agent: ^?ELF^A^A^A^B^C^A<96>^A@<E0>^B^F^PQ<E5>td^F^D<80>^U^De*^D^A^A^F
<8C>^D^H^LP<84>: not found
/usr/local/bin/mackerel-agent: 2: /usr/local/bin/mackerel-agent: Syntax error: word unexpected (expecting ")")

arm のバイナリに上書きします。

$ tar zxf mackerel-agent_linux_arm.tar.gz
$ sudo cp mackerel-agent_linux_arm/mackerel-agent /usr/local/bin
$ file /usr/local/bin/mackerel-agent
/usr/local/bin/mackerel-agent: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped

これで /etc/mackerel-agent/mackerel-agent.conf に apikey を設定すれば動作するはずです。

各種ファイルがある場所

起動スクリプト /etc/init.d/mackerel-agent
設定ファイル /etc/mackerel-agent/mackerel-agent.conf
ログ /var/log/mackerel-agent.log

リンク
Mackerel(マカレル): 新世代のクラウドパフォーマンス管理・監視ツール