jettyサーバで、jmx経由でJMV統計を取る方法。

${jetty.base}/start.iniファイルの末尾に以下を追記する。

#
# Initialize module jmx-remote
#
--module=jmx-remote
## JMX Configuration
## Enable for an open port accessible by remote machines
jetty.jmxremote.rmihost=localhost
jetty.jmxremote.rmiport=1099

 

一応これで、rmiで1099ポートにポートにアクセスすると、

JVMのモニタリングができる。

 

以上

投稿日時:2017年06月24日 23:14   カテゴリー:java  

rabbitmqでクラスターを組む際、

クラスターに参加するノードすべてが名前解決によって、

他ノードに接続する仕様となっている。

hostsファイルやdnsmasqなどの簡易DNSを立てるのが簡単ではあるが、

クラウド環境を使っていると、hostsファイルやresolve.confファイルなどが、

再起動等で書き換えられしまうケースもある。

そこで、独自に名前解決を行う必要があるのだが、

erlangの名前解決手法が意外にハマったので、

クラスターの構築手順と合わせて備忘録を残しておく。

 

[バージョン]

os:centos7.2

rabbitmq:3.6.10(rpmで入れた)

 

[前提]

各ノードの情報は以下の通り。

  • 192.168.15.11(ホスト名はbroker01)
  • 192.168.15.12(ホスト名はbroker02)
  • 192.168.15.13(ホスト名はbroker03)

 

[クラスターの構築手順]

1.インストールしたら、とりあえずbroker01,02,03の全台で起動

# systemctl start rabbitmq

この時点では各ノードが個別に動いている状態である。

 

2.broker01,02,03に/etc/rabbitmq/hostsというファイルを以下内容で配備

192.168.15.11 broker01
192.168.15.12 broker02
192.168.15.13 broker03

 

3.brker01,02,03に/etc/rabbitmq/erl_inetrcというファイルを以下内容で配備

{hosts_file, "/etc/rabbitmq/hosts"}.
{lookup, [file,native]}.

 

4.broker01に/etc/rabbitmq/rabbitmq-env.confというファイルを以下内容で配備

export ERL_INETRC=/etc/rabbitmq/erl_inetrc

RABBITMQ_NODENAME=rabbit@broker01
# ↓の設定は、独自です。なければ、デフォルトが適用されます。
RABBITMQ_LOGS=/var/log/rabbitmq/rabbitmq.log
RABBITMQ_SASL_LOGS=/var/log/rabbitmq/rabbitmq-sasl.log
RABBITMQ_PID_FILE=/var/run/rabbitmq/rabbitmq.pid
RABBITMQ_NODE_IP_ADDRESS=0.0.0.0
RABBITMQ_NODE_PORT=5672
RABBITMQ_DIST_PORT=5675

 

5.broker02に/etc/rabbitmq/rabbitmq-env.confというファイルを以下内容で配備
export ERL_INETRC=/etc/rabbitmq/erl_inetrc

RABBITMQ_NODENAME=rabbit@broker02
# ↓の設定は、独自です。なければ、デフォルトが適用されます。
RABBITMQ_LOGS=/var/log/rabbitmq/rabbitmq.log
RABBITMQ_SASL_LOGS=/var/log/rabbitmq/rabbitmq-sasl.log
RABBITMQ_PID_FILE=/var/run/rabbitmq/rabbitmq.pid
RABBITMQ_NODE_IP_ADDRESS=0.0.0.0
RABBITMQ_NODE_PORT=5672
RABBITMQ_DIST_PORT=5675

6.broker03に/etc/rabbitmq/rabbitmq-env.confというファイルを以下内容で配備
export ERL_INETRC=/etc/rabbitmq/erl_inetrc

RABBITMQ_NODENAME=rabbit@broker03
# ↓の設定は、独自です。なければ、デフォルトが適用されます。
RABBITMQ_LOGS=/var/log/rabbitmq/rabbitmq.log
RABBITMQ_SASL_LOGS=/var/log/rabbitmq/rabbitmq-sasl.log
RABBITMQ_PID_FILE=/var/run/rabbitmq/rabbitmq.pid
RABBITMQ_NODE_IP_ADDRESS=0.0.0.0
RABBITMQ_NODE_PORT=5672
RABBITMQ_DIST_PORT=5675

 

7.broker01,02,03に/etc/rabbitmq/rabbitmq.configというファイルを以下内容で配備

[
  {rabbit,
    [
      {loopback_users, []},
      {tcp_listen_options,
        [
          {backlog, 1024},
          {nodelay, true},
          {exit_on_close, false}
        ]
      },
      {vm_memory_high_watermark, 0.4},
      {disk_free_limit, "2GB"},
      {cluster_partition_handling, pause_minority}
    ]
  },
  {rabbitmq_management,
    [
      {listener, [{port, 5676}]}
    ]
  }
].

上記はあくまで一例で、ノード分断の際の生き残り戦略として、小数をダウンさせるという設定にしてます。

 

8.broker01,02,03の/var/lib/rabbitmq/.erlang.cookieファイルの内容を同じにする。
ここで、同ファイルの所有者はrabbitmq:rabbitmqで、権限は0400とする。

 

上記状態で、全ノードを再起動することで、

クラスター状態が完成する。

 

あと、rabbitmq-server.serviceファイルはちょっと変更して以下のようにしている。

デフォルトだと、nofile,noprocあたりがなかったような気がする。。

[Unit]
Description=RabbitMQ broker
After=syslog.target network.target

[Service]
Type=notify
User=rabbitmq
Group=rabbitmq
WorkingDirectory=/var/lib/rabbitmq
ExecStart=/usr/sbin/rabbitmq-server
ExecStop=/usr/sbin/rabbitmqctl stop
NotifyAccess=all
TimeoutStartSec=3600
LimitNOFILE=65536
LimitNPROC=65536

[Install]
WantedBy=multi-user.target

 

公式のドキュメントにだいたい書いてある通りですが。。

気になるのは、hugepageとか、OSレベルのIOのスケジューリングとかかな。

あとは、負荷テストやるのみ。。

また、負荷テストやったら書こうと思います。

 

以上

投稿日時:2017年06月24日 22:50   カテゴリー:rabbitmq  

信頼性の高いメッセージキューを使って、

遅延処理を行うケースの重要性について最近考えるようになった。

そのため、AMQPとか調べていて、rabbitmqを使ってみようかと考えた。

 

とはいえ、rabbitmqはAMQP0.9をベースとしており、

AMQP1.0をベースにしていないなどの点において、

採用候補としては迷うところである。

ActiveMQとかの方がいいかもね、という考えもある。

AMQPではないが、kafkaなどもよさげではあるが、

簡単に調べて、rabbitmqが良さげな点としては、

  • 貧弱サーバでもある程度動く(と思っている)
  • クラスター機能が単体で存在している

といったところでしょうか。

riakを検証しててなんとなくわかったのですが、

開発言語であるerlangはそれほど大きなメモリを使わず、

マルチコアの利用も上手な印象であったため、

他サーバへの相乗り等、縮小することも考えると、悪くないかなーといった具合で検証を進めるてみることにしたというわけです。

ActiveMQやkafkaだと、貧弱サーバで動かすのは厳しい感じがしてます。。

 

で、簡単ながら、検証してみたことろ、メッセージの信頼性の度合はプログラムに依存するような印象を持ってます。

rabbitmq本体に、キューのタイプなどを定義できるのかなーと思っていたが、

特段相違そのような設定などは見られなったため、

プログラムの書き手が信頼性の確保処理の速度について理解しておく必要があるという点が、

中々やっかいでもある反面、融通も効きやすい感じである。

また、諸々検証したら続きを書いてみようと思う。

 

以上

 

投稿日時:2017年06月11日 23:37   カテゴリー:rabbitmq  

以前の記事で、galeraの書き込み能力を向上させるために、

spiderと併用したらいいのではないかと記載した。

しかし、この二つの組み合わせるには、

xa transactions(二相コミット)をあきらめる必要がある。

 

そもそも、galera自体、xaには非対応であり、

また、xa transactionsはバイナリログに対して、クラッシュセーフではないようだ。

(MySQLのドキュメントには記述があったが、MariaDBには記載を見つけられなかった。。)

 

上記前提を踏まえたうえで、

galeraとspiderの共演を実現するためには、xaをあきらめることは必須だが、

そもそもの話として、実装上複数ノードのwriteを極小化しておく必要が十分にあると考えられる。

 

これまで、プログラム側では、begin,begin,commit,commitみたいな実装を平気でしていたが、

そもそもこれ自体が出来るだけ避ける必要のある実装であることを、

今回のgaleraとspiderの共演を実現するために調査していた過程で気づいた。。。

今更の話だが、commitは失敗しないだろうという気持ちがどこかにあり、commitの失敗をリカバリーすることが頭の中から抜けていたように思えて反省している。

 

とはいえ、とはいえ、spiderを挟むことで、

プログラムのシャーディング負担を軽減し、

さらにgaleraで高可用性を確保する組み合わせは、とても魅力的ではある。

 

どこかで、galeraとspiderを共演するために、必要な設定・注意事項等をまとめようと思う。

検証した結果の結論から先に書くと、spiderは受信したSQLを変化させて、バックに投げるため、

場合によっては、SQLの発行回数の増加や、参照取得行数の増加が発生する。

この変化パターンを正確につかんでおかないと、気づかないうちに高負荷をバックに与えてしまう可能性があるため、十分に注意したい。

どっかでこのあたりもまとめてみようと思う。

 

以上

投稿日時:2017年06月11日 23:07   カテゴリー:mariadb, mysql  

MariaDBで準同期レプリケーションで、

猛烈に書き込み中に、MariaDBを停止させ、

単純にslaveを昇格させただけでは、ロストする。

binlogをmasterから救い出さないといけない。

mhaではbinlogを救い出すという処理があるようだが、

当方が使っていたMariaDB Replication Managerにはそのような機能がない。

 

これに対し、Galleraで同じことをやっても、

ロストしなかった。

 

もうちょっといろいろなパターンでやってみないと分からないが、

Galleraのデータ整合性は、準同期よりも1ランク高い気がしている。

ただ、Galleraは書き込み性能がイマイチなので、

フロントにSpiderを置いて、shardingすれば、

高可用性・高負荷耐性をもったシステムが作れそうな気がしている。

 

また進展あれば、記載したいと思う。

 

以上

投稿日時:2017年05月21日 00:50   カテゴリー:mariadb, mysql  

分散型KVSで、cassandraと同じようにリング型マルチマスターの特徴をもつ、riakというKVSがある。

今回riakについて諸々検証してみたので、載せておく。

 

[バージョン]

riakKV2.3.3

 

[試験内容]

500万キーで、protobufを使い、20KBのバイナリデータのPUT/GETの繰り返した。

PUT/GETの繰り返し間隔は約0.1秒で、JAVAの公式が提供するriakライブラリを使って、1時間程度試験を行った。

 

[サーバスペック]

8core/7.2GB/SSD.100GBの仮想マシンの6クラスター

 

[バケットタイプ]

# riak-admin bucket-type create my_dvv_type '
{
  "props":
  {
    "allow_mult":false,
    "last_write_wins":false,
    "dvv_enabled":true,
    "pw":"one",
    "pr":"one",
    "dw":"one"
  }
}'

 

[結果]

結論として、公式が推奨するbitcaskは使えなかった。

bitcaskは追記型のため、同一キーに対してPUTすると、

爆発的にDISK使用量が増える。

試験を始めて、即座に100GB近くDISKを消費したため、

levelDBに切り替えてテストを行った。

(ちなみに、bitcaskは、使われなくなったキーは、mergeされるまで残り続けるらしく、

mergeの処理というのもとても重いようだ。ここは未検証。)

 

計算上は、

500万キー、1キーあたり20KBのデータ、

6ノード、n_valは3なので、

500万×20KB×3÷6=6GB

となり、実際もだいたい、1ノードあたり、6GB程度のlevelDBのDISK使用量であった。

 

で、気になるパフォーマンスだが、

PUT/GETの繰り返しを秒間3000程度はさばいたところで、

各ノードのCPU使用率が60%くらいであったが、

DISK書き込みのスループットが限界に近づいていた状態であった。

 

また、JAVAでメモリ上にデータのHASH値を保持し、

GET時のHASHと比較したが、ひとつもずれはなかった。

単純に、last_write_wins:trueとしたときは、ずれが生じてしまっため、

同一キーに激しくPUTする環境で、最新のデータを必ず取りたいときは、

"allow_mult":false,
"last_write_wins":false,
"dvv_enabled":true,

の設定がよいのかと思っています。

 

[考察]

riakは永続性が求めれる大量のデータを扱う場合、

かなり使えることが分かった。

ただし、protobufを使わないと、パフォーマンスはでないし、

各言語のライブラリは確認しておく必要あり。

(phpの3rdpartyのprotobufライブラリは60KB以上のデータ扱えない問題あり。javaは1MBでも大丈夫だった。)

 


 

クラスターからの取り外し、参加させる場合など、

キーのリハッシュが生じる際は気を付ける必要があるが、

cassandraを使うよりは設定は楽で、運用も楽そうな感じはする。

サーバのスペックとしては、

CPUもMEMORYもDISKもNETWORKも、

全ての性能がある程度求められるが、かなり使える手応えである。

 

今回は、KVSの機能としか見ていないが、

機能は豊富であるので、今後も期待しています。

 

以上

 

投稿日時:2017年05月21日 00:04   カテゴリー:riak  

MySQL/MariaDBで、binlog_formatというのが、

  • statement
  • mixed
  • row

とありますが、

このうち、mixedを選択していた場合、

statementかrowがクエリーのタイプによって、

決定されると書いてあったのだが、

よく見ると、tx_isolationが

InnoDB テーブルを使用中で、トランザクション分離レベルが READ COMMITTED または READ UNCOMMITTED の場合、行ベースのロギングのみを使用することができます。ロギング形式を STATEMENT に変更することは可能ですが、InnoDB は挿入を実行できないため、実行時にこれを行うと、非常に速くエラーが発生します。』

という記述が公式にあった。

 

rowだと、バイナリログの出力サイズが大きいから、

mixedにして削減しようと思ったが、

そもそもREAD COMMITEDで運用していたから、意味なかったという話。。

 

投稿日時:2017年04月30日 21:50   カテゴリー:mariadb, mysql  

前回も書いたが、

maxsclaleとphpのmysqlndでまた問題があったので、

記載しておく。

 

たぶんまた、


PDO::setAttribute( ATTR_EMULATE_PREPARES, false )

のせいなのだろうが。。

 

その1 maxscaleのコネクションプールが使えなくなる

nativeのエミュレートを有効にした状態で、

maxscaleのコネクションプールを使うと以下のようなエラーが頻発する。


Wrong COM_STMT_PREPARE response size. Received 7 with query:

これは、mysqlnd側が出力しているエラーなのだが、

どうもレスポンス(応答)のサイズが期待したものと異なるからのようある。

 

その2 高負荷でreadwriteが使えなくなる

maxscaleのreadwrite splitを使っている状態で、

高負荷になると以下のエラーが頻発する。


SQLSTATE[HY000]: General error: 2003 Lost connection to backend server. with query:

どうも、slaveを見失ってしまうことが多く、結果として、

master側への接続もエラーになるというもの。

 

使っていたバージョンは、

maxscale2.0.4なのであるが、

意外に高負荷に現状耐えることが出来てないのかな、、と思う。

とはいえ、すぐにbugfixされるので、継続的に見守っていきたい。

 

投稿日時:2017年03月21日 22:28   カテゴリー:mariadb, mysql, php  

JAVAのwebsocketの能力はすごい。

APサーバとして、jetty9を使い、

ほぼメモリのみで完結する処理で、

8coreの仮想マシンで、

同時接続10,000を超えることが可能である。

(当然、OSレベルのチューニングも必要、コードレベルではスレッドプールの適切な利用が必要であり、syncronized、Concurrent、Atomicも使って一貫性を確保することも必要)

 

当然、メモリの使用量には気を付けなきゃいけないが、

多少DB書き込みが入っても、コネクションプールを使っていれば、

全くパフォーマンスダウンしない。

 

やはり、JAVAのマルチスレッドは偉大であると、切に思いました。

 

JAVAのマルチスレッドでの記事は、大規模業務系ぐらいしかないため、

どうも細かい内容が出てきづらい。

もっとオープンなところで積極的に活用されることを願っています。

 

投稿日時:2017年03月14日 23:29   カテゴリー:java  

phpのmysqlndというライブラリは素晴らしいものである。

しかし、その機能に悩まされたので、記載しておく。

 

そもそもmysqlndは、

  1. ネイティブのprepared statementのサポート
  2. DBの型に合わせたphpの自動型変換サポート
  3. フェイルオーバ検知の仕組みの提供(mysqlnd_ms)

などの機能がある。

 

1と2については、


PDO::setAttribute( ATTR_EMULATE_PREPARES, false )

により実現できる。

しかし、3については、これを設定すると機能しなくなる(らしい、未検証)。

 

さらに上記を設定した場合、

raw_queryでさえも、prepared statementとして扱われてしまう。

一見問題なさそうなのですが、

maxsacleのreadwrite splitをかましていると、

prepared statementがmasterに振られてしまうため、

slave参照が行われなくなってしまう。

じゃあ、mysqlnd_msでやればいいじゃんって話だが、

先ほど書いたように機能しなくなってしまう(らしい、未検証)。

 

というちょっと困る事象。。

maxslaceがprepared statemtでもslaveに振ってくれればいいのだが。。

投稿日時:2017年03月14日 23:15   カテゴリー:mariadb, mysql, php