JavaMailでSMTP接続をして、
メールを送信しようとした時、
javax.mail.MessagingException: 501 Syntax: HELO hostname
のエラーがでることがある。
これは送信元のサーバのホスト名が
/etc/hostsに掲載されていない場合に起こる。
その他にも色々方法はあるようだが、
/etc/hostsにhostnameをしっかり書いておくことは大事です。
とはいえ、最近クラウドばかり使っていると、
この辺疎かになりがち。。
IT系のめもを蓄積していこうかと
JavaMailでSMTP接続をして、
メールを送信しようとした時、
javax.mail.MessagingException: 501 Syntax: HELO hostname
のエラーがでることがある。
これは送信元のサーバのホスト名が
/etc/hostsに掲載されていない場合に起こる。
その他にも色々方法はあるようだが、
/etc/hostsにhostnameをしっかり書いておくことは大事です。
とはいえ、最近クラウドばかり使っていると、
この辺疎かになりがち。。
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のページを見たが、それらしき記述はなかった。。
redisの冗長化を行うためには、
がある。
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の欠点は以下の通り。
などなど。
とくに、クライアントライブラリが少ないのは気がかりである。
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をベースに使っていて、
ノンブロッキングをサポートしているしね。
当サイトは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です。
昨日書いた記事を検証してみた。
以下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回やって、一度も不整合は起きず。
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はフレームワークの世界だから、厳密にわかる人は少ないのだろうけど、
ここは教えて欲しい。。。
・・・後日
上の例は大丈夫だった。
新しく記事を書きました。
RDBで大量のselectをしたら、
DBサーバの負荷は重いのだろうか?
例えば、1億レコードが入っているテーブルに対して、
select * from [table]
したら、DBサーバの負荷は重いのだろうか?
個人的に思うところとして、
サーバ側は、クライアント側に一定のバッファで
結果を返すことにのみ注力しているのであれば、
少々ネットワークは忙しくなるかもしれないが、
サーバのシステム負荷(CPU使用率、メモリ使用率)は低いんじゃないか?
って考えてます。
誰か教えて欲しいわ。。
ソースコード見るしかないかね。。
この仮定が成立するとすれば、
インデックスがない環境で複雑なクエリーを発行するより、
一気に大量レコードを引いて、
アプリケーションプログラムで分散並列で処理しちゃえば、いいんじゃないの?って思う。
Hadoopは詳しくないけど、似たようなものなのかな?
ちょっと勉強してみようかな。。
AWSのRDSにmariadbが追加されましたね。
xtradbのサポートはあるようだけど、
mariadbのクラスター関連のエンジンはサポートしていない感じがする。
AWSの場合、Auroraがあるから、mariadb流行らないかも。。
クラスター関連をサポートしてくれないかな。。
windows10にvirtualbox5を入れて、
ゲストOSをローカルネットワーク内に参加させる方法が、
windows8とvirtualbox4のときと異なったので、
メモしておく。
以前は、wifiとホストオンリーアダプタでブリッジを作っていたが、
今回はブリッジのみでいけるが、Oracleのドライバーが必要らしい。
(前提)
とする。
手順1. Oracleのドライバーを入れる
ホストオンリーアダプタのプロパティから、以下の画面を開き、
「VirtualBox NDIS6〜」なるものをインストールする。
立ち上がった画面で、「サービス」を選択して追加する。
「「VirtualBox NDIS6〜」なるものを選択して「OK」を押す。
これで、ok。
手順2. ゲストOSのネットワークにブリッジアダプターを選択する
ゲストOSの設定で、ブリッジアダプターを選択する。
手順3. ゲストOSのネットワークを固定IPに設定する
今回は192.168.1.15とする。
これで、ゲスト側のネットワークを起動すれば、
192.168.1.11のような同一ネットワーク内の他ホストから接続可能となる。
もちろん、firewall等もあるから、そこは適宜設定。
以上
java8でラムダ式を始めてみて、
こりゃscalaも勉強しとかなきゃあかんな、
と思い、scalaをダウンロードしにいったら、
TypesafeActivatorもあったから、こっちでやることにした。
1.まずsbtをいれる
# port install sbt
2.次にeclipseのscalaプラグインを入れる
マーケットプレイスにもある。
3.そしてsbtをダウンロードして、パスを通す
# cd /opt # curl -O "http://downloads.typesafe.com/typesafe-activator/1.3.6/typesafe-activator-1.3.6.zip" # unzip typesafe-activator-1.3.6.zip # ln -s /opt/typesafe-activator-1.3.6 /opt/typesafe-activator # echo "export PATH=$PATH:/opt/activator-dist" >> /etc/profile # source /etc/profile
これで、activatorコマンドが実行できるようになった。
4.eclipseプロジェクトへの変換
activator new
とかで新規プロジェクトの雛形をつくってくれるので、
そのプロジェクトに移動後、
$ sbt eclipse
ってやれば、eclipseへのインポートが可能になる。
なんか、
activator eclipse
とか、plugin.sbtに追加しろとかあるけど、
どれも不要だった。。