持続的接続をredisで行う場合、
接続は1つでよいと書いた記憶があったが、
javaでノンブロッキングでも大丈夫か検証してみた。
javaのredisクライアントはlettuceを使用し、
1つのコネクションを、
マルチスレッドで共有し、SET、GETを試みたところ、
結果にずれは生じなかった。
結論として、
redisはシングルスレッドであるため、
持続的接続の場合は1コネクションでOK。
ただし、javaではマルチスレッドの性能を生かすため、
CPU数 x 2〜3 ぐらいがいいのかなとは思う。
ちなみに、上記でやっても問題なしでした。
以上
投稿日時:2015年12月29日 15:38
カテゴリー:
java,
redis
JavaMailでSMTP接続をして、
メールを送信しようとした時、
javax.mail.MessagingException: 501 Syntax: HELO hostname
のエラーがでることがある。
これは送信元のサーバのホスト名が
/etc/hostsに掲載されていない場合に起こる。
その他にも色々方法はあるようだが、
/etc/hostsにhostnameをしっかり書いておくことは大事です。
とはいえ、最近クラウドばかり使っていると、
この辺疎かになりがち。。
投稿日時:2015年12月25日 13:45
カテゴリー:
java
javaのweb socketで、decoderとpathparamはある条件において不可能なようなだ。
以下の場合はダメ。
@ServerEndpoint(
value = "/ws/{p1}/{p2}/"
decoders = {HogeDecoder.class},
encoders = {HogeEncoder.class})
public class HogeWebsocket {
/**
* open hander.
*/
@OnOpen
public void onOpen(@PathParam("p1") String p1, Session session, EndpointConfig config) {
:
:
}
}
これだと、p1がdecoderの対象になるみたい。
そのため、次のような方法で対処する。
@ServerEndpoint(
value = "/ws/{p1}/{p2}/"
decoders = {HogeDecoder.class},
encoders = {HogeEncoder.class})
public class HogeWebsocket {
/**
* open hander.
*/
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
Map<String, String> pathParameters = session.getPathParameters();
String p1 = pathParameters.get("p1");
:
}
}
本件は、decoderでバイナリからテキストに変換しようとした際に起きた現象。
なので、decoderが何をするかによるとは思うが。。
javaのページを見たが、それらしき記述はなかった。。
投稿日時:2015年12月21日 18:38
カテゴリー:
java,
websocket
redisの冗長化を行うためには、
- master <-> slave構成
- master <-> slave構成 + sentinel
- cluster
がある。
clusterはredis3より正式サポートされた機能である。
特徴としては、以下の通り。
master <-> slave構成だと、
masterが倒れたときのフェイルオーバが皆無である。
master <-> slave構成 + sentinelだと、
masterが倒れたときに、slaveが自動昇格できる。
ただ、slave x 2以上、sentinel x 3以上が望ましい感じがする。
cluster構成だと、
分散でデータを保持しているため、
slaveも同時に使い、自動昇格させる必要がある。(slaveがあれば自動昇格する)
master x 3以上、slave x 3以上にする必要がある。
と考えると、clusterが一番な気がするが、
clusterの欠点は以下の通り。
- selectはない
- multi – execができない?
- 対応しているクライアントライブラリが少ない
- リダイレクトが発生するため、速度が遅くなる?
- クラスター再構築が難しめ
などなど。
とくに、クライアントライブラリが少ないのは気がかりである。
python, rubyではあるらしい。
javaでもlettuceが対応している。
javaのコードは以下の通り。
List<RedisURI> list = new ArrayList<>();
list.add(new RedisURI("192.168.1.45", 16381, 1, TimeUnit.SECONDS));
list.add(new RedisURI("192.168.1.45", 16382, 1, TimeUnit.SECONDS));
list.add(new RedisURI("192.168.1.45", 16383, 1, TimeUnit.SECONDS));
list.add(new RedisURI("192.168.1.45", 16384, 1, TimeUnit.SECONDS));
list.add(new RedisURI("192.168.1.45", 16385, 1, TimeUnit.SECONDS));
list.add(new RedisURI("192.168.1.45", 16386, 1, TimeUnit.SECONDS));
RedisClusterClient client = RedisClusterClient.create(new Iterable<RedisURI>() {
@Override
public Iterator<RedisURI> iterator() {
return list.iterator();
}
});
AsyncExecutions<String> excutions = null;
RedisAdvancedClusterAsyncCommands<String, String> con = client.connect().async();
AsyncNodeSelection<String, String> masters = con.masters();
excutions = masters.commands().set("hoge", "fuga");
excutions.forEach(result -> result.thenAccept(ret -> System.out.println(ret)));
excutions = masters.commands().get("hoge");
excutions.forEach(result -> result.thenAccept(ret -> System.out.println(ret)));
con.close();
client.shutdown();
しかし、multi – execができないのは結構痛い。。。
うまいことやればできるのかな。。
ただ、分散してしまうから、無理なきがする。
このlettuceっていうライブラリは良さげ。
nettyをベースに使っていて、
ノンブロッキングをサポートしているしね。
投稿日時:2015年12月10日 13:06
カテゴリー:
java,
redis
当サイトはhttpサーバとして、
nginxで運用しているのだが、
nginxをipv4とipv6のハイブリット運用に変更したので、
メモを残す。
nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 10;
client_header_timeout 10;
client_body_timeout 10;
reset_timedout_connection on;
send_timeout 10;
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset UTF-8;
server {
listen 80;
listen [::]:80 ipv6only=on;
}
include /etc/nginx/conf.d/*.conf;
}
そして、一部sslサイトがあるので、
ssl側は以下のようにする。
※httpでアクセスしてきたときのリダイレクトも入れている
server {
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443;
listen [::]:443 ipv6only=on ssl;
ssl on;
ssl_certificate /etc/pki/tls/certs/server.crt;
ssl_certificate_key /etc/pki/tls/certs/server.key;
server_name example.com;
:
:
}
netstatの結果、
nginxがipv4の80と443、ipv6の80と443で待ち受けていることがわかる。
# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 27124/nginx: master
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 27124/nginx: master
tcp6 0 0 :::443 :::* LISTEN 27124/nginx: master
tcp6 0 0 :::80 :::* LISTEN 27124/nginx: master
ちなみに、centos7で、nginxのバージョンは1.6.3です。
投稿日時:2015年12月07日 14:22
カテゴリー:
nginx
昨日書いた記事を検証してみた。
以下3つの例を検証。
1.単純ケース
@WebServlet(name = "test01", urlPatterns = {"/test01"})
public class Test01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
try (PrintWriter writer = resp.getWriter();) {
resp.setStatus(200);
resp.setContentType("text/plain");
writer.write("name is " + name);
writer.flush();
writer.close();
}
}
}
2.絶対ダメなケース
@WebServlet(name = "test02", urlPatterns = {"/test02"})
public class Test02 extends HttpServlet {
private String name;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
name = req.getParameter("name");
try (PrintWriter writer = resp.getWriter();) {
resp.setStatus(200);
resp.setContentType("text/plain");
writer.write("name is " + name);
writer.flush();
writer.close();
}
}
}
3.今回検証したかったケース
@WebServlet(name = "test03", urlPatterns = {"/test03"})
public class Test03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
new MyClass(req, resp).execute();
}
class MyClass {
private HttpServletRequest req;
private HttpServletResponse resp;
private String name;
public MyClass(HttpServletRequest req, HttpServletResponse resp) {
this.req = req;
this.resp = resp;
name = req.getParameter("name");
}
public void execute() throws IOException {
try (PrintWriter writer = resp.getWriter();) {
resp.setStatus(200);
resp.setContentType("text/plain");
writer.write("name is " + name);
writer.flush();
writer.close();
}
}
}
}
結論としては、3は大丈夫であった。
jmeterで同時接続100を10回やって、一度も不整合は起きず。
投稿日時:2015年11月27日 14:52
カテゴリー:
java
servletはエントリーポイントのインスタンスは1つしか作成しない。
そして、それが複数スレッドで共有される。
そのため、インスタンスフィールドはスレッドセーフにならない。
・スレッドセーフではない例
public class TestServlet extends HttpServlet {
private String name;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
name = req.getParameter("name");
PrintWriter writer = res.getWriter();
writer.print(name);
}
}
で、ここからがわからんところなのだが、
ローカル変数はスレッドセーフになるのだから、
doGetの処理の中で、以下のようなことをしたら、問題ないのか?
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
new MyClass(req, res).execute();
}
}
public class MyClass {
private HttpServletRequest req;
private HttpServletResponse res;
public MyClass(HttpServletRequest req, HttpServletResponse res) {
this.req = req;
this.res = res;
}
public void execute() {
String name = req.getParameter("name");
PrintWriter writer = res.getWriter();
writer.print(name);
}
}
もし、上記でスレッドセーフになるっていうなら、
それでよくね?って思っちゃう。
それとも、MyClassのインスタンスフィールドは実はスレッドセーフではないのか?
メモリ使用量としては、生成するインスタンス分大きいのはわかるが、
もし上記で解決するなら、煩わしいスレッド問題とはオサラバできると思うのだが、
問題あるのだろうか?
servletはフレームワークの世界だから、厳密にわかる人は少ないのだろうけど、
ここは教えて欲しい。。。
・・・後日
上の例は大丈夫だった。
新しく記事を書きました。
投稿日時:2015年11月26日 19:58
カテゴリー:
java
RDBで大量のselectをしたら、
DBサーバの負荷は重いのだろうか?
例えば、1億レコードが入っているテーブルに対して、
select * from [table]
したら、DBサーバの負荷は重いのだろうか?
個人的に思うところとして、
サーバ側は、クライアント側に一定のバッファで
結果を返すことにのみ注力しているのであれば、
少々ネットワークは忙しくなるかもしれないが、
サーバのシステム負荷(CPU使用率、メモリ使用率)は低いんじゃないか?
って考えてます。
誰か教えて欲しいわ。。
ソースコード見るしかないかね。。
この仮定が成立するとすれば、
インデックスがない環境で複雑なクエリーを発行するより、
一気に大量レコードを引いて、
アプリケーションプログラムで分散並列で処理しちゃえば、いいんじゃないの?って思う。
Hadoopは詳しくないけど、似たようなものなのかな?
ちょっと勉強してみようかな。。
投稿日時:2015年11月26日 13:07
カテゴリー:
rdb
AWSのRDSにmariadbが追加されましたね。
xtradbのサポートはあるようだけど、
mariadbのクラスター関連のエンジンはサポートしていない感じがする。
AWSの場合、Auroraがあるから、mariadb流行らないかも。。
クラスター関連をサポートしてくれないかな。。
投稿日時:2015年11月17日 13:19
カテゴリー:
aws,
mariadb
windows10にvirtualbox5を入れて、
ゲストOSをローカルネットワーク内に参加させる方法が、
windows8とvirtualbox4のときと異なったので、
メモしておく。
以前は、wifiとホストオンリーアダプタでブリッジを作っていたが、
今回はブリッジのみでいけるが、Oracleのドライバーが必要らしい。
(前提)
- ホストOSのアドレスは192.168.1.10
- ゲストOSのアドレスは192.168.1.15
- 他ホストのアドレスを192.168.1.11
とする。
手順1. Oracleのドライバーを入れる
ホストオンリーアダプタのプロパティから、以下の画面を開き、
「VirtualBox NDIS6〜」なるものをインストールする。

立ち上がった画面で、「サービス」を選択して追加する。

「「VirtualBox NDIS6〜」なるものを選択して「OK」を押す。

これで、ok。
手順2. ゲストOSのネットワークにブリッジアダプターを選択する
ゲストOSの設定で、ブリッジアダプターを選択する。

手順3. ゲストOSのネットワークを固定IPに設定する
今回は192.168.1.15とする。
これで、ゲスト側のネットワークを起動すれば、
192.168.1.11のような同一ネットワーク内の他ホストから接続可能となる。
もちろん、firewall等もあるから、そこは適宜設定。
以上
投稿日時:2015年11月06日 13:49
カテゴリー:
virtualbox,
windows