Oracle DBでtnsnames.oraを使ってフェイルオーバー(もしくは負荷分散)を行う。

基本的にマニュアルの通りですが、Oracle DBの場合接続文字列を変えるだけでフェイルオーバー(もしくは負荷分散)を行えます。

docs.oracle.com

複数をどう切り替えるかというと、(FAILOVER=on)もしくは(LOAD_BALANCE=on)をつけるだけ。 どのサーバー間で切り替えるかを設定するのは、ServiceNameが同じ場合はADDRESS_LISTを使用してサーバーのアドレスを切り替えて、ServiceNameが違う場合はDESCRIPTION_LISTで切り替えます。

net_service_name= 
 (DESCRIPTION_LIST=
    (LOAD_BALANCE=on)
    (FAILOVER=off)
    (DESCRIPTION=(ADDRESS=~~~
    )
    (DESCRIPTION=(ADDRESS=~~~
net_service_name= 
(DESCRIPTION=
  (ADDRESS_LIST=
    (LOAD_BALANCE=on)
    (FAILOVER=off)
    (ADDRESS=~~~
    (ADDRESS=~~~
  )
  (SERVICE_NAME=service_name))
)

JDBCでtnsnames.oraを読み込む

接続文字列をJDBC接続文字列に直接書き込むかtnsnames.oraの場所を変数として渡してあげる必要があります。

-Doracle.net.tns_admin=TNS_NAMES_ORA_DIRECTORY

docs.oracle.com

使うべきなのか?

正直、使わない方が良いと思います。 正系のOracle DBが生きてるか死んでるかよくわからない場合に正しく動かないだろうというのと、結局監視側で一括して生死判定した方が良いよねぇということで、DNSサーバー立ててそこで切り替えた方がよさそう。

マニュアルには(FAILOVER=on)と(LOAD_BALANCE=on)の両方を有効にした場合の挙動として以下のような記述があります。 接続ごとに毎回この挙動が発生することが許せるなら使えばいいんじゃないかな。。。

クライアントは、ADDRESS_LISTを無作為に選択し、選択したADDRESS_LISTに障害がある場合、他方にフェイルオーバーするように指示されます。この指示は、LOAD_BALANCEパラメータとFAILOVERパラメータがonに設定されていることで示されます。

なんでもかんでもDBが機能持ってたほうが良かったという時代の名残なのかなぁ。

リングフィットを1週目クリアしたけれども痩せなかった。

リングフィットをやったら痩せましたという人ばかりなので、痩せませんでしたという記録も。

リングフィットをやったけれども、痩せませんでした。 6月14日に初回起動をして、10月18日*1 にクリア。 そのままサブクエストも同じ日に終了。

f:id:megascus:20201018165507p:plain
体重推移

どうせ運動してなかったんでしょう?

と、思われる人もいるかもしれませんが、負荷15から始めて後半はずっと負荷30でした。 身長が189センチぐらいあって、体脂肪率が25%前後だから、BMI的な健康値よりは筋肉が15kgぐらい多く、脂肪が5kgぐらい多い感じです。 クリアしたときの累計でも総活動時間は47時間、総消費カロリーも15000kcalオーバーということで、ほかの人よりはずっと多いはず。 最後のほうは1日当たり200kcal~で週5ぐらいを目安に運動していました。 f:id:megascus:20201018170022p:plain f:id:megascus:20201018170050p:plain

15000kcalは多いように見えるけど、体脂肪にすると2kgちょっと分でしかなくて、食事制限をしないといかに意味がないかということがわかりますね。

リングフィットで世界一

リングフィットには同年齢の人たちで運動量(回数)を比較してくれる機能があります。 私がリングフィットを買ったのは発売日から8か月経っていましたが、いくつか1位を取ることができました。

世界一・・・・・いい響きだ。

リングフィットではストーリー中で運動を行いやすい種目と、あまり行わない種目の二つがあって、私がやったのはろくろ回し。 どの年代でも2時間ぐらいやれば世界一になれるんじゃないでしょうか。*2

f:id:megascus:20201018170937p:plain
世界一

他に一つものすごく世界一になりやすい種目がありますが、そちらを公開すると10分ぐらいで世界一になってしまう人も出てくるので、どうしても世界一になりたい人は探してみてください。 ヒントとしてはサイレントモードのスロートレーニングです。

カロカン

カロリーカンスト、略してカロカン。 リングフィットを普通にやってると100kcal前後で一日の運動を終了することになるのですが、一日当たり999.99kcalまでしか測れないことを利用してカロリーカンストまで頑張るという遊びがあったので私もやってみました。 マラソンで稼ぐ人が多いようですが、サイレントモードだとマラソンのカロリー消費量が少ないのでろくろ回しで。 1分当たり10kcalぐらい消費できるので結構すぐに終わりました。

f:id:megascus:20201018171456p:plain
カロカン

リングフィットの感想

個人的には大ヒットでした。ジムで運動してると最終的にはつらい、しにたい、なんでこんなことやってるんだ・・・・・みたいな考えしか出てこなくなるけど、最初から最後まで楽しく運動できた感じ。 ただ、いくつかほかの人に勧めるとか、継続的に行うことを考えると二つほどよくないところがありました。

一つ目としては最初の負荷決定がヒアリングに寄ってるんだけど、それで出てくる負荷がちょっと高すぎでは?という気がしました。

普通の人というのは営業で外回りをして半日歩いてるとか、ちゃんと毎日家事をしてますとかいう人たちのことで、座り作業しかやってない人というのは普通よりずっと少ない運動量なんだと。 自己申告よりも5ぐらい下げるぐらいでちょうどよかったんじゃないでしょうか。 続けられそうなら上げればいいわけですし。 最初の種目がわりと負荷が高めなものもあって、続けられない人が多いというのは非常に残念です。 1週目クリアまで行けてる人も統計情報を見る限り2割前後しかいなさそうですし。 負荷30で3日で終わってしまうよりは負荷1でも最後まで行けたほうが素晴らしいことなので、負荷を軽くしてでも最後までやってほしいなぁという気持ちです。

二つ目としてはリングコンが小さすぎる!

なんとなく、150 cm~160cmぐらいの人間にちょうど良い大きさで作られているような気がします。 私にはリングコンが小さすぎて一部出来ない種目がありました。 具体的にはカタニプッシュ。 筋肉が盛り上がってくるとリングコンを潰すことができなくなって、bestが取れない・・・・・

リングアローも出来ないことはないですが、鍛えられる場所が違う感じがしますね。前の腕ばかり疲れる。

次回作では大きめなリングコンも売り出してほしいですねぇ。1.5倍ぐらいあるやつ。

という感じで、非常に面白いし、たぶんこれからもリングコンが壊れるまでやっていくことでしょう。 つらすぎて続かないという人は負荷が高すぎるので、負荷を下げてちょっとでも続けてみてください。

*1:リングフィットアドベンチャー発売から1周年記念の日

*2:私に勝ちたければ5時間ぐらいやる必要があります。

AWS ALBで特定のパスもしくはパスが存在しない場合のみリクエストを許可したい場合

https://example.com/app もしくは https://example.com ではアクセスを許可したいが、それ以外についてはアクセスを許可したくない(404を返したい)場合は以下のように設定する。

  1. パスが/app または /app/* または / の場合は許可する。
  2. パスが /* の場合は固定レスポンス(404)を返す。
  3. それ以外の場合(デフォルト)は許可する。

Javaのメソッド呼び出し階層を表示する

Threadオブジェクトからスタックトレースを取得できるのでそれを使用する。

System.out.println(java.util.Arrays.stream(Thread.currentThread().getStackTrace())
    .skip(1).limit(4).map(t -> t.getClassName() + "." + t.getMethodName()).collect(java.util.stream.Collectors.joining(",")));

skip(1)をかましているのは結果にgetStackTraceメソッド呼び出しも含まれているため。

JavaからActive Directory(LDAPS)接続(自己署名証明書の検証スルーコード付き)

自分向けの備忘録として。

基本はこちら。

kazuhira-r.hatenablog.com

こちらの記事だと自己証明書のスルーに使用しているのが X509TrustManager だが、新しいTLSに対応するためには代わりに X509ExtendedTrustManager を実装してあげる必要がある。

よって、以下のような感じになる。

接続側

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, LDAP_URL);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, AD_USER_NAME);
        env.put(Context.SECURITY_CREDENTIALS, AD_PASSWORD);
        env.put("java.naming.security.protocol", "ssl");
        env.put("java.naming.ldap.factory.socket", LooseSSLSocketFactory.class.getName());

        DirContext ctx = null;
        try {
            List<Map<String, String>> ret = new ArrayList<>();
            ctx = new InitialDirContext(env);

            for (NamingEnumeration<SearchResult> search = ctx.search("OU=XX,dc=XXXX,dc=local", null); search.hasMoreElements();) {
                SearchResult next = search.next();
                Attributes attributes = next.getAttributes();
                //実際の処理
            }
            return ret;
        } catch (AuthenticationException ae) {
            //認証に失敗した
            ae.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ctx != null) {
                try {
                    ctx.close();
                } catch (NamingException ex) {
                }
            }
        }

LooseSSLSocketFactory

package dev.megascus.ssl;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;

public class LooseSSLSocketFactory extends SSLSocketFactory {

    SSLSocketFactory delegate;

    public LooseSSLSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new X509TrustManager[] { new X509ExtendedTrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String string, Socket socket)
                        throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String string, Socket socket)
                        throws CertificateException {
                }

                @Override
                public void checkClientTrusted(X509Certificate[] xcs, String string, SSLEngine ssle)
                        throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] xcs, String string, SSLEngine ssle)
                        throws CertificateException {
                }
            } }, new SecureRandom());

            delegate = sslContext.getSocketFactory();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
        return delegate.createSocket(socket, s, i, b);
    }

    @Override
    public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
        return delegate.createSocket(s, i);
    }

    @Override
    public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
        return delegate.createSocket(s, i, inetAddress, i1);
    }

    @Override
    public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
        return delegate.createSocket(inetAddress, i);
    }

    @Override
    public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
        return delegate.createSocket(inetAddress, i, inetAddress1, i1);
    }

    public static SocketFactory getDefault() {
        return new LooseSSLSocketFactory();
    }
}

なお、Active Directoryは普通にやると1000件しか結果が返ってこない。 1000件以上登録されている可能性がある場合は以下の記事を参考にする。

qiita.com

JavaMailでメールアドレスに名前を付ける

JavaMailで送信したメールに宛先や送信元に名前を表示したい場合がある。

以下のような感じですね。

ゆとり<megascus@megascus.dev>

InternetAddressクラスの3つの引数があるバージョンを使えば対応できる。

docs.oracle.com

日本語を扱う場合、charsetとして"iso-2022-jp"を使用しないと文字化けるので注意。