カテゴリー「java」

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

mavenのレポジトリとしては、

githubが使える。

ただし、githubだと、最新バージョンしか管理できないため、

ちょっと使いづらい。

 

maven公式にアップできないものもあるだろうから、

そんなときは、archivaを使うと良い。

https://archiva.apache.org/index.cgi

 

archivaをセットアップしたので、作業履歴を残しておく。

1.ダウンロード

$ wget http://ftp.riken.jp/net/apache/archiva/2.2.0/binaries/apache-archiva-2.2.0-bin.tar.gz
$ unzip apache-archiva-2.2.0apache-archiva-2.2.0-bin.zip

 

2.設定修正

$ vim apache-archiva-2.2.0/conf/jetty.xml
<Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>

<Put name="mail.user">{your gmail uer}</Put>
<Put name="mail.password">{your gmail password}</Put>
<Put name="mail.transport.protocol">smtp</Put>
<Put name="mail.smtp.host">smtp.gmail.com</Put>
<Put name="mail.smtp.port">587</Put>
<Put name="mail.smtp.auth">true</Put>
<Put name="mail.smtp.starttls.enable">true</Put>
<Put name="mail.debug">false</Put>
$ vim apache-archiva-2.2.0/conf/archiva.xml
<application>
<url>http://{your domain}/url>
<timestamp>EEE d MMM yyyy HH:mm:ss Z</timestamp>
</application>

 

3.nginx設定

# vim /etc/nginx/conf.d/archiva.conf 
server {
    listen                  80;
    server_name             {your domain};

    location / {
        include                 /etc/nginx/proxy_params;
        client_body_buffer_size 128k;
        proxy_pass http://127.0.0.1:8080;
    }
}

 

4.クライアント設定

$ vim ~/.m2/settings.xml
<settings>
  <servers>
    <server>
      <id>archiva.internal</id>
      <username>{your username for your archiva}</username>
      <password>{your password for your archiva}</password>
    </server>
    <server>
      <id>archiva.snapshots</id>
      <username>{your username for your archiva}</username>
      <password>{your password for your arvhiva}</password>
    </server>
  </servers>
</settings>

5.pom.xmlに追記

  <!-- distributionManagement -->
  <distributionManagement>
    <repository>
      <id>archiva.internal</id>
      <name>Internal Release Repository</name>
      <url>http://{your domain}/repository/internal/</url>
    </repository>
    <snapshotRepository>
      <id>archiva.snapshots</id>
      <name>Internal Snapshot Repository</name>
      <url>http://{your domain}/repository/snapshots/</url>
    </snapshotRepository>
  </distributionManagement>

 

以上を設定したい状態で、

$ mvn clean deploy

にて、デプロイが可能となる。

結構いいです。

 

ただ、認証情報のリセットが一定期間で要求されるので、
若干そこがめんどくさいかな。

投稿日時:2016年04月04日 17:39   カテゴリー:java   [コメントがあればどうぞ]