はじめに
こんにちは。プラットフォーム事業本部 メンバーシップサービス部の井上です。
日頃は、DMMのサービスで使用されている基盤システムにおけるバックエンド周りの開発・保守などを行なっています。
今回はCassandraサーバを運用して行くうえで発生したエラーについてと、それを解消するまでのお話をさせていただきます。
基盤システムのCassandra
自分が所属しているチームでは基盤システムを保守運用している関係でたくさんのログを保存・管理しています。
そして、大量のログを運用することから、私たちのチームではCassandraと呼ばれるNoSQLサーバを使用しています。
https://www.apache.org/licenses/LICENSE-2.0
Cassandraサーバでエラーが出るまで
Cassandraサーバの運用を行なっていたある日、Cassandraに書き込む処理で突然エラーが発生しました。
調査を行なっていくとCassandraサーバのgc周りでエラーが出ていることがわかったのでGCログを解析しました。
GCログの解析には下記サイトを利用しました。
gceasy.io GCログファイルをアップロードすることでGCログを詳細に解析してもらうことができます。
GC形式変更前のGC挙動
上記のGCログを確認すると、赤い三角の部分でFULLGCが走っています。
FULLGCが起きた時間帯とエラー通知のタイミングが同じであったことから、FULLGCがエラーの原因であることがわかりました。
エラー対策
原因が判明したところで次は何かしらの対応が必要になりましたが、そこで対策として一番改善が見込めると判断したのがGC形式の変更です。
始めに対策案として挙げられていたのは、ヒープメモリーの増強でした。
しかし、私たちのCassandraではCMSGCを採用していました。
CMSGCはヒープメモリを16G以上割り当てるとFULLGCが悪化してしまうGC形式であり、私たちはすでに16GB分のメモリをヒープメモリに割り振っている状態だったため、これ以上メモリを割り振ることができませんでした。
そこで、次の案として挙げられたのがCMSGCからG1GC形式への変更です。
CMSとG1GCのどちらを採用したほうが良いかについては下記のようになっています。
G1 is recommended in the following circumstances and reasons:
・ Heap sizes from 16 GB to 64 GB.
・ G1 performs better than CMS for larger heaps because it scans the regions of the heap containing the most garbage objects first, and compacts the heap on-the-go, while CMS stops the application when performing garbage collection.
・ The workload is variable, that is, the cluster is performing the different processes all the time.
・ For future proofing, as CMS will be deprecated in Java 9.
・ G1 is easier to configure.
・ G1 is self tuning.
CMS is recommended in the following circumstances:
・ You have the time and expertise to manually tune and test garbage collection.
・ Be aware that allocating more memory to the heap, can result in diminishing performance as the garbage collection facility increases the amount of Cassandra metadata in heap memory.
・ Heap sizes no larger than 16 GB.
・ The workload is fixed, that is, the cluster performs the same processes all the time.
・ The environment requires the lowest latency possible. G1 incurs some latency due to profiling.
Heap sizes from 16 GB to 64 GB. https://docs.datastax.com/en/Cassandra/3.0/Cassandra/operations/opsTuneJVM.html
G1GCではヒープメモリーに最大64GBまでメモリーを割り振ることができ、CMSGCよりも多くのメモリーを割り振ることができます。
他にも、CMSより設定が簡単な点など、私たちの運用してるサーバではCMSGCよりG1GCのほうが条件に適していることがわかりました。
上記内容から私たちのチームでは、CMSGCからG1GC(Garbage First Garbage Collection)に変更することにしました。
今回はG1GCについて詳細な仕組みまではご説明致しませんが、もし詳細な仕組みを知りたい場合は下記スライドがとても参考になるものとなっています。
では早速、GC設定を変更していきます。
今回変更を加える設定ファイルは下記になります。
Cassandra ├── NOTICE.txt ├── NEWS.txt ├── LICENSE.txt ├── CHANGES.txt ├── interface ├── doc ├── javadoc ├── tools ├── pylib ├── lib ├── bin ├── conf │ └── metrics-reporter-config-sample.yaml │ └── logback.xml │ └── logback-tools.xml │ └── jvm.options ← ################ このファイルに変更を加えます。 ################ │ └── hotspot_compiler │ └── cqlshrc.sample │ └── commitlog_archiving.properties │ └── Cassandra-topology.properties │ └── Cassandra-rackdc.properties │ └── Cassandra-jaas.config │ └── Cassandra-env.ps1 │ └── README.txt │ └── triggers │ └── Cassandra.yaml_org │ └── Cassandra.yaml │ └── Cassandra-env.sh └── logs
変更前の jvm.optionsのGC形式が書かれている箇所です。
Apache #-Xms4G #-Xmx4G #-Xmn800M ################# # GC SETTINGS # ################# ### CMS Settings -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSWaitDuration=10000 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSEdenChunksRecordAlways # some JVMs will fill up their heap when accessed via JMX, see CASSANDRA-6541 -XX:+CMSClassUnloadingEnabled ### G1 Settings (experimental, comment previous section and uncomment section below to enable) ## Use the Hotspot garbage-first collector. # -XX:+UseG1GC # -XX:G1RSetUpdatingPauseTimePercent=5 # -XX:MaxGCPauseMillis=500 ## Optional G1 Settings # -XX:InitiatingHeapOccupancyPercent=70 # -XX:ParallelGCThreads=16 # -XX:ConcGCThreads=16
CMSGCの設定が書かれていますので、下記のようにG1GCの設定に変更します。
-#-Xms4G -#-Xmx4G +-Xms32G +-Xmx32G -#-Xmn800M +-Xmn800M ################# # GC SETTINGS # ################# ### CMS Settings --XX:+UseParNewGC --XX:+UseConcMarkSweepGC --XX:+CMSParallelRemarkEnabled --XX:SurvivorRatio=8 --XX:MaxTenuringThreshold=1 --XX:CMSInitiatingOccupancyFraction=75 --XX:+UseCMSInitiatingOccupancyOnly --XX:CMSWaitDuration=10000 --XX:+CMSParallelInitialMarkEnabled --XX:+CMSEdenChunksRecordAlways +#-XX:+UseParNewGC +#-XX:+UseConcMarkSweepGC +#-XX:+CMSParallelRemarkEnabled +#-XX:SurvivorRatio=8 +#-XX:MaxTenuringThreshold=1 +#-XX:CMSInitiatingOccupancyFraction=75 +#-XX:+UseCMSInitiatingOccupancyOnly +#-XX:CMSWaitDuration=10000 +#-XX:+CMSParallelInitialMarkEnabled +#-XX:+CMSEdenChunksRecordAlways # some JVMs will fill up their heap when accessed via JMX, see CASSANDRA-6541 --XX:+CMSClassUnloadingEnabled +#-XX:+CMSClassUnloadingEnabled ### G1 Settings (experimental, comment previous section and uncomment section below to enable) ## Use the Hotspot garbage-first collector. -# -XX:+UseG1GC -# -XX:G1RSetUpdatingPauseTimePercent=5 -# -XX:MaxGCPauseMillis=500 +-XX:+UseG1GC +-XX:G1RSetUpdatingPauseTimePercent=5 +-XX:MaxGCPauseMillis=500 ## Optional G1 Settings -# -XX:InitiatingHeapOccupancyPercent=70 -# -XX:ParallelGCThreads=16 -# -XX:ConcGCThreads=16 +-XX:InitiatingHeapOccupancyPercent=70 +-XX:ParallelGCThreads=16 +-XX:ConcGCThreads=16
変更後はヒープメモリの割り当てを32GBに変更しています。
その他、G1GCに必要な設定を入れています。
下記のような設定ファイルに変更を加えたあとは1台ずつ再起動をかけていき設定を読み込み直します。
GC形式変更後、GC挙動を確認したところ下記のようになりました。
GC形式変更後のGC挙動
FULLGCが起きなくなり、gc周りでかかっている時間もかなり改善されたことがわかります。
以上、今回はCassandraでFULLGCが起きた際の対策についてお話しさせていただきました。
同じ問題が起きている方がいらっしゃいましたらぜひ参考にしていただけたらと思います。
おわりに
採用情報をお伝えします。 私が所属するプラットフォーム事業本部 メンバーシップサービス部では、一緒に働く仲間を募集しています。 2,900万人のユーザを支える会員プラットフォームの開発、運用に少しでもご興味のある方はぜひご応募ください!