カテゴリー「java」

TCPに引き続き、UDPを作ってみた。

https://github.com/shigenobu/OrangeCabinet

一応、nugetに公開済みです。

これも、JAVA版があるのですが。。一応紹介。

https://github.com/shigenobu/blueshelf

一応、mavenで公開済みです。

この、C#のUDPライブラリの特徴は、以下となります。

  • 例によって、ハーフクローズを検知用に、最終受信からN秒でタイムアウト(UDPはそんなもんないけど)を処理
  • クライアントでもbindする

一番目は、送信元が同じ限り、タイムアウトするまでは独自のオブジェクトで任意変数を格納できる。

(セッションみたいなイメージ)

二番目は、クライアントでも予めbindすることで、ポートを決め打ちできる。

connectだと、ポートが決め打ちできないので、あえてbindを使う形にしています。

なんでこんなもんをつくっているのかというと、

実は、TCP/UDPのサーバ機能を必要とするあるものを作りたいと考えているからです。

うまくできたら、nugetに公開しようかと考えています。

今回ちょっとハマったのは、BeginXXXとEndXXXは対になっているらしく、

BeginReceiveFrom

EndReceiveFrom

はセットで使う必要があるということでした。

ただ、BeginReceiveFromの部分でも、使わないremote endpointインスタンスを生成しないといけないのは、ちょっと微妙な気がした。

完了時に、remote endpointが取れればいいと思うのだが。。

また、システムコールとしては、epoll_createは使われていたが、UDPなんでepollである必要もないのかなとは思った。

JAVAだと、UDPに対するepollの実装はないので(正確にはJAVA7でお蔵入りしたようだが)。

概ね問題なさそうだが、一時オブジェクトの生成が少し多い気がしている。

IAsyncResultオブジェクトを毎回作っているような感じなので、そこは調整できればとは思う。

(ただ、毎回作らないと受信バッファの読み込みがうまくいかないので、簡単にはいかない気がしている。)

以上

投稿日時:2021年12月13日 22:24   カテゴリー:c#, java, network   [コメントがあればどうぞ]

Javaで以前作ったTCPサーバ・クライアントみたいな感じで、

C#の非同期・ノンブロッキングTCPサーバ・クライアントを作ってみた。

https://github.com/shigenobu/PurpleSofa

一応、nuget.orgには登録してあります。

ちなみにJavaのもの。

https://github.com/shigenobu/redchest

一応、mavenには登録済みです。

以前、C#のTCP実装では、

  • BeginXXXのメソッドを使うパターン ※async/awaitではない
  • SocketAsyncEventArgsクラスを使うパターン

があるようだと書いたのですが、

「SocketAsyncEventArgsクラスを使うパターン」では、どう頑張っても接続ごとにスレッドを割り当てて、

受信を待機する形にせざるを得ない感じでした。

「SocketAsyncEventArgsクラスを使うパターン」は、少ないクライアントで大量のやりとりをするケースに向いているのかな?

と感じています。

そのため、汎用的な側面から、今回は「BeginXXXのメソッドを使うパターン」のパターンで実装しました。

C#版もJava版と同様、

  • openハンドラ(acceptもしくはconnect時に1回呼び出される)
  • messageハンドラ(read時にN回呼び出される)
  • closeハンドラ(close時に1回呼び出される)

という形となっています。

C#版もJava版同様、

  • 最終受信からN秒(デフォルト60秒)経過で、タイムアウト切断します。
  • 切断処理は、キューを経由して非同期で行われます。
  • 接続(セッション)のオブジェクト内に、任意の値を入れられます。

という実装になっています。(Java版は上記に加えて、シャットダウンハンドラーの実装もあります。)

このライブラリの最大の特徴は、「最終受信からN秒経過でタイムアウト切断」というところでしょうか。

なんでこんなことしているかっていうと、keep aliveをしようがなにしようが、

この方法でしか結果的に”ハーフクローズ”を検知できないからです。(経験的に)

C#版を作るにあたって、ちょっと気になった点として、

連続的にメッセージを送信すると、まれに受信時に2つのメッセージを同時に取得してしまうケースがあるようです。

Javaのときはなかったのですが、どんなに排他制御をしても無理な感じでした。(受信時の問題っぽいので)

そのため、実際に利用するときは、プロトコロル(というかメッセージフォーマット)をよく決めて、

アプリケーションでメッセージを分割できるようにする必要があるのかと感じます。

また、デフォルトで、バッファサイズを2048byteとっていますが、

広域通信だと、MTU(通常1500byteくらい)より小さい値で分割受信するケースもあるので、

このあたりもアプリケーションで吸収する必要があるかと思います。

以上

投稿日時:2021年12月07日 22:52   カテゴリー:c#, java, network   [コメントがあればどうぞ]

個人でこっそりgithubで作っているMariaDBの差分検出・反映ツールである「magentadesk」に、

API機能とHTML機能を追加しました。(0.4.0からHTML機能がはいってます)

(magentadesk)

https://github.com/shigenobu/magentadesk

今まではcli版しかなったのですが、web版も追加されています。

web版でしていることは、cli版の処理を呼び出しているに過ぎないのですが、

HTML機能を使うことで、各種jsonデータをsqliteに保存しておけるようになり、ボタン一つで差分検出・反映が可能となります。

API機能は、cli版の単なるHTTPインターフェースでしかないのですが、

HTML機能で追加したrelationという設定は、テーブルの子・親関係を登録しておくことで、

差分検出時にチェックボックスが連動するというものとなります。

magantadeskでは、外部キーが設定されているものは、

反映対象外としている(これは反映順番の整合性を保つのが難しいため)のですが、

それだと、差分確認時に、親子関係がわかりくいということから、このような機能を作ってみました。

で、API・HTML機能を作るに当たり、苦労した点があったので書いておきます。


(HTTPサーバにcom.sun.net.httpserver.HttpServerを利用)

デフォルトで同胞されているHTTPサーバなのですが、これが非常にくせのあるものでした。

例外などの際、ようは最後の最後のタイミングで、ただしくHTTPレスポンスを構築してくれないので、

最後の最後で、レスポンスを構築するように工夫しました。

(HTML機能の情報を蓄積するDBとして、sqliteを利用)

READ-COMMITEDをサポートしていないので、SERIALIZABLEの分離レベルを選択。

そのうえで、ファイルのため、WRITEブロックをすることは明白なので、

とにかくsqliteに接続している時間を各処理で短くするよう調整しました。

(テンプレートエンジンとしてvelocityを利用)

え?veloctiy?と思うかもしれませんが、2.3というバージョンが出ています。

当方は、velocity-toolは使わず、

event_handler.reference_insertion.class(旧eventhandler.referenceinsertion.class)

のプロパティを設定して、独自クラスでテンプレート関数を追加しています。

テンプレート上で、NULLと空文字の判定がデフォルトではできなかったので、

独自関数で対応しました。


という具合に、地道な苦労を重ねました。

magentadeskは主にwebサービスでの本番反映を想定して、汎用化を試みたものですが、

ニーズは少なそうだなと感じています。。

今後は、国際化対応(日本語化)を入れていきたいかなと考えていますが、

JAVAではなく、jqueryでやろうかなとか考え中です。

以上

投稿日時:2021年11月25日 15:04   カテゴリー:java, mariadb   [コメントがあればどうぞ]

MariaDBに特化した、データベースの差分検出/反映ツールを作ってみました。

https://github.com/shigenobu/magentadesk

こちらのツールは、同一筐体内に存在する2つのデータベース(スキーマ)の差分を検出し、検出した差分結果を使って、反映対象先データベースにデータをコピーするものとなります。

以下のMariaDB特有機能をふんだんに使ってしまっているため、MySQLでは動きません。

  • Dynamic Column
  • Except syntax
  • CTE
  • Sequence

使いどころとしては、webサービスなどで、staging環境で確認が取れたデータを、production環境に反映するといったシチュエーションとなるかと。

staging環境とproduction環境の筐体を同一にしておき、productionはそこからレプリケーションでproduction専用のDBサーバに配るような形がよいかなと思います。

日本語のマニュアルは以下となります。

https://github.com/shigenobu/magentadesk/blob/master/README.ja.md

JAVAの単体実行バイナリをreleaseページからDLしてもられば使えます。

依存を極小化したので、わずか1.5MBのバイナリとなり、取り回しも楽かと。

そのほか、過去に作成したものですが、JAVAのTCPサーバ/クライアント、UDPサーバ/クライアントのMAVENライブラリも紹介させてください。

(redchest)

https://github.com/shigenobu/redchest

websocketライクなインタフェースで設計しており、NIO2のTCP実装を使っています。Linuxで動かせば、epollのシステムコールで処理します。特徴としては、断線などにも対応すべく、最終受信からN秒で接続を破棄するように作り込んでいます。注意点として、広域(日本⇔ヨーロッパなど)で使う場合、epollのシステムコールの制約なのか、ごく稀にMTUより小さい受信バッファサイズであっても、さらに分割される場合があります。(C/C++でも同様の現象確認済)その際は、次回受信で不足分が取得できますので、前回メッセージを一時的にセッションに蓄積するなどの工夫が必要です。

(blueshelf)

https://github.com/shigenobu/blueshelf

こちらもwebsocketライクなインターフェースで設計した、NIOのUDP実装を使っています。Linuxならselectのシステムコールですね。特徴としては、複数ポートでlistenすることで、多重のIOを実現しています。そもそも、UDPには多重IOの技術はあまり不要かと思いますが、複数ポートを使うことで、複数のIOをうまく使い、メニーcore環境におけるパフォーマンス向上を目指しました。こちらも、最終受信からN秒で、「切断」のような扱いにしています。

以上

投稿日時:2019年06月25日 22:53   カテゴリー:java, mariadb   [コメントがあればどうぞ]

久しぶりにjava。

prometheus/jmx_exporterを使って、おれおれjar(主にstandaloneサーバ)を監視する場合についてまとめておきます。

jmx_exporterを使って、tomcat/jetty等のサーブレットコンテナなどを監視する方法はよくあるのですが、おれおれjarについてはあまりやっている人が少なそうなので。。

環境は、

OS:CentOS7

JDK:OpenJDK8

でやってます。


前提として、$HOMEに以下が配備されているものとします。

  • jmx_prometheus_javaagent-0.3.1.jar
  • config.yml
  • your.jar

上記の場合、jmx_exporterを使っての監視するためのコマンドは以下となります。(先に結論)

$ java \
 -javaagent:${HOME}/jmx_prometheus_javaagent-0.3.1.jar=9080:${HOME}/config.yaml \
 -Djava.rmi.useLocalHostName=true \
 -Djava.rmi.server.hostname=127.0.0.1 \
 -Dcom.sun.management.jmxremote.port=1099 \
 -Dcom.sun.management.jmxremote.authenticate=false \
 -Dcom.sun.management.jmxremote.ssl=false \
 -Dcom.sun.management.jmxremote.rmi.port=1099 \
 -jar ${HOME}/your.jar

ちなみに、config.ymlの内容は以下のとおりです。

---
hostPort: 127.0.0.1:1099
username:
password:

rules:
- pattern: ".*"

設定内容は、

javaオプションで1099ポートでjmxリスナーを上げて、

javaagent設定を食わしたjmx_exporterにjmxにて1099ポートへアクセスさせる、

というものです。

これにて、

$ curl -s localhost:9080/metrics

で、jmx_exporterから情報が引き出せます。

以上

投稿日時:2019年01月10日 15:58   カテゴリー:java   [コメントがあればどうぞ]

fedora27にて、

  • java-1.8.0-openjdk-1.8.0.161-5.b14.fc27.x86_64
  • openjfx-8.0.152-12.b04.fc27.x86_64

でjavafxを動かそうと思ったら、全く動かなかった。

そこで、

  • jdk1.8-1.8.0_161-fcs.x86_64

いわゆるOracleJDKに変更したら、無事動いた。

javafx以外は問題なさそうなんだけど。。。

ちなみにOracleJDKでも、TextFieldに日本語入力を行おうとすると、

ざっくり以下のようなSIGSGVが起きる。。


# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f1128822e11, pid=9155, tid=0x00007f10f8126700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_161-b12) (build 1.8.0_161-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# j com.sun.glass.ui.gtk.GtkView.notifyInputMethodDraw(Ljava/lang/String;III[B)V+16

 

javafxがんばれ!

 

以上

投稿日時:2018年03月15日 23:12   カテゴリー:fedora, java   [コメントがあればどうぞ]

javaでfluentdのサーバ、

つまりforwordを受ける側の処理なのだが、

これを書こうと思い、

fluentdのmsgpackのフォーマットを調査していたところ、

以下のライブラリに出会った。

https://github.com/okumin/influent

 

上記のライブラリはとても素晴らしく、

javaのマルチスレッド、NIOを十二部に活用されていた。

テストをしたところ、十分な負荷にも耐えられ、

高い安定性を誇ることが分かった。

※テストしたのは、バージョン0.3.0

 

ただ、msgpackを前提としているので、

jsonデータのmsgpack化ではパースエラーになる。

具体的には、公式に提供されているphpライブラリだと、

デフォルトの書き込みフォーマットはjsonであるため、

ここはmsgpackに変更する必要がある。

 

とはいえ、とても優れたプロダクトであり、

UDPのハートビートにも対応されている点は、

とても利用しやすいと感じた。感謝感謝。

 

以上

投稿日時:2018年01月20日 22:27   カテゴリー:java   [コメントがあればどうぞ]

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   [コメントがあればどうぞ]

JAVAのwebsocketの能力はすごい。

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

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

8coreの仮想マシンで、

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

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

 

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

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

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

 

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

 

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

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

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

 

投稿日時:2017年03月14日 23:29   カテゴリー:java   [コメントがあればどうぞ]

JAVAでredisを使う際、以下のライブラリを使用していた。

https://github.com/mp911de/lettuce

 

このライブラリはとても素晴らしいのだが、

Non Blocking IO機能を、マルチスレッド環境で使おうとすると、

どうもコントロールが難しい。

 

というのもの、このライブラリは内部的にnettyを使っており、

Non Blockingを使う際、nettyのHashedWheelTimerってやつが、

シングルスレッドでtickを刻んでいるため、複数接続を作ろうとすると怒られる。(たぶん作れない)

そもそもredisはシングルスレッドなので、複数接続作ることが間違っているのかもしれないが、

常時接続を1本をマルチスレッド環境で使うのもなんとなく心細い。。

エラーハンドリングでの再接続なども実装しようとすると、

せめてcore数くらい接続を用意しておきたい心持である。。

 

結局Non Blockingはやめて、Blockingを選択したことで、

複数接続を扱えるようになったが、正直結構悩むところである。

 

投稿日時:2017年03月14日 23:05   カテゴリー:java, redis   [コメントがあればどうぞ]