気が付いたらmysqlサーバがswapしてた

昨日の夜にmuninをフラフラーっと見てたんです。とあるDBサーバで今度作業するっていういので今の状況を確認しておこうと見たら・・・・

2GBもswapしてるじゃないですか!
アタヽ(д`ヽ彡ノ´д)ノフタ
うーん、swap I/Oの頻度はそこまで多くないから死にはしないけど原因見つけて対処しないとなっと。
前に読んだhttp://d.hatena.ne.jp/fat47/20121121/1353495937:【メモ】MySQLでのswap発生とNUMAアーキテクチャを思い出しました。

「お、確かにR410でCPU2個詰めるからもしかしたら・・・」
と思ったので搭載CPUの数を調べようと/proc/cpuinfoを見たら


# cat /proc/cpuinfo | grep physical | grep id
physical id : 1
physical id : 1
physical id : 1
physical id : 1
physical id : 1
physical id : 1
physical id : 1
physical id : 1
1個しか搭載してませんでした・・・
8coreだったのはHTしてるっぽいですね・・・構築は他の人がやったので細かいところは知らなかったのでちょうどいい機会。

innodb_buffer_poolの設定が間違ってるのかと思いましたが、実メモリ32GBに対して24GB割り当ててたので間違ってはないようだ。他のmy.cnfの設定とか見ても特別変なところはない。

結論 vm.swappinessの設定がデフォルトでした。
kernel 2.6から追加されたkernelパラメータらしいのですが、swap領域の扱いを制御するパラメータとのこと。
このパラメータの値が小さければ小さいほどswapしにくいと。
mysqlでは0にするのを推奨しているようです。まぁmysqlもメモリに乗り切らなかったら(古いキャッシュ)結局Diskにアクセスしに行くんだからswapしようが、普通にDiskIOが発生しようが変わらないんじゃないかと。

でも既にswapしてるしってことで対応手順を

kernel パラメータのvm.swappinessを設定

vm.swappinessはsysctl.confに記述してやらないと再起動したら設定が消えちゃうのでこいつを使ってやる。

# vim /etc/sysctl.conf

vm.swappiness = 0 #この1行を追記

保存したら

# sysctl -p

で/etc/sysctl.confの設定を反映。サーバの再起動とか何もいらないです。sysctl -w hogehoge = xxxとかでもできた気がするけど、今回は記憶にある方法でこれを採用。まぁあとは、記述した設定がそのまま反映されるので再起動時と全く同じになるというメリットもあります。

上記コマンドでも反映されたパラメータが出力されるのですが、一応確認で

# sysctl -a | grep swappiness
vm.swappiness = 0

これで設定が反映されていることが確認できました。

が!

swapしてることには変わらないのでそれの対応。swapしたデータをメモリに戻してやる。

swapしたデータをメモリに戻す

 # cat /proc/swaps 

でどのデバイスをswapに割り当ててるか確認する。
今回は/dev/sda2だったので対象はこいつ

# swappoff /dev/sda2

こいつを実行してやればswapにあるデータがメモリに戻ります。メモリに乗らなければ破棄されるらしい。
戻すというかswap領域をなくしてるだけなのですが。
基本メモリは消えても困らないデータを乗せるところなので破棄されてもデータロスは起きないはず。

別のターミナルでtopコマンドとか実行しながら進捗を確認するといいと思います。

swap領域はないならないで困るので戻してやります。

# swapon -a 

freeなりなんなりコマンドを実行してswap領域が戻ってることを確認したらめでたしめでたしです。

muninで確認してもswap領域が空いたことを確認できました。

これでもswapするようならmysqlの設定を1から見直す必要があります。
ちなみにこの作業を全てやるのに40分ほどかかりました。mysqlが稼働してて更新が走ってる状態なので完全に止まってる状態ならもう少し早く終るかもです。


こんな設定は1台見つけるとゴキブリの様にうじゃうじゃと他のサーバでも同じ設定になっているのが見つかるので洗い出す仕事が増えました・・・
既に10台以上確認している・・・
まだswapしてなきゃいいけど、swapしてるとやっかい・・・

自作の起動スクリプトをchkconfigに追加する方法

自作の起動スクリプトを書く時に2行加えるだけ


オープンソースだと起動スクリプトがなかったりするので自作したりしますよね?シェルで普通に起動スクリプトを書いてもchkconfigには登録できないと聞いてちょっと調べてやってみました。今回はvarnishの起動スクリプトをchkconfigに登録するために設定してみました。下記の#!/bin/bashを除く2行を追記するだけ


#!/bin/bash
# chkconfig: 2345 75 25
# description: Varnish start/stop Script

何をしているか?


# chkconfig: 2345 75 25

これは

chkconfig varnish on
を実行した時にonになるランレベルを2,3,4,5と指定しています。
起動は75番で停止は25番を利用します。
この番号は
$ ls /etc/rc.d/rc3.d/
K01smartd K10saslauthd K16abrt-oops K50netconsole K74haldaemon K75quota_nld K85messagebus K88auditd K92ip6tables K99cpuspeed K99rngd S09network-inject S12nslcd S13irqbalance S25cloud-init S30nscd S55sshd S58ntpd S80postfix S85httpd S90munin-node S99local
K05atd K16abrt-ccpp K16abrtd K74acpid K75netfs K85mdmonitor K87restorecond K89rdisc K92iptables K99lvm2-monitor S01sysstat S10network S12rsyslog S20kdump S26udev-post S50snmpd S57ntpdate S64mysql S84tomcat S90crond S99cloud-init-user-scripts

こうゆう番号のことです。なのでかぶらないように適当な数字を振るといいと思います。

EMOBILE(LTE)を購入したのでWiMAXと比較してみた。

EMOBILEの購入きっかけ

正直WiMAXでも十分外で使えるんですが、プチプチ切れたり、急激な速度低下によるストレスが溜まってしょうがないのでEMOBILEを購入してみました。私はプライペートではMac Book Airを使っているのでネットにつながっているかをターミナルでずっと自鯖pingを打って確認しています。

  • プチプチ切れる

というのはpingでRequest timeout for icmp_seqが頻繁に発生するのです。この状態ではネットに繋がっておらず、ヘタすれば再接続することもなくPCからWi-Fiを切って再接続する必要がありました。

  • 急激な速度低下

だいたいpingのtimeが100msくらいなのですが、急に数千ms〜数万msとおかしな値になり実際に通常のwebページを表示するのも困難に・・・

  • 地下でもないカフェで全く電波が入らないことも・・・

端末について

端末は

になります。



サイズはどちはも若干大きめでiPhoneくらいでしょうか。重さもだいたい同じくらいなのでバックに入れている分には苦になることはないのではないでしょうか?

回線速度比較

iPhone4から比較


iPhoneからはSpeedTestというアプリを使用して比較してみました。計測回数はそれぞれ2回です。


WiMAX



EMOBILE




平均すると若干EMOBILEの方が早いですが、iPhoneの端末自体の限界もあるのかと思います。

Mac Book Airから比較

Mac Book AirからはUSENのスピードテストを利用しました

WiMAX





EMOBILE





平均するとWiMAXは3Mbps、EMOBILEは6Mbpsと倍くらい違いました。LTEの方が理論値上ベストエフォートが大きいので速くないと困るわけなのですが、ここまで違うとなるとちょっとWiMAXは使いづらくなりますね。ただでさえ安定しないのでWiMAXは極力使いたくない感じです。これからの使い道はEMOBILEの電池が切れた時にWiMAXを利用するというくらいでしょうか?あとはPCはEMOBILE、mobile系はWiMAXと使い分けるのでもいいですが。


今回は試行回数が少ないので絶対とは言えない数値ですが、私が計測した場所ではこのような違いが出ました。WiMAXの端末自体1年半前のものなので端末の劣化という可能性もありますし、電波状況や他のWi-Fi端末からの干渉によって数値は全然異なってくるので鵜呑みにしないようお願いします。測定場所は吉祥寺の某2Fです。

チューニンガソン #4に参加してきました

ロスタートさんの公式のブログの方でまとめられてましたので追記 【2012年7月4日】

【レポート】いろいろチューニングしてパフォーマンスを競うバトルイベント!「Tuningathon」第4弾! #tuningathon


チューニンガソンとは

http://www.zusaar.com/event/312053

FBファンページ

アプリ以外のインフラ部分だけをチューニングしまくってとにかく速くするというバトルです。

前回参加した時のエントリーはTuningathon 2!に出てきましたです。この時はMediaWikiでいかに速くレスポンスを返すかという回だったのですが、nginxのプロキシの設定を間違え測定不可という結果に終わってしまいました(´・ω・`)・・・

今回はRuby on RailsRefineryというOSSCMSが対象でした。

  • RoR refineryのコメントPOST/GET回数
  • 10並列で一定秒数間測定
  • 秒間平均POST/GET回数がスコア
  • エラー返却は単純に除外
  • POSTはGETの10倍のスコア
  • POST後のGETによる反映チェック
  • 反映チェックの成功率の二乗をスコアに乗算

がバトル条件でした。

サーバは

であり、スペック的には少々厳しい感じです。

チューニング開始

まず最初に行ったのはtmuxをyumでインストールして、自鯖からconfファイルを持ってきてペイン分割してとtmuxがないとダメな子なので最初にやりました。使い方は前のエントリーから


メインウィンドウを3ペインで分割し、1つをtop -d 1を実行し、1つをperf topでベンチマークを実行した時に何が起こるかを確認しました。LL言語はさすがというか、とにかく重いんです。第2回の時もPHPが重すぎて・・・
今回はRoRと全くの未経験ゾーンだったのでとにかくベンチマークを実行・眺めるをやってました。
実は最初の時はベンチマークがうまく走らず、エラー箇所をベンチマークスクリプトの中身から確認したらtry〜catch部分でExceptionが発生していました。おかしいな、おかしいなと半ば諦めも若干入りつつ一旦Google先生RoR関連のチューニングを調べていました。

実はrailsの実行をrootで実行しなきゃいけないのに一般ユーザで実行していて問題になっていたようですw

これに気づいたのが13:30頃。まだScoreは2.7くらいのデフォルト状態。

いろいろ試してみるも対して変わらない時にTLに

とか流れてきて、@netmarkjpが強すぎて泣きたくなりましたw

更に15時頃1100という謎な値を叩きだす@netmarkjpさん。
自分はこの時3とかをさまよってました


16時手前にRubyのEnterprise Editionのインストールが終了して、PATHの設定を書き換えて計測したら5を超えました。
でも@netmarkjpの200分の1というもう絶望的な値でした。この時にはもう20を超えるような人も出始めていました。

16:30にPassengerのインストールが終わりapacheのデフォルトポートを3000に、DocumentRootをrailsに当てるという無理やりな構成にして10手前まできました。


Passengerの設定をいろいろ変更してみて再度ベンチマークを何度か走らせた時に自己最高の16が出て喜びました。

間に公式の測定が走っており、そのタイミングでtop10が10超えくらいだったのでもしかしたらと思ったのですが、この時には結構時間も立っていたのでもうみんな20くらいなのかな〜っと諦めモードも若干入りつつ。Passengerの設定を何度も変えてベンチマークを走らせるということをしていました。多分最後1時間くらいほとんどPassengerいじってましたね。

最後30分くらいになってmysqlinnodb関連をチューニングかけるかと思いつき、自鯖の設定を丸々コピーして貼っつけましたwww時間がなかったのでコピペで何か変わればいいかな〜くらいにしか思ってませんでしたが、何も変わらず。

自分が一番の失敗だったのはapacheの再起動をした時にScoreが一回急激に下るという現象が何かを本当の意味で理解していなかったことだと思います。単純に何度か行うとキャッシュが聞いてScoreが上がるんです。なので今回トップ2の2組はvarnishでひたすらキャッシュするというので1000を超えるScoreを出していたようです。
自分は気づかずずっとRubyだけ触ってました。CPUバウンドするRubyをどうにかして軽くしたいとしか思ってなかった時点で上位は厳しかったようです。

結果発表

なぜか9位に入賞してしまいました(^^)
呼ばれた時にびっくりし過ぎて、前でしゃべってもテンパってて何を喋ったかも覚えてませんwすいませんでしたw

nginxは使用せず、apacheを利用しました。

Passengerは以下の様な設定にしました。


LoadModule passenger_module /usr/local/ruby-enterprise-1.8.7/lib/ruby/gems/1.8/gems/passenger-3.0.13/ext/apache2/mod_passenger.so
PassengerRoot /usr/local/ruby-enterprise-1.8.7/lib/ruby/gems/1.8/gems/passenger-3.0.13
PassengerRuby /usr/local/ruby-enterprise-1.8.7/bin/ruby

Header always unset "X-Powered-By"
Header always unset "X-Rack-Cache"
Header always unset "X-Content-Digest"
Header always unset "X-Runtime"

PassengerMaxPoolSize 40
PassengerMaxInstancesPerApp 2
PassengerPoolIdleTime 3600
PassengerUseGlobalQueue on
PassengerHighPerformance on
PassengerStatThrottleRate 20
RailsSpawnMethod smart
RailsAppSpawnerIdleTime 86400
RailsFrameworkSpawnerIdleTime 0

ギリギリまでいじったのは

  • PassengerMaxPoolSize 40
  • PassengerMaxInstancesPerApp 2

の2項目だと思います。メモリが余っていたのでPoolSizeを上げてみてもっとキャッシュできないかと試したり、インスタンス数をCPU*2にしたりなどして調整しながら一番いい値の時の設定を採用しました。

my.cnfは


max_connections = 500
bulk_insert_buffer_size = 8M
nice=5
query_cache_size = 16M
query_cache_limit = 1M
thread_cache_size = 1
innodb_buffer_pool_size = 512M
innodb_additional_mem_pool_size = 4M
innodb_log_buffer_size = 8M
innodb_log_file_size = 64M
innodb_log_files_in_group = 2
と本当に何も考えずコピペしただけでした。

今回このようなチューニング方法を採用した理由はrx-7乗りのnamikawaさんのブログを見つけたところからこのようにしました。

3年前のエントリーですが、基本は変わらないので採用してみました。

当日はアルバイト時代にインフラコンビを組んでいたYosuke Yamamotoさんにわからないところをちょいちょい聞いて教えてもらったりしたので1人で結果を出したわけではないので次回は本当に1人で結果が出せるようにしたいです。

今回の1位2位の上位者たち。

VOYAGE GROUPさんのアジトを会場で懇親会が行われました。いつもいつも会場提供とお酒の提供をありがとうございます。
AWSの提供をして頂いているAmazonさん、取材にいらした技術評論社の方、運営をして頂いているゼロスタートの方々いつも楽しいイベントにして頂きありがとうございます。
自分が優勝するまで続けてくださいw優勝したら勝ち逃げしたいですwなので数年〜10数年続けていただけるとwwww

そして2次会は近くの権八で技術話をつまみにお酒と翌日の朝は起きるのが辛かったです・・・

TwitterのURLの部分やgistの部分がちゃんtp表示されるかわかりませんが、参加したエントリーになります。

rackhubの時刻がおかしかったので直してみた

時刻がおかしいことに気づいた

watchコマンドでとあるコマンドを1秒間隔で実行していたのですが、watchコマンドを実行すると時刻が表示されるわけです。
まずはntpが入っているか確認したらインストールされていなかったのでインストール。
debianなのでaptitude

# aptitude install ntp

インストールが終わったのでまずはntpqで現在の設定を確認

# ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
+219x123x70x90.a 192.168.7.123 2 u 60 64 1 10.250 942.395 0.066
+ns.bio.keio.ac. 131.113.1.16 2 u 59 64 1 13.035 945.438 0.050
-chiba.ocn.likk. 133.100.9.2 2 u 25 64 1 39.404 960.892 4.935
*laika.paina.jp 203.178.137.183 2 u 30 64 3 10.073 944.949 0.040

ん?大丈夫そうだぞ?でもいつまで経っても9時間くらいずれているので/etc/ntp.confを編集しました。私が使うのはntp.nict.jpとntp.jst.mfeed.ad.jpの2つです。
これを設定したのですが、10分以上経っても反映されず・・・9時間というずれ方に疑問は感じていたのですが気づかず・・・

ntptraceでntpサーバへ接続してみることにしました。

# ntptrace ntp.nict.jp
ntp-b2.nict.go.jp: timed out, nothing received
***Request timed out
タイムアウトになりました。(実際他のサーバからやってもタイムアウトになったので仕様のようです)。全く違うclock.tl.fukuoka-u.ac.jpに実行したところ普通に返ってきました。

# ntptrace clock.tl.fukuoka-u.ac.jp
clock.tl.fukuoka-u.ac.jp: stratum 1, offset 0.000000, synch distance 0.000645, refid 'GPS'

なのでこのドメインも追加してntpを再起動したのですが変化なし・・・

友人の助言

HI_PONが「rackhubようわからんけど、UTCなんじゃないの?JSTにすればいいんじゃね?」
( ゚д゚)ハッ!そういえばそんなん前に見た気がする!ということで調べたら見事UTCになってました。

# date
Tue May 1 13:53:50 UTC 2012

UTCからJSTに変更するために下記コマンドで環境変数を変更

# export TZ=Asia/Tokyo

そしてntpサーバを再起動かけたら日本時間に直りました。

# date
Wed May 2 01:06:28 JST 2012

とりあえず、これでtmuxとかwatchを使ってる時にターミナルで時刻を確認できるようになりました。

Macの電源が切れそうで走り書きしたので汚くて申し訳ないです・・・

pythonで久々にfizzbuzzを書いた

何も難しいことではないんですが、pythonを思い出すためにfizzbuzzを書きました。
1発では書けず10分くらいかかってしまいましたが、書けました。
for文とif文での一番簡単な書き方なのでなんの参考にもなりませんが、ログ用に残しておきます。

#!/bin/python

for i in range(1,101):
if i%15 == 0:
print "fizzbuzz"
elif i%5 == 0:
print "buzz"
elif i%3 == 0:
print "fizz"
else:
print i

他の書き方にも挑戦したいとおもいます。

memcachedの自動再起動スクリプトを書いた

「おかしい」とか「間違ってる」などありましたら、バンバンご教授くださいませm(_ _)m

実装環境

  • CentOS5系
  • memcached 1.4.5
  • nagiosのpluginが入っていることが前提
  • 言語は依存関係が少ないbashを利用

私が管理しているサーバはすべてNagios+nrpeによる監視をしているのでnagiosのpluginが入っています。
もし入っていない場合はtelnetで書き直すなどtcp接続のコマンドを利用してください。

実行するコマンドの出力確認

今回利用するpluginのオプションは以下の通りになります。

# /usr/lib64/nagios/plugins/check_tcp  -H localhost -p 11211 -t 5 -E -s 'stats\r\nquit\r\n' -e 'uptime' 

このコマンドを実行すると下記の出力が得られます。

TCP OK - 0.001 second response time on port 11211 [STAT pid 26729
STAT uptime 2213898
STAT time 1334472012
STAT version 1.4.5
STAT pointer_size 64
STAT rusage_user 6.167062
STAT rusage_system 8.447715
STAT curr_connections 10
STAT total_connections 27880
STAT connection_structures 11
STAT cmd_get 0
STAT cmd_set 0
STAT cmd_flush 0
STAT get_hits 0
STAT get_misses 0
STAT delete_misses 0
STAT delete_hits 0
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 195184
STAT bytes_written 22385028
STAT limit_maxbytes 134217728
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT bytes 0
STAT curr_items 0
STAT total_items 0
STAT evictions 0
STAT reclaimed 0
END]|time=0.000521s;;;0.000000;5.000000

この出力の中から不変的な文字列を抽出し、比較することで異常を検知することが可能です。
今回利用した文字列は”TCP OK”になります。

スクリプトの詳細

1回のチェックで失敗した場合に再起動をかけてしまうと誤検知による再起動がかかってしまう可能性があるので複数回チェックを行います。
自動再起動のスクリプトは以下の通りです。

#!/bin/bash

TCPCHECK_CMD=/usr/lib64/nagios/plugins/check_tcp
CHK_OK="TCP OK"
COUNT=1

while [ $COUNT -le 3 ];
do
RES=`$TCPCHECK_CMD -H localhost -p 11211 -t 5 -E -s 'stats\r\nquit\r\n' -e 'uptime' | awk '{print $1,$2 }' | head -n 1`

if [ "$RES" = "$CHK_OK" ]; then
echo "memcached status OK"
exit 0
else
echo "memcached status NG"
fi
COUNT=`expr $COUNT + 1`
sleep 30

if [ $COUNT -gt 3 ]; then
/etc/rc.d/init.d/memcached restart
echo "RESTART"
fi

done

exit 0

  • 11211のlocalhostをチェック
  • 正常動作した場合はそのチェックしたタイミングでスクリプトから抜ける
  • チェック間隔は30秒空ける
  • COUNTを利用してチェック回数で再起動するかどうか判定を行なっている

実行した時の出力

まずは正常動作している場合にスクリプトを実行します。

# sh memcache_restart.sh 
memcached status OK

次にmemcachedが応答しない場合にスクリプトを実行します

memcachedが応答しない場合を作るためにあえてmemcachedを停止してから実行しました。

# sh memcache_restart.sh 
memcached status NG
memcached status NG
memcached status NG
memcached を停止中: [失敗]
memcached を起動中: [ OK ]
RESTART

再起動されたかをpsコマンドで確認します。

 # ps uaxf |grep memcached
root 21438 0.0 0.1 65460 832 pts/0 S+ 15:57 0:00 \_ grep memcached
root 21150 0.0 0.1 69016 764 ? Ssl 15:57 0:00 memcached -d -p 11211 -u root -m 128 -c 1024 -P /var/run/memcached/memcached.pid

現在時刻でmemcachedが起動していることが確認できました。
正常に再起動されることがわかりましたが、これだといつ再起動がかかったのかわかりにくいのでrestartをかけるところに|を利用して自分のメールアドレスに対してmailコマンドを実行すればいいと思います。
複数サーバに仕込む場合にはどのサーバが再起動されたか確認するために件名にホスト名が入る様にするのもポイントになります。

〜忘れていたので追記〜

実装方法

memcachedの再起動にはroot権限が必要なのでrootのcrontabに登録します。

 # crontab -e
 */5 * * * * /bin/sh /root/memcache_restart.sh > /dev/null 2>&1

これで5分に1回チェックを行なってくれます。時間は適度調整してください。
スクリプトでも30秒のsleepが3回発生するので再起動されるまでに最大6分30秒かかります。