b.l0g.jp     About     Archive     Feed

WEB+DB PRESS vol. 79の記事を書きました

cover

同じ会社で働いてる @kuwa_tw さんから紹介いただいて、WEB+DB PRESS vol. 79の記事を書かせていただきました。雑誌に、というか印刷物に自分の書いたものが掲載されるのは初めての経験です。あまり歓迎されないけれども避けては通れない、メンテナンスという切り口で書かせていただいています。

始め、執筆の話をもらった時は、自分の書いた文章が印刷されて世に出るなんて想像もつかない出来事だなあと思っていましたが、実際手元に届いても、これが広く読者の方々に読まれるというのがどういうことなのかよくわかっておりませんw 皆さんからマサカリが飛んできて初めて理解できるものなのかもしれません。ご意見などありましたら @dblmkt までいただけるとうれしいです。

執筆のチャンスをくれた @kuwa_tw さんを始め、不慣れな我々をサポートしてくれた技術評論社の編集者の方、一緒に記事を執筆し色々なアドバイスをくれた同僚達にこの場を借りて感謝を表したいと思います。ありがとうございました!

CentOS 6になったらTomcatのJVMが仮想メモリを大量に確保するようになった

 

CentOS 5+Tomcat 7+JDK 7+Apacheという組み合わせで動かしていたサーバ群に、OSだけCentOS 6にしてミドルウェアのバージョンは変えないサーバを何台か追加したところ、CentOS 6の方が、Tomcatが確保している仮想メモリ量が圧倒的にでかいことに気づいた。

ちなみに、どちらのサーバもヒープサイズは「-Xmn1024m -Xmx2048m -Xms2048m」となっており、本来なら2GBプラスアルファ(コードキャッシュ他の領域分)しかメモリは食わないはずだ。もちろん、ロードバランサではどちらのサーバにも同じ重みでアクセスを流していおり、負荷は同じのはず。

CentOS 5のサーバ

こちらはざっくり3GB弱の仮想メモリを確保していると出ている(左から5番目、VSZの列)。ヒープサイズから考えるとまあこんなものかというレベル。

# ps auwx
  
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
  
31234 10315 110 8.8 3134280 1447956 ? Sl Nov14 6870:09 /usr/local/java/bin/java -Djava.util.logging.config.file=/usr/l cal/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -server -XX:MaxPermSize=128m -XX:PermSize=128m -XX:SurvivorRatio=2 -Xmn1024m -Xmx2048m -Xms2048m (後略)
  

CentOS 6のサーバ

一方こちらは10GB弱ものメモリを確保していることになっている。ヒープサイズとの差分9GB近くはどっから出てきたのか?


# ps auwx
  
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
  
31234 19463 156 33.6 11270576 2708744 ? Sl Nov14 9532:10 /usr/local/java/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -server -XX:MaxPermSize=128m -XX:PermSize=128m -XX:SurvivorRatio=2 -Xmn1024m -Xmx2048m -Xms2048m (後略)
  

CentOS 6の方のサーバのTomcatのプロセスIDを指定してpmapコマンドでメモリの確保状況を見てみると、何やら同じ容量(64MBぐらい)を確保しているanonという行がたくさん表示されているのが目につく。これが悪さしているようだ。ちなみに、一番右の列には通常そのメモリを確保しているファイル名が出るが、anonというのは匿名で割り当てのみがされた領域を示しているようだ。

  
# pmap -x 19463 | sort -k2 -n
  
Address Kbytes RSS Dirty Mode Mapping
  
(略)
  
00007f08d0218000 63392 0 0 -- [ anon ]
  
00007f0878215000 63404 0 0 -- [ anon ]
  
00007f099c208000 63456 0 0 -- [ anon ]
  
00007f08941fe000 63496 0 0 -- [ anon ]
  
00007f09341fb000 63508 0 0 -- [ anon ]
  
00007f091c1ea000 63576 0 0 -- [ anon ]
  
00007f08901e5000 63596 0 0 -- [ anon ]
  
00007f08fc1e3000 63604 0 0 -- [ anon ]
  
00007f09c01e0000 63616 0 0 -- [ anon ]
  
00007f094c1d8000 63648 0 0 -- [ anon ]
  
(略)
  

調べてみたところ、この現象は、CentOS 6に含まれているglibc 2.11の挙動によるものだそうだ。glibc 2.10から、スレッドごとにメモリ空間を割り当てるような実装に変わったとのこと。なお、CentOS 5ではglibcは2.5。以下、glibcのコミッタUlrich Drepper氏による2.10のchangelog解説からの抜粋。

glibcに対する今回の変更では、スレッドごとにメモリプールを作るようになった。これで多くの場面で間違った割り当てを排除することができる。メタデータは通常1つのスレッド内でしかアクセスしない(スレッドは割り当てられたコアから移動されないのが望ましい)。アドレス空間を吹き飛ばしてしまうようなメモリのハンドリングを防ぐため、メモリプールの使い過ぎに上限が設けられた。デフォルトでは、32ビットマシンではコアあたりメモリプール2つ、64ビットマシンではコアあたりメモリプール8つを生成する。

プールが確保するサイズは64MBであり、上の例のCentOS 6のマシンの場合、CPUは24コアの64ビットマシンなので、「24コア x 8 x 64MB」が仮想メモリとして確保されているため、VSSの列の値が大きくなっていたというわけだ。なお、このプール用のメモリはあくまで割り当てられただけで使用されているわけではない。そのため、実際に使われているメモリはRSS(Resident Set Size)の列に表示されているものである(当然だが)。

Tomcat動かしてて気づいたのでタイトルが「TomcatのJVMが~」となっているが、同じようなつくりのメモリを大きく確保するアプリケーションでは同じことになるのは言わずもがな。

参考1 : Quoraのやりとり「なぜいくつかのアプリケーションはRHEL5と比べてRHEL6では明らかに大きな仮想メモリを使うのか?」

参考2 : IBM developerWorksの記事「Linuxのglibc 2.10以上(RHEL6)のmallocは仮想メモリの使用量を過大に表示するのか」

参考3 : StackOverflowのやりとり「Linux上でのJavaの仮想メモリ使用量が大きすぎる」
解説が非常に詳しくてためになる。

参考4 : 上述glibcコミッタUlrich Drepper氏の記事

MySQL Casual Talks vol.5 メモ

 

MySQL Casual Talks vol. 5に行ってきたので、自分なりのメモと資料へのリンク。

途中、アラートが鳴り始めて確認してたりしてメモが適当なところがあるが仕方なしw

かなりのスピードでじゃんじゃんプレゼンが進んで行ったが、どれも面白い・役立つ内容ばかりで、楽しいひと時でした。発表者の皆様、会場の提供や調整などしてくださった@myfinderさんはじめとする皆様、ありがとうございました。自分の隣でビール缶を次々と「カシュッ」と空けていた@oranieさんのような余裕を持ちつつ、次回は自分も何かネタを提供できるといいなあ。

@yuryuさん GTIDを使い始めてやめた話

MySQL5.6でGTIDを試してそっと閉じた from Haruka Iwao
  • GTID - 全てのトランザクションを一意に識別、一貫性保証
  • マスタを切り替えると、マスタのUUIDが変わるのでGTIDが2個になる
  • 利点
    • change master to … master_auto_position=1で簡単にレプリをはれる
    • mysql workbenchのmysqlfailoverとか使える
  • 欠点
    • クラスタ全部GTID有効にする必要
    • MyISAM使用不可
    • HAしたいならMHAでいいんじゃね?
  • バグ
    • GTID有効でFLUSH LOGSするとレプリ停止(5.6.11のみ)
    • stop/start slaveするとトランザクションがスキップされる可能性あり
    • ネットワーク切断でトランザクションスキップの可能性
  • 結局、本格的に使うには時期尚早なので辞めました、ということ

@con_mameさん MySQL 5.6移行記

僕らのMySQL5.6移行記(仮) from Yutaka Hoshino
  • クックパッでは5.5のサーバを5.6にバージョンアップしたり最初から使ったり
  • レプリしてクエリ流してコンフィグいじり始めた
    • うまく行ったのは最初だけで問題勃発
  • EBSでスナップショット取ったボリュームを5.6マシンにぶら下げてmysql_upgrade実行
  • Kage
    • リクエストをコピーしてsandbox環境に流す仕組み(ユーザへはproductionからの結果が返る)
    • レスポンスのdiffも取れる
    • バックエンドを5.6にして違いを確認
  • バージョン違い、設定違いのサーバを並べて比較
  • 開発用DBを先に新しくしてリリース前に新環境を試す
  • バグ確認用(最新) → 検証用(1つ前) → 本番用(安定版)
  • 各バージョンが入ったAMIを用意しておいてすぐ起動できるようにしてある
  • GTID有効だとsql_slave_skip_counter使えない
  • AWSだと色んな検証がCasualにできる
  • bugsは見ましょう!
  • 5.6で遅くなるところもあるので、得意な部分から本番投入していっている

@yoshi_kenさん 5.0 Tritonnから5.6 mroongaへの移行

Tritonn (MySQL5.0.87+Senna)からの mroonga (MySQL5.6) 移行体験記 from Kentaro Yoshida
  • 技評の記事の裏話
  • 旧構成 マスタはDRBDでミラー、スレーブにレプリ
  • 5.6スレーブを追加してそこに孫をぶら下げて旧環境を切り離し
  • 本番環境のアクセスログから抜き出したURLを使ってテスト
    • 5.6で遅くなったクエリをチューニング
    • SQLMODE厳格化への対応
  • テスト中に見つけたmroongaのバグはすぐに修正してもらえた
  • HWトラブル
    • マスタ死亡、起動しない、焦げ臭い!さらにもう一台も焦げた。。
  • GTIDよりsemi sync repl + MHAがいいのでわ
  • innodb_file_per_tableでなかったのでダンプしてバージョンアップした
  • memcached APIはバグで使えなかった

@yoku0825さん アプリ担当が出してきたDDLがドイヒーな話

とあるイルカのバーボンハウス from yoku0825
  • すごい心が痛い&共感出来る内容だったけどテンポ早すぎてメモできなかったw
  • MariaDB 10からもGTIDが使えるようになった(ただしMySQLとは結構違う)
  • ログ用テーブル
    • 突っ込みどころたくさんww
  • インデックス名はidx_カラム名_カラム名_…とすると長いけどexplainのときに分かりやすい
  • フレームワークが作る通りではなくDBの特性を考える
  • SQL文を見るだけでどのインデックスを使うかなどの意図が分かる名前付け

@kamipoさん mysql-build

プレゼン資料

  • この辺りトラブル発生してメモがおろそか
  • いろんなMySQLをインストールして使い分ける仕組み
  • percona serverのmysqldumpにはkeyを消してダンプして作り直すオプションがある
    • ダンプが高速化
  • fbの5.6にはlogical key readのオプションがある

@do_akiさん multi master replication

殿堂入りのアレ~Multi-Source Replication を添えて~ from do_aki
  • MySQL Casual定番の内容
  • change masterを2秒ごとに切り替えてマルチマスタ
  • 5.7では標準でできるようになった
  • 過去に色々な方法でマルチマスタを試みている人がいるww

@RKajiyamaさん 5.7 Multi-source replication

MySQL Casual Talks vol.5 - MySQL Labs - @RKajiyama from rkajiyama
  • labsにはDMR以前のものがありますよ
    • hadoop applier for mysql
      • hadoopをMySQLスレーブのように使う
    • JSON UDF
    • Multi source replication
    • MySQL Utilities Fabric
      • シャーディングの情報を管理する仕組み
    • Fabric + multi source replication + multi thread slaveの組み合わせ良さげ

@songmuさん

プレゼン資料

  • GitDDL::Migrator, SQLTranslator(SQLFairy)
    • ブランチごとにテーブルやカラムが違うと大変
    • テーブル構成の違いなどが表示できる
    • ブランチを行ったり来たりしながらalterしたりできる
  • App::RunCron
    • perlのラッパー、レポータを書くと色々できる
    • cronのログってnullに捨てちゃうけど困るよね
    • cronlog
    • cronの処理をラップしてエラー処理が可能

@nekogeruge_987さん DB2からMySQL5.5への移行

  • 13年運用されてるデータベース
  • レコードをCSVにしてload infile
  • シェルスクリプトで自動化
  • 4時間以内に終わらせるという時間制約
    • loadを高速化する工夫
    • ジョブフローの最適化(jenkins build flow plugin)
    • ジョブフローをGroovyで書ける(並列実行などなども可)
    • データ移行自体をCIする(1クリックデータ移行!)
    • /var/lib/mysql以下の並列rsync

@monryさん Amazon RDS

20131025 my sql casual talks vol.5 from Tetsuya Mori
  • マスタ1台、スレーブ5台
    • 243ドル/月
  • 物理サーバが1台13万以上ならRDSの方が安い(3年償却)

@chobi_eさん ストレージエンジンを作ってみた