トップ ソフト 雑記 日記 リンク

2019年3月3日日曜日

システム稼働状況ページを作った

Service status osa-p.net を作った話。

元々、zabbixでシステムの状況はモニタリングしているのだが、それを外部に公開する仕組みを用意していなかった。zabbixのページをそのまま公開したくなかったので、必要な情報だけ抽出して表示できる仕組みが欲しかった。


SNSでつぶやいてみると

UptimeRobotというサービスを紹介してもらえた。

早速設定してみたところ、格好良い稼働状況ページが出来上がったのだが、うちのシステム上、ウェブサーバとデータベースが分離しており、データベースを使う処理は動かないが、ウェブサーバだけで完結する処理は動くという状況があり得て、その表示がしにくいなと感じた。

そこで、やはり自前で処理を作るかと、ついでに使ったことのなかったVueも試しに取り入れてみた。普段仕事でもまだまだjQueryを使うことが多く、また思い付いたサービスを個人で作るときにも早く公開したくて慣れているjQueryを使ってしまうことが多い。今回は急ぐものでもなかったので、サンプル程度しか動かしたことのなかったVueを使ってみた。といっても、やはりサンプルの継ぎはぎではあるのだけど。

処理自体は問題無くできて、さて公開するかというところで問題があった。
稼働状況ページは、自分が管理しているシステムの中で動かしてしまうと、一緒に落ちたときに肝心の状況が見えなくなってしまうので、公開ページは別のサービスで動かしたかった。まず最初に選んだのがS3で、ここでは静的サイトを公開する情報も整っていたので簡単に設定して公開。あとはネームサーバとして使っているCloudflareでCNAMEを張ってやれば動くだろうと考えていた。

実際に公開してみたところ、httpでは繋がるのだが、httpsでは接続ができなかった。S3の公開では、「https://S3ドメイン/バケット名/」だとhttpsが使えるのだが「https://バケット名.s3ドメイン」ではhttpsが使えない。Cloudflare側でHTTP Proxyを有効にしていたら、オリジンサーバーがhttpでも使えたような記憶があったのだけど、どうも上手く行かないので間にCloudFrontを挟んでhttpsでも繋がるようになった。

しかし別の問題が発生した。ページの作りとしては、zabbixから出力したSLAの情報をS3に5分毎にアップロードし、静的ページ側でそれを読み込んで表示する。CloudFrontは読み込んだ情報をキャッシュしてしまうので、いつまでも古い情報が表示されてしまうのだ。もちろんCloudFrontの設定にも用意されているので、TTLの設定を5分にしてみたり、クエリが付いていたらキャッシュしない設定にしたり、キャッシュをクリアしてみたりしたのだが、どうにも解消できなかった。

結局Netlifyで静的ページ部分を配信しつつ、データはS3から読み込むという仕組みで解決した。このやり方ならGitHub Pagesでも大丈夫だろうが、最初すべてをGitHub Pagesで配信しようと考えてしまい、5分毎にコミットとプッシュをしたら怒られそうだなと思って頭の中からGitHubを使うことを取り除いてしまっていた。

ひとまず大枠の仕組みが完成したので、これを応用して、zabbixに入力したメンテナンス情報を各サービスで表示したり、自動でメンテモードに切り替えたりもできるだろう。今はデータベースを止めるメンテナンスがあるときに、各サービスのcronを止めたり、フラグを立てたりと手動で処理してアクセスが止んだのを確認してから作業したりしているので、この辺りも自動化してしまいたいと考えている。



2019年1月27日日曜日

PostgreSQLのshared_buffers設定とZFSのARCの関係を調べた

いつも個人のプロジェクトではPostgreSQLを使っており、自宅サーバで大きいデータベースを運用しています。最近まではmdadmで組んだRAID-5の上に、ext4でファイルシステムを作って、その中にデータベースのテーブルスペースを置いていました。
しかし、最近ZFSを使い始め、同じようにRAID-Zでファイルシステムを作ってテーブルスペースを置くようになりチューニングを再確認していたのですが、少し気になることが出てきたので調べてみました。

PostgreSQLのshared_buffers設定

PostgreSQLの設定には、shared_buffersというものがあり、搭載されているメモリから共有メモリを確保して、PostgreSQLの各プロセスが利用しています。この値は
1GB以上のRAMを載せた専用データベースサーバを使用している場合、shared_buffersに対する妥当な初期値はシステムメモリの25%です。 shared_buffersをこれよりも大きな値に設定することが有効なワークロードもあります。 しかし、PostgreSQLはオペレーティングシステムキャッシュにも依存するため、shared_buffersにRAMの40%以上を割り当てても、それより小さい値の時より動作が良くなる見込みはありません。(PostgreSQL日本語ドキュメント 19.4. 資源の消費より)
とあり、あまり大きくしても効果が無いとまで書かれています。
実際にext4でテーブルスペースを管理していた時は、この設定でhtopをみると搭載メモリの利用状況を示すバーの約25%が緑色、約75%が黄色となり、キャッシュが有効に働いていることが確認できました。

ZFSのARC設定

ZFSにはARCと呼ばれるメモリ上のキャッシュ機構を持っています。これは空きメモリから使用され、ディスクから読み出した際にARCにも格納され、同じデータの読み出しが発生した場合はディスクを参照せずここから読み出すことによって高速化を行います。ZFSを開発したSunのエンジニアが、MySQLで使う場合のチューニング指標として
ZFS上でMySQL/InnoDBを利用する場合、利用されるキャッシュにはいくつかの階層が存在します。InnoDB自身がバッファプールを持っていますし、ZFSにはARCがあります。そして、それらのキャッシュは個別に何をキャッシュまたはフラッシュすべきかということを判断するようになっています。そして、それらが同じデータをキャッシュするというような状況が生じてしまうこともあるでしょう。InnoDB内でキャッシュすると、データへたどり着くまでにより短い(そして高速な)コードパスで済むでしょう。そして、InnoDB内でキャッシュミスが生じれば、例えそのデータがARCに存在していたとしてもダーティページのフラッシュが生じてしまうことになります。これは不要な書き込みを生じさせる原因となります。ARCは利用可能なメモリの容量によって(自)動的に縮退・拡張しますが、単にそれを制限する方がより効率的です。我々が実施したテストでは、ZFS内でキャッシュするよりInnoDB内でデータをキャッシュしたほうが7〜200%の性能向上が見込めることを確認しています。(翻訳を紹介している漢(オトコ)のコンピュータ道: 違いが分かるエンジニアのためのMySQL/InnoDB/ZFSチューニング!より)
と紹介されています。このため、データベースでZFSを利用する場合ARCのキャッシュ情報はallではなくmetadataのみをキャッシュするように設定するという紹介をあちこちで見かけます。

鵜呑みにして設定

わたしもこれを読んで同じように設定していたのですが、思った以上にパフォーマンスが上がらず、はてどうしたものかと悩んでいました。そしてふと気が付いたのが、htopで表示されるメモリの使用状況バーは搭載メモリの25%だけが緑でキャッシュが全く使われていない状況でした。つまりメモリの25%しか使っていない状態でした。

ということは、ext4ではOSの標準設定によりキャッシュが働いているからshared_buffersを増やさなくても良いということなのですが、ZFSでキャッシュを最低限にしている場合、shared_buffersを確保した方がいいのではないか?ということです。

そこで、PostgreSQLにおいてZFSを使用する場合、shared_buffersを増やしたときと、ARCのすべてキャッシュするときのベンチマークを取ってみました。

以下の環境でテストを行いました。
  • Core i7-6700(3.4GHz) Windows 10 Pro上のHyper-Vで実行されるCentOS7
  • カーネル 3.10.0-957.1.3.el7.x86_64
  • CPU割り当て4
  • メモリ 4GB(Hyper-Vの動的メモリは使用しない)
  • ZFS 0.7.12(RPMからインストール)
    zfs set recordsize=128K tank(初期値)
    zfs set compression=off tank(初期値)
    zfs set dedup=off tank(初期値)
  • PostgreSQL 11.1(ソースからビルド)
  • pgbench -i -s 100 bench(1000万件)
  • SELECT pg_database_size('bench'); → 1,576,528,895(データベースサイズは約1.5GB)
  • 設定変更後に再起動。一度pgbench -l -T 60 -c 2 -j 2 -P 10 benchで60秒間のベンチを回して、その後5回分のトランザクション数を記録

テストパターンは以下の4種類です。
  1. 両方鵜呑みにする
    shared_buffers=1GB
    zfs set primarycache=metadata tank
  2. ZFSの言うとおりにデータベースのキャッシュを増やす
    shared_buffers=3GB
    zfs set primarycache=metadata tank
  3. PostgreSQLの言うとおりにファイルシステムのキャッシュを増やす
    shared_buffers=1GB
    zfs inherit primarycache tank(デフォルトがallなので)
  4. 一応両方増やす(サイズ的にshared_buffersが優先になるはず)
    shared_buffers=3GB
    zfs inherit primarycache tank

結果


回数\パターン1234
1656590758773
2552670835822
3613543663644
4586656788794
54766741016987
平均値577627812804
中央値586656788794

ZFSのキャッシュをした方が良いという結果になりました。
パターン2はパターン4と同じになるかと思ったのですが、パターン1よりは性能が良いがパターン3より性能が出ないということで、やはりshared_buffersの設定は増やしすぎても効果が無いようです。
またパターン3とパターン4でも差がないことからshared_buffersを増やすぐらいならARCに回した方が良いという結果になりました。

MySQLでZFSを使うシーンに出会っていないので、今回はPostgreSQLの設定だけですが、やはり実際に測ってみないと分からないものだなと感じました。


ちなみに、ZFSのレコードサイズをデータベースとあわせた方が良いという意見を見かけるので、8Kと16Kを試してみたのですが、

zfs set recordsize=8K tank
回数\パターン1234
1696688681689
2701688690704
3686674631716
4627621639654
5683633678657
平均値679661664684
中央値686674678689

zfs set recordsize=16K tank
回数\パターン1234
1678609682683
2713543682688
3543612604668
4592682680663
5667690689717
平均値639627667684
中央値667612682683

大した有意差が見られず、また128Kの方が成績が良かったことから、うちでも8Kにしていたのを128Kに戻しました。
ARCが効きやすいレコードサイズの設定があるのかと思って検索してみたりしたのですが、それらしいドキュメントは見つけられませんでした。ソースをあたるしかなさそうです。

広告