LVS/DSR + iptablesで切断したコネクションが消えなくてハマった

LVS+DSRでMySQLサーバの参照を分散してRailsから接続してみたところ、
デプロイごとにMySQLのコネクションが増えていくという事象が発生してハマりました。
Railsの持続的なコネクションだとそもそもLVSで分散できねーだろ、ってツッコミは今回は無しでお願いします・・・

結論としてはLVS が FIN を落とすに書いてるとおり、LVSサーバのiptables設定がダメだったのですが、いちおう経緯を書いておきます。

iptables無しの状態

通常、MySQLに外部から接続すると

$ mysql -utest -ptest -h192.168.1.111 tmp_app_development

MySQLサーバ上にESTABLISHEDなコネクションが出来て、

[root@mysql01 ~]# netstat -an | grep 3306
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      
tcp        0      0 192.168.1.111:3306          192.168.1.61:49788          ESTABLISHED 

MySQLのプロセスリストが1つ増えます。

mysql> show processlist;
+----+------+--------------------+---------------------+---------+------+-------+------------------+
| Id | User | Host               | db                  | Command | Time | State | Info             |
+----+------+--------------------+---------------------+---------+------+-------+------------------+
| 34 | test | 192.168.1.61:49805 | tmp_app_development | Sleep   |   28 |       | NULL             |
| 37 | root | localhost          | NULL                | Query   |    0 | init  | show processlist |
+----+------+--------------------+---------------------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

そして、切断するとどっちも消える。

[root@mysql01 ~]# netstat -an | grep 3306
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN  
mysql> show processlist;
+------+------+--------------------+------+---------+------+-------+------------------+
| Id   | User | Host               | db   | Command | Time | State | Info             |
+------+------+--------------------+------+---------+------+-------+------------------+
| 2648 | test | 192.168.1.61:51120 | NULL | Query   |    0 | init  | show processlist |
+------+------+--------------------+------+---------+------+-------+------------------+
1 row in set (0.00 sec)

はずなんですが、、、

今回起こった事象

LVSサーバにiptablesを適用することになったので、こんな感じでMySQLの接続を許可する設定をいれました。

[root@lvs01 ~]# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT

そうするとデプロイするたびにMySQLサーバの接続数が増えていく。
APPサーバ側は異常はないんだけど、MySQLサーバで旧プロセスのコネクションが残ったままになってるっぽい。

簡単に確認するためにdatabase.ymlの接続先をLVSのVIPに切り替えて接続、切断してみる。

[mikeda@test01 tmp_app]$ ./bin/rails c
irb(main):001:0> User.first
irb(main):002:0> exit

切断しても、コネクションがESTABLISHEDのままで残っている・・・

[root@mysql01 ~]# netstat -an | grep 3306
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      
tcp        0      0 192.168.1.111:3306          192.168.1.61:49805          ESTABLISHED

MySQLのプロセスも消えずにどんどん溜まっていく・・・

mysql> show processlist;
+----+------+--------------------+------+---------+------+-------+------------------+
| Id | User | Host               | db   | Command | Time | State | Info             |
+----+------+--------------------+------+---------+------+-------+------------------+
| 34 | test | 192.168.1.61:49805 | tmp  | Sleep   |   28 |       | NULL             |
| 37 | root | localhost          | NULL | Query   |    0 | init  | show processlist |
+----+------+--------------------+------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

でもMySQLのwait_timeoutは変えたくない・・・

というわけで調査と対応

LVSサーバ、MySQLサーバで切断時のtcpdumpを取ってみると、

LVS側ではえんえんとFINパケットが届いているんだけど、

[root@lvs01 ~]# tcpdump -n port 3306
...
05:21:47.240436 IP 192.168.1.61.49822 > 192.168.1.111.mysql: Flags [F.], seq 390, ack 1871, win 618, options [nop,nop,TS val 8292014 ecr 8285790], length 0
05:21:47.441272 IP 192.168.1.61.49822 > 192.168.1.111.mysql: Flags [F.], seq 390, ack 1871, win 618, options [nop,nop,TS val 8292215 ecr 8285790], length 0
05:21:47.843234 IP 192.168.1.61.49822 > 192.168.1.111.mysql: Flags [F.], seq 390, ack 1871, win 618, options [nop,nop,TS val 8292617 ecr 

MySQL側には何も来ない。

[root@mysql01 ~]# tcpdump -n port 3306
...

というわけでLVS/DSR + iptablesでググってみるとこういう記事を見つけた。

LVS が FIN を落とす

LVS の DR 構成は、帰りのパケットが LVS を通らないために netfilter(iptables) がコネクションの確立を認識せず、FIN を通さないということが判りました。netfilter で TCP の state を見ないようにすることで、無事解決です。

なるほど。
とりあえず書かれているようにLVSサーバのiptables設定を変更してみると、

[root@lvs01 ~]# iptables -D INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
[root@lvs01 ~]# iptables -A INPUT -m tcp -p tcp --dport 3306 -j ACCEPT

解決!!!

LVSサーバではクライアントからのFINと(MySQLサーバからのFINに対する)ackのみが確認されて、

[root@lvs01 ~]# tcpdump -n port 3306
...
05:42:10.944673 IP 192.168.1.61.49851 > 192.168.1.111.mysql: Flags [F.], seq 390, ack 1871, win 618, options [nop,nop,TS val 9515718 ecr 9509710], length 0
05:42:10.945068 IP 192.168.1.61.49851 > 192.168.1.111.mysql: Flags [.], ack 1872, win 618, options [nop,nop,TS val 9515718 ecr 9513806], length 0

MySQLサーバではFIN、FIN/ack、ackの全てが確認できました。

[root@mysql01 ~]# tcpdump -n port 3306
...
05:42:10.594478 IP 192.168.1.61.49851 > 192.168.1.111.mysql: Flags [F.], seq 391, ack 1871, win 618, options [nop,nop,TS val 9515718 ecr 9509710], length 0
05:42:10.594571 IP 192.168.1.111.mysql > 192.168.1.61.49851: Flags [F.], seq 1871, ack 392, win 243, options [nop,nop,TS val 9513806 ecr 9515718], length 0
05:42:10.594852 IP 192.168.1.61.49851 > 192.168.1.111.mysql: Flags [.], ack 1872, win 618, options [nop,nop,TS val 9515718 ecr 9513806], length 0

DSRの挙動を考えると、なるほどなという感じですね。

ついでに

Railsではなくmysqlコマンドで接続、切断すると、

$ mysql -utest -ptest -h192.168.1.111
mysql> exit
Bye
$ 

コネクションはESTABLISHEDではなくFIN_WAIT2になりました。

[root@mysql01 ~]# netstat -an | grep 3306
tcp        0      0 0.0.0.0:3306                0.0.0.0:*                   LISTEN      
tcp        0      0 192.168.1.111:3306          192.168.1.61:49793          FIN_WAIT2

これはtcp_fin_timeoutの設定値に従って60秒で消えます。

[root@mysql01 ~]# sysctl -a | grep tcp_fin_timeout
net.ipv4.tcp_fin_timeout = 60

ちゃんと調べられてないけど、この違いはなんなんだろう。

まとめ

LVS/DSR + iptablesは初めてで、ちょっとハマりました。
もしかしたら常識なのかもですが。

LVS/DSRはハマりどころ多いですねぇ。

EC2の料金を円建て月額で表示するページを作ってみた

$0.2/時間とか言われてもパッとどのぐらいの値段かわからん

というわけで昨日、EC2の料金を円建て月額で表示するChrome拡張を作ってみたという記事を書いたんですが、
Chrome拡張にする必要があんまなさそうなので、popupのHTMLだけ抜き出してS3にアップしました。

f:id:mikeda:20141224113354p:plain

需要がありそうなら、RDSとかRIも対応するかもです。

※追記
RIと、ちょっとだけRDS対応しました

EC2の料金を円建て月額で表示するChrome拡張を作ってみた

AWSインスタンス料金は基本的に時間あたりのUSドルなんですが、
$0.2/時間とか言われてもパッとどのぐらいかわからん
と前から思っていたので、円建て月額にして表示するChrome拡張を作ってみました。

計算に使う情報は、ここから取得した円相場と、公式のEC2ページが参照しているJSONPファイルです。
計算式は単純に、『USD/時間 × 24 × 30 × 円相場』してるだけです。

以下、機能説明です。

料金表示ポップアップ

アイコンをクリックするとポップアップにEC2の円建て月額の一覧が表示されます。

f:id:mikeda:20141222210358p:plain

USD/時間→円/月に変換する電卓的なのもついてます。

Excel貼り付け用にCSV表示もできます。

f:id:mikeda:20141222210416p:plain

ManagementConsoleに料金表示

ManagementConsoleで、EC2インスタンス一覧ページの右下に『月額チェック』というボタンが出来てて、クリックするとインスタンスタイプの横に円建ての月額料金が表示されます。

f:id:mikeda:20141223165016p:plain

今のところ東京リージョンのみ対応。

ホントはインスタンスを作成、表示するときに、自動で金額を出すようにしたかったんですが、HTMLが複雑&動的過ぎてかなりショボイ感じになってます。
そこまで作りこんでManagementConsoleの更新に追随していくのは、まぁムリそう。

しかしこっちの機能が無いならChrome拡張である必要が全くないので、ポップアップの機能だけWEBサービスとして作りなおしたほうが良さそうな気がしてます。
それだと静的なHTMLをS3にアップロードするだけでいけそうだし。うーむ・・・

※追記

作りました。

http://mikeda.hatenablog.com/entry/2014/12/24/113359

まとめ

AWSの円建ての月額料金の計算を簡単にしてくれるChrome拡張をカッとなって作りました。

今のところ機能はそうとう限定的ですが、もし需要、要望があればもうちょっと作りこんでみるかもです。

コワーキングスペースを契約してみた

久しぶりのブログ!

 実は今、無職なんですが、ニート力が上がりすぎて社会復帰不可能になりそうだったので、コワーキングスペースを借りて極力そこで過ごすようにしました。

今回はその経緯と検討したことについてです。

まず自宅について

実は自宅に作業スペースがあります。
自宅でも作業できるように!と考えたころがあって、Thunderboltディスプレイ(9万円)とコンテッサ(ヤフオクで5万円)が置かれてます。

f:id:mikeda:20141222114426j:plain

しかしここで作業することは年に2回くらいしかありません。
このために広めの部屋に住んでることも考えると、完全にコストに見合っていないですね。

自宅で作業できない理由の1つは『ベッドのある空間ではダラケちゃう』こと。
自分は自宅では寝たきり派で、枕元にはMac、iPad、スマホの充電器が完備されています。
ちょっと休憩!とベッドに飛び込んで、ホントに『ちょっと休憩』ですむ確率はほぼ0%です。
もう1つの理由は『誰かに見られてないとダラけちゃう』ことです。

というわけで、基本的に作業、勉強をする時は外でする、というのが自分のスタイルになってます。

喫茶店

今までは週末作業には、渋谷のmiyamaって喫茶店をよく使っていました。

http://www.ginza-renoir.co.jp/miyama/

喫煙席側にですが、こういう1人用のスペースがあって、そこが非常に気に入ってます。

 

f:id:mikeda:20141222152356p:plain

作業スペースとしての喫茶店ですが、価格としてはコーヒー1杯の500円で済むので非常に安いです。
しかしコーヒー1杯で8時間とか居座るのはやはり気まずい。(2杯ならいいとかそういう問題ではなく)
週末だけならまだしも平日もとなると、自分の許容できる気まずさボーダーラインを超えてしまいました。

図書館

図書館にも何度か行ったことはあります。

しかし自分も含めて全く本を読む気がない学生や社会人が、朝イチで席を取ってしまうのがキツイ。
そして週末は特に、閉館時間が早めで夕方とかに閉まっちゃうので、自分には向いてませんでした。

コワーキングスペース

というわけで、渋谷でコワーキングスペースを探してみました。

Lightningspot

ここは1回しかいったことがないです。

http://lightningspot.com/

駅も近くて料金も安い。
1日利用で1,000円、月契約で15,000円/月のようです。
しかし作業スペースが手狭で、自分が使った時は中央のスペースで勉強会っぽいイベントをしていてけっこう賑やかでした。
音にはかなり弱いので、長期間使うのはちょっと辛いかなと思って候補から外しました。

PoRTAL

5回ほど使ってみました。

http://www.hituji.jp/portal/

ここはそうとういいです。
駅から近くて、広々として、中も落ち着いた感じでオシャレ。
外部ディスプレイなども自由に使えて、夕方にはスタッフがコーヒー入れてくれたり。
そしてワーキングスペースが静かなのが非常にいい。
ミーティングは原則、ミーティング用のブースか、ソファ席メインの広々としたラウンジスペースで行うことになってます。電話用の小さな小部屋もあったりします。

ただ高い。
デイリー利用は2000円ですが、基本的に週末のみ。
月でフル契約すると45,000円。辛い。
顧客よんでMTGとか、フリーランスとしてガッツリ働く場合は使ってみたいなぁと思います。

co-ba

けっきょく契約したのはここでした。

http://tsukuruba.com/co-ba/

駅からはちょっと遠目。
2フロアあって、5Fが月額会員専用のワーキングスペース、6Fは一日利用も可能なライブラリスペースになっています。
1フロアで20~30人くらい入れる感じです。

1番いいのは5Fは会員になると24時間使えるところ。
契約するとカードキーを渡されて、それで時間を気にせずいつでも入退出ができます。
価格はデイリーだと2,000円、月額だと15,000円。

イマイチなところは騒音。ホントに音に弱いので。
6Fはデイリーでも使えるところなので、一時利用なMTG、プレゼン、インタビュー、撮影などでも使われることがあり、状況によってかなりうるさいです。
5Fは月額会員用のワーキングスペースなのでそれに比べるとかなりマシですが、それでもけっこう人口密度が高くて区切りのない空間で、MTG、SkypeMTG、電話などバンバンやられるとかなり気になる。
いつも耳栓をしています。

あと平日はけっこう席が混んでて、午後から来ると5Fは使えないことがあるかも。

まとめ

というわけで、コワーキングスペースをいくつかまわってみたのでそのメモでした。

週末に作業/勉強したいけど自宅では集中できない、って人いたら検討してみるとどうでしょうか。
それで作業や勉強が捗るなら、そんなに高くない投資なんじゃないかな。
週末、夕方だけなら、上に書いてるのよりもっと安いプランがたいていあります。

そして、もっと静かでいいとこあるよーってのがあったら、ぜひ教えて下さい!

2013年のふり返り

こんばんわ、mikedaです。
年越し監視待機で帰省できず、今日2つ目のカップラーメン食べながら大晦日を過ごしています。


唐突ですがここ数年、順調にアクセスを伸ばしていたこのブログ、今年は伸びが止まってしまいました。

というかこのままじゃ12月は1万切りそうだ・・・(´・ω・`)
というわけで、最後のあがきに今年のまとめブログを書くことにしました。

ブログについて

『サーバのリソース使用状況レポートを作る』にミョウにはてブがつきましたが、理由はよくわからんです。
そして去年の暮れに書いた記事ですが、『Vyattaを6.5にアップしたらMTU制限が効かなくなって切り戻した→解決!?』は何人かに「あれ見て助かったよ」と言われて嬉しかったです。こういう記事をもっと増やしていきたいですね。


あとは特に無し!今年は記事が少なかったですね。
年別に並べると一目瞭然。

  • 2008年:44件
  • 2009年:88件
  • 2010年:26件
  • 2011年:40件
  • 2012年:35件
  • 2013年:9件

技術的な話については、今年は基盤整備に明け暮れてあまり新しいことしてないのもありますが、まぁそれでも少なすぎですね。
来年はガバっと増やす予定です。
ただ会社の技術ブログがオープンしたので、技術的なことは主にそっちで書くつもりです。
取り急ぎ、個人より会社のブランディングに注力しようと思ってます。

外部での発表について

まとまった量の話をしたのは『DevLOVE現場甲子園2013』とその再演(『たてらぶ〜DevLOVE現場甲子園 完結編〜』)だけでした。

LTも少ないです。

件数についてはブログ記事のとことほぼ同じです。来年はガバっと増やしたいです。


あとはchefについて調べてた時に、@さんとか@さん他、詳しそうな数人を集めてクローズドな少人数勉強会をやったことがあって、オープンなとこだと言えないような細かい議論ができてなかなか楽しかったので、またそういうのもやりたいですね。

読んだ本について

マンガ

去年から電子書籍で買うようになって、すごく購入数が増えたのですが、
なんと今年は700冊買ってました

電子書籍やばいですね。
ジャンプBOOKストア!』(『マーガレットBOOKストア!』)はしばらく前に価格改定があって、少年誌系だと1冊300円で買えるのでオススメです。

大当たり系はなかったですが、印象に残ってるのはこのへんです。

四月は君の嘘(1) (月刊マガジンコミックス)

四月は君の嘘(1) (月刊マガジンコミックス)

純潔のマリア 1 (アフタヌーンKC)

純潔のマリア 1 (アフタヌーンKC)

CAPTAINアリス(1) (イブニングKC)

CAPTAINアリス(1) (イブニングKC)

新世界より(1) (少年マガジンコミックス)

新世界より(1) (少年マガジンコミックス)

あとはこのへんが面白かったかな

一般書籍/技術書

今年は30冊読んでました。
読んで良かったな、と思うのはこのあたりです。

これからの「正義」の話をしよう (ハヤカワ・ノンフィクション文庫)

これからの「正義」の話をしよう (ハヤカワ・ノンフィクション文庫)

幕末史 (新潮文庫)

幕末史 (新潮文庫)

夜のピクニック (新潮文庫)

夜のピクニック (新潮文庫)

インフラエンジニアの教科書

インフラエンジニアの教科書

パーフェクトRuby (PERFECT SERIES 6)

パーフェクトRuby (PERFECT SERIES 6)

7つのデータベース 7つの世界

7つのデータベース 7つの世界


そして『なれるSE!』シリーズは安定して面白いですね

仕事について

もう転職して1年3ヶ月です。

今年はインフラ整備に注力しました。

  • システムの安定性/メンテナンス性の向上
    • OS/MWのバージョン/設定を統一し各種自動化(chef導入とか)を実施
    • 仮想化/構成見直しでAPP/DBなどの各種コンポーネントを分離
    • 更新処理の多いDBサーバをリプレース(BBWC付きRAIDコントローラを搭載/載せ替え)
    • 重たい処理、トラブル関連の調査/改善をいろいろ
  • コスト削減
    • サーバ25台、ラック1.5本を削減

粛々とやるべきことをやったな、という感じです。

来年はたぶん、インフラ整備というとこではもうあんまやることがない、少なくとも今年のような貯金の食いつぶしで自分の年俸分のアウトプットは出せないでしょう。
ムリヤリやること見つけてオーバースペックなことやってもしゃあないので、ビジネス的なところを意識して幅広く立ち回っていこうと思ってます。
そのためにできればHW/OS/MWに詳しい、精度の高いオペレータを1人育てたいけど、どうだろうなぁ。

リア充化について

気になる人もちょいちょいいたし、合コンも何度か行ったものの成果は全く出せませんでした(´・ω・`)

2014年のこと

2014年に力を入れて取り組まなくてはいけないこととしては、まずはリア充化』でしょう。
来年は34歳です。
『エンジニア35歳限界説』はどうでもいいですが、『35歳過ぎると彼女ができない説』はかなり気になっています。


あとはまぁ、基本的に先のこと考えるの嫌いなので(目標はいつだって、今より幸せになることだけです)、その時思うやりたいことやってきます。
来年もよろしくお願いします!!!

Dangerなターミナルに色を付ける

エンジニアならたいてい作業中の画面はこんな感じになってると思います。

あんまりいっぱいターミナル開くと、すぐ『あのターミナルはどこだあああ!?』ってなっちゃいますよね。
そして『ギャー、このコマンドはこのサーバじゃなかったあああああああ!!!』みたいなコピペ事故はみんな20回くらいやってると思います。


そういうのを防ぐために『ターミナルを簡単に色づけできたらなぁ』と思って、
.bashrcとか/etc/profile.d/~~.shにこんなのを書いてみたところ、

alias color_danger='PS1="\[\033[0;31m\][\u@\h \W]\\$ \[\033[0m\]"'
alias color_warning='PS1="\[\033[0;33m\][\u@\h \W]\\$ \[\033[0m\]"'
alias color_normal='PS1="[\u@\h \W]\\$ "'

コマンドで簡単にプロンプトに色を付けられるようになりました。


なんかわかりやすくなった気がする!!!

Nagiosのアラート情報をSpreadSheetに自動で書き込む

『WEB+DB PRESS Vol.75』の『継続的Webサービス改善ガイド』は良かったですね。


その記事に、「毎日、アクセスログを解析した結果をGoogle DocsのSpreadSheetにまとめている」ということが書かれていて、サンプルがgistに公開されていました。
puboo-performance-index.rb

へー、SpreadSheetに自動でいろいろまとめるの、なかなか便利そう!ということで自分でもちょっとやってみました。

まずは試し

rubyでSpreadSheetを操作するのはgoogle_driveを使うとすごく簡単でした。

#!/home/mikeda/.rbenv/shims/ruby
# -*- coding: utf-8 -*-

require 'google_drive'
session = GoogleDrive.login("<user>@gmail.com", "<password>")

#ファイルのリストを表示
#session.files.each do |file|
#  p file.title
#end

#テスト用のスプレッドシート、ワークシートを開く。なければ作る
ss_title = 'test_ss'
ws_title = 'test_ws'
ss = session.spreadsheet_by_title(ss_title) || session.create_spreadsheet(ss_title)
ws = ss.worksheet_by_title(ws_title) || ss.add_worksheet(ws_title)

#A1の値を更新する
ws[1,1] = "aaa"
ws.save

NagiosのアラートをSpreadSheetに!

というわけで、今回はNagiosのアラートを自動でSpreadSheetに書き込むようにしてみます。
※『定例会議で障害情報を報告しろ』とかってけっこう言われますよね!


まずこういうスクリプトを作って

#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-

require 'google_drive'

# Google Docsのアカウント
USER = '<user>@gmail.com'
PASSWORD = '<password>'

host, state, type, desc, info, timestamp = ARGV
time = Time.at(timestamp.to_i)

headers = %w(時間 Host State Type Desc Info 担当者 対応詳細)

ss_title = 'nagios_alert'
ws_title = time.strftime("%Y-%m")

session = GoogleDrive.login(USER, PASSWORD)

ss = session.spreadsheet_by_title(ss_title) || session.create_spreadsheet(ss_title)
ws = ss.worksheet_by_title(ws_title)
unless ws
  ws = ss.add_worksheet(ws_title)
  headers.each.with_index do |header, i|
    ws[1, i+1] = header
  end
end

num_rows = ws.num_rows
ws[num_rows + 1, 1] = time.strftime("%Y/%m/%d %H:%M:%S")
ws[num_rows + 1, 2] = host
ws[num_rows + 1, 3] = state
ws[num_rows + 1, 4] = type
ws[num_rows + 1, 5] = desc
ws[num_rows + 1, 6] = info

ws.save

ちょいちょいとNagiosのコンフィグをいじります

define command{
  command_name  notify-host-by-spreadsheet
  command_line  /etc/nagios/helper/notify-by-spreadsheet.rb "$HOSTALIAS$" "HOST DOWN" "$NOTIFICATIONTYPE$" "-" "-" "$TIMET$"
  }

define command{
  command_name  notify-service-by-spreadsheet
  command_line  /etc/nagios/helper/notify-by-spreadsheet.rb "$HOSTALIAS$" "$SERVICESTATE$" "$NOTIFICATIONTYPE$" "$SERVICEDESC$" "$SERVICEOUTPUT$" "$TIMET$"
  }

define contact{
   contact_name spreadsheet
   use          generic-contact
   host_notification_commands     notify-host-by-spreadsheet
   service_notification_commands  notify-service-by-spreadsheet
   }


テストでアラート飛ばしてみると・・・

書き込まれた!(枠線とか色はちょっと手でいじりました。)

まとめ

アプリとSpreadSheetを連携させると、各種レポートの作成がいろいろ楽にできそうですねー