Minecraft Server の JVM をモニタリングする

目的

Minecraft が高負荷になる場合に FullGC が発生したかなどの JVM 側の負荷なのか 単純に Minecraft 自体での処理が重いのかなどの切り分けを行うためにモニタリングしたい。

方法

自分のサーバは基本的に prometheus によるモニタリングを行っているので Minecraft のサーバ自体のモニタリングが行えるとよい。

GitHub - prometheus/jmx_exporter: A process for exposing JMX Beans via HTTP for Prometheus consumption

手順

前提

  • Minecraft が運用されている
  • Prometheus が運用されている
  • Grafana が運用されている

JMX のメトリクスを取得できるようにする

jmx_exporter によるメトリクスの取得を行うための javaagent の jar を落とす。

$ curl -OLJ https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.3.1/jmx_prometheus_javaagent-0.3.1.jar

jmx_exporter 用の config ファイルを用意。今回は簡単のため空ファイルを作成。

$ touch config.yaml

javaagent のオプションを指定して起動。jmx_exporter の jar ファイルはパス指定でも良さそうだが config.yaml がうまく動かなかったので場所を変えたい場合は要確認。下記は 8080 ポートで開く例。(実運用では jmx_exporter で 8080 はあまり使わない)

java -jar -javaagent:.jmx_prometheus_javaagent-0.3.1.jar=8080:config.yaml  -jar minecraft_server.jar nogui

Prometheus で メトリクスを取得するようにする

簡単な例。正確な記述は割愛。

  - job_name: jmx
    static_configs:
    - targets: ['xxx.xxx.xxx.xxx:port']

グラフの用意

最近の Grafana では公式のページにある程度設定されたダッシュボードがあり、これを import することによってだいたいそのまま使うことができる様子。

https://grafana.com/dashboards/3457

下記のような表示になる。GC カウントも見られ、FullGC が多いかどうかを確認でき、メモリバウンドなのかなどの確認がしやすくなる。

f:id:nise_nabe:20180830225535p:plain

結果

自分のサーバでは特に FullGC が発生してはいなかった。 原因としてログインしているユーザによる牧場で牛や豚が大量にいたことが原因のようだった。

その他

prometheus で minecraft 特有のメトリクスを取得も可能な様子。

https://github.com/sladkoff/minecraft-prometheus-exporter

この exporter は spigot という minecraft server に MOD が導入できる(api 利用が可能になる)ものを利用することによって可能な様子。自分はバニラサーバで動かしているので一旦導入は保留。

Spring Boot 2 アップグレード後に JPA ( Hibernate )が勝手に SEQUENCE を使おうとする問題

問題

Spring Boot 1.5 -> 2.0 に上げたとき MySQLJPAHibernate)経由で利用している場合、 GeneratedValue に AUTO を指定していると INSERT 処理時などに下記のような例外が発生する可能性がある。

Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException Table 'xxx.hibernate_sequence' doesn't exist

原因

Spring Boot の AutoConfiguration では hibernate を使う際に hibernate.id.new_generator_mappings の値のデフォルト値が false になっており、native の id generator が使われていたが Spring Boot 2 になったタイミングでデフォルト値が true になった。 hibernate.id.new_generator_mappings が true の場合、Hibernate 5 では AUTO が指定された場合は常に SEQUENCE 扱いとなる様子。MySQL の場合は SEQUENCE に対応していないため AUTO にしている状態では動かなくなる。

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide

Id generator

The spring.jpa.hibernate.use-new-id-generator-mappings property is now true by default to align with the default behaviour of Hibernate. If you need to temporarily restore this now deprecated behaviour, set the property to false.

Spring Boot 1.5

https://github.com/spring-projects/spring-boot/blob/v1.5.14.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java#L207

        result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "false");

Spring Boot 2.0

https://github.com/spring-projects/spring-boot/blob/v2.0.3.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaProperties.java#L237

        result.put(USE_NEW_ID_GENERATOR_MAPPINGS, "true");

対応案

下記2つの対応が考えられる

  • spring.jpa.hibernate.use-new-id-generator-mappings の設定を 明示的に false を使う
  • 対象となる GeneratetedValue アノテーションすべてに明示的に IDENTITY を指定する

id generator が false は deprecated とあるので true のほうがよさそうだが デフォルトの AUTO のままでは IDENTITY が使われるルートがなさそうなので一括で対応する方法はなさそう。

参考 URL

letsencrypt の certbot renew を apache plugin から nginx(webroot) に切り替える

環境

内容

もともと apache がサポートされていたため apache を利用して letsencrypt を利用していたが nginx を使うように変更したため nginx で直接 https 処理を行うように変更したい。

$ vim /etc/letsencrypt/renewal/example.com.conf

下記のようになっているはず

# Options used in the renewal process
[renewalparams]
authenticator = apache
installer = apache
account = ......

これを下記のように書き換える

# Options used in the renewal process
[renewalparams]
authenticator = webroot
installer = None
account = ......
[[webroot_map]]
example.com = /path/to/webroot

このあとそのまま certbot renew をするとよい。 また cron で自動で確認するようになっていると思うので /etc/cron.d/certbot の内容の一部を下記のように書き換える。reload でもいいかもしれないが自分の環境では特に気にすることもないためそのまま restart している。

.... && certbot -q renew
↓
.... && certbot -q renew --post-hook "service nginx restart"

--post-hook か --renew-hook がいいかは1年ぐらい運用したけど毎回失敗しててよくわからなかった。

BSD + ansible で sysrc を用いて利用可能にする

BSD 系では rc.conf に *_enable="YES" のような形で設定しないと init script 等で起動しない挙動をするようにするのが一般的な様子?(詳しくは未調査)

ansible でこのあたりを編集するのはつらいのでコマンドを用いて設定できるようにするには sysrc を使うと便利。 sysrc はどうやらデフォルトで入ってなさそう(少なくとも DragonflyBSD においては)なのでこれをインストールするタスクも入れる必要がある。 (汎用的に使うには role に設定して dependences にいれておいたほうが便利そう)

- name: install sysrc
  package:
    name: sysrc
    state: present

- name: enable openvpn
  command: sysrc -ni openvpn_enable="YES"
  register: openvpn_enable_rc
  changed_when: (openvpn_enable_rc.stdout == "NO -> YES") or (openvpn_enable_rc.stdout == " -> YES") 

上記の動作確認は DragonflyBSD で行ったがこの sysrc は存在してもしなくて return code は 0 を返すため設定に成功したかどうかわからず そのままでは changed 設定ができない。苦肉の策として標準出力を用いている。

sysrc の 実行例

以下はもとに設定がない場合。

n をつけない場合

$ sysrc openvpn_enable="YES" 
openvpn_enable:  -> YES

n をつけた場合

$ sysrc -n openvpn_enable="YES" 
 -> YES

i をつけない場合

$ sysrc openvpn_enable
sysrc: unknown variable 'openvpn_enable'

i をつける場合何もかえらない。そのキーが存在しない場合に sysrc: unknown variable 'openvpn_enable' といったメッセージを出す場合があるので前述の ansible task では 念のためつけている。(影響があるのは 設定する場合と -x で削除する場合)

$ sysrc -i openvpn_enable

e は以下のように ダブルクオーテーションの挙動がなにかおかしいので使ってない。

$ sysrc -e openvpn_enable="YES"
openvpn_enable=" -> YES

さくらの VPS 上の DragonflyBSD で ipv6 ネットワーク設定をする

環境

  • さくら のVPS
  • DragonFly v5.0.2-RELEASE

準備

さくら VPS のコントロールパネルで IPv6 アドレスとゲートウェイを確認する。 自分の場合は特に申請してなくてもついていたのでデフォルトで付いている様子。(契約タイミングやデータセンターによるかもしれない) -この IPv6 アドレスは サフィックスIPv4 アドレスが付いているパターンのものらしい [1]. - 追記)と思ったけど よーく見るとコンパネの記載にあるのは ドットではなくコロンのため、単純に同じ数字を用いた ipv6 アドレスという可能性のほうが高そう。

設定

vtnet0 インタフェースを用いる場合

/etc/rc.conf

# IPv6
ipv6_enable="YES"
ipv6_network_interfaces="vtnet0" # あってもなくてもいい
ipv6_defaultrouter="fe80::1%vtnet0"
ipv6_ifconfig_vtnet0="inet6 (コントロールパネルに表示されるIPv6アドレス) prefixlen 64"

他の設定については /etc/defaults/rc.conf を確認。

簡単に各項目を説明。

key default description
ipv6_enable NO ipv6 を使う場合に YES ( FreeBSD 9 以降?では 使うべきではないらしい が DragonflyBSD では関係ない様子)
ipv6_network_interfaces auto auto の場合は ifconfig -l の結果が入る。自分の場合は 別の設定名で インタフェースが必要なのでそれを使うという意図で明示している。
ipv6_defaultrouter NO コンパネで確認する ゲートウェイを入れる。 そのままだとなぜか通じないのでインタフェース名を入れると動く。( netstat -f inet6 -rn などを見ると %lo などがついている場合があったので)
ipv6_ifconfig_vtnet0 - ifconfig で設定する内容 ipv6_ifconfig プレフィックス の設定はipv6_network_interfaces の値に入っている場合に使われる様子

設定後は ssh で繋いでる場合は 下記の様にするとおそらく良い [2]。 ipv6 設定を反映するためには /etc/rc.d/network_ipv6 を使ったほうが良さそうな気がしてとりあえず入れているがきちんと検証してない。

$ sudo /etc/rc.d/netif restart && sudo /etc/rc.d/routing restart && sudo /etc/rc.d/network_ipv6 restart

つながっているかどうかは 外から ping6 を実行するなどして確認 [3]。

発生した問題

ping6 や sshipv6 アドレスを直接指定して動かした場合に動作せず、サーバ側のコンソールで下記のようなエラーが出る現象があった。

nd6_storelladdr: sdl_alen == 0
nd6_storelladdr: sdl_alen == 0
nd6_storelladdr: sdl_alen == 0

このエラーが出ている部分はこのあたり。 impossible と書いてあるけど…

/usr/src/sys/netinet6/nd6.c

2091     if (sdl->sdl_alen == 0) {
2092         /* this should be impossible, but we bark here for debugging */
2093         kprintf("nd6_storelladdr: sdl_alen == 0\n");
2094         m_freem(m);
2095         return (0);
2096     }

自分の場合の原因は、ipv6 アドレスの設定部分だった様子。 記事によっては ifconfig_vtnet0_ipv6 のような ifconfig プレフィックスになっている場合があるが、 少なくとも自分の環境ではこれでは動作せず、上記のような謎エラーが表示される。

ipv6 を prefix とするような設定にするとたぶん大丈夫。 このあたりは /etc/network.subr 内 network6_interface_setup 関数で呼ばれている様子なので詳しい挙動を見たい場合はこのあたりを参考に。

参考文献

2017年 まとめ

技術編

  • http client に詳しくなった
  • mockito をまともに使い始めた
  • spring framework をまともに使い始めた
  • spring boot をまともに使い始めた
  • gradle をまともに使い始めた
  • ansible をまともに使い始めた
  • Raspberry Pi を手に入れた

ゲーム編

漫画編

4 桁行かないぐらいだけど書ききれないので割愛

コーヒー編

  • コーヒーに凝り始めた
  • 機器
    • twinbird の サイフォンコーヒーメーカーを買った
    • マキネッタ(モカエキスプレス)を買った(壊れた)
    • デロンギエスプレッソマシンを買った
    • 有田焼セラミックフィルターを買った
    • HARIO のウォーターブリューコーヒーメーカーを買った
  • SCAJ 2017 に行った
  • コーヒー豆を買った(合計推定 10 kg )

その他

  • ネパールに行った
  • 国内の旅行に何回か行った
  • 壊れたエアコンで暑さに耐えきれずに引っ越しをした

wp-comments-post.php への投稿が 405 Method Not Allowed になる問題

確認環境

問題

wordpress の記事のコメント投稿が 405 Method Not Allowed になる

確認される現象

記事詳細ページのコメント欄へコメントできない

原因

条件1 : nginx の設定

nginx の location ディレクティブで .php を指定して fastcgi に引き渡している。

https://codex.wordpress.org/Nginx#General_WordPress_rules

upstream php {
        server unix:/tmp/php-cgi.socket;
        server 127.0.0.1:9000;
}
...
server {
        ...
        location ~ \.php$ {
                ...
                fastcgi_pass php;
                ...
        }

条件2: iThemes Security の「コメントスパム」設定が有効

iThemes Security で該当項目を有効にしていると 生成される nginx.conf で以下のような 設定が出力される。

        # コメントスパムを削減 - セキュリティ > 設定 > WordPress の微調整 > コメントスパム
        location = /wp-comments-post.php {
                limit_except POST { deny all; }
                if ($http_user_agent ~ "^$") { return 403; }
                valid_referers server_names jetpack.wordpress.com/jetpack-comment/;
                if ($invalid_referer) { return 403; }
}

上記より

nginx の location ディレクティブは最長一致の設定が用いられる[1]。 そのため条件1で設定した .php の location よりも 条件2の /wp-comments-post.php が優先されるはず。そして 条件2の設定では fastcgi_pass がないためそのまま静的ファイルとして処理される。 nginx は静的ファイルの場合は POST は許可されないため 405 になる[2]。

解決方法

このままだとコメントスパム対応部分が弱いとも考えられるので コメントスパム部分は別のプラグインに任せるか、上記設定を参考にして自分で fastcgi_pass をする設定を追加するなどすればよい気もする。

(余談) iThemes Security が出力する設定を変更することはできないため、対象 location ディレクティブに fastcgi_pass を設定できない。 そして自分は location ディレクティブに fastcgi_pass を記載することなく設定する方法がわからない、というのと wordpress を運用しようとしている人の nginx 力はそんなに高くないと思っているため 技巧を凝らした nginx 設定するのはあんまりよくない気もする。ので「コメントスパムを off にする」ぐらいしか思いつかない。

参考 URL