[SOA] Automatically Disable Proxy Service to avoid overloading OSB

原文はこちら。
https://blogs.oracle.com/ateamsoab2b/entry/automatic_disabling_proxy_service_when

Oracle Service Bus(OSB)の利用に関する質問でよく尋ねられるのは、「エンドポイントが一時的に接続できなくなったときに、OSBに過負荷がかからないようにするには?」というものです。エンドポイントが想定ほど素早く応答せず、最悪の場合徐々に応答時間が悪化する場合にはどうすればいいのか、という質問も、同じぐらい頂きます。関心はOSBが止まるという潜在的リスク 関連するプロキシサービスが呼び出し側からのリクエストを受信し続けた場合に、OSBが止まるという潜在的リスクに対する懸念があるのです。
設計プラクティスの観点からすると、エンドポイントの可用性を高くしておくことが常に推奨されています。複数のエンドポイントに対するロードバランサやOSBのフェイルオーバ機能を使って、OSBをより安全に、エンドポイントのエラー由来の脆弱性を減らすことができます。さらに、ワークマネージャを構成してプロキシサービスに割当て、ビジネスサービスの流量制御を有効にするという、OSBのベストプラクティスを実装するべきでしょう。これらの2個の機能の詳細はこのエントリでは取り扱いませんので、OSBでのワークマネージャの使用の詳細、流量制御については、以下のリンクから確認して下さい。
Oracle® Fusion Middleware Administrator's Guide for Oracle Service Bus 11g Release 1 (11.1.1.6.3)
Using Work Managers with Oracle Service Bus
http://docs.oracle.com/cd/E23943_01/admin.1111/e15867/modelingmessageflow.htm#OSBAG1428
Throttling
http://docs.oracle.com/cd/E23943_01/admin.1111/e15867/throttling.htm

Oracle® Fusion Middleware Oracle Service Bus管理者ガイド 11g リリース1(11.1.1.6.0) Oracle Service Busでのワーク・マネージャの使用
http://docs.oracle.com/cd/E28389_01/admin.1111/b61436/modelingmessageflow.htm#BACDDGHB
スロットル
http://docs.oracle.com/cd/E28389_01/admin.1111/b61436/throttling.htm
しかし、これはストーリーの全体図ではありません。予期しない問題がエンドポイントで発生したら、その事象を通知して欲しいでしょうし、その事象に対する適切なアクションを取りたいと考えることでしょう。特に唯一のエンドポイントもしくはエンドポイントを管理するシステムが外部にあって管理できない場合はなおさらです。それでは、エンドポイントで以下の2個の頻出する問題が発生したときの通知方法を見ていきましょう。
  • エンドポイントが到達不能になる
  • エンドポイントは生きているが、レスポンスが遅くなりSLAに抵触する
OSBには通信エラーでレスポンスのないエンドポイントURIをオフラインにする、すてきな機能があります。Service Level Agreement (SLA) のルールを定義して、エンドポイントURIがオフラインになったときにアラートを発行することができます。レスポンス時間に関するSLAを定義することもできます。レスポンス時間が定義した時間よりも長い場合、OSBがアラートを自動的に発行することができます。
アラートが発行されれば、取るべき適切なアクションが何かを決定する必要があります。エンドポイントの問題が継続し、迅速に解決できない場合には、取り得るアクションは、問題が切り分けられるまでリクエストを受け付けないプロキシサービスを停止することです。OSB管理コンソールから手作業でプロキシサービスを無効にすることができますし、WLSTでも実現可能です。このエントリでは、エンドポイントの異常でSLAに抵触したときに、プロキシサービスを自動的に無効にする、OSBのJava APIを使った代替手段をご紹介します。
実装手順はおおよそ以下のようになります。
  1. レスポンス時間が想定値を上回る場合、もしくはエンドポイントが到達不能になった場合にアラートを発行するSLAルールを作成する
  2. アラートを指定のJMS Queueに送るよう設定する
  3. JMS Queueを監視する 「管理用」のプロキシサービスを作成する
  4. アラートをJMS Queueから受けた際に関連するプロキシサービスを無効にする Javaコールアウトを 「管理用」プロキシサービス内に作成する
詳細は以下の通りです。

指定したJMS Queueにアラート送るためのアラートの送り先を作成します。

ビジネスサービスを作成し、オフラインになっているエンドポイントURIを有効にします。エンドポイントURIが到達不能であれば、OSBは自動的にステータスをオフラインになります。

SLAを定義します。レスポンス時間の最大値が5000ms(5秒)を超える場合、もしくはエンドポイントがオフラインとマークされた場合に、アラートを発行します。

指定のJMS Queueをチェックする「管理用」プロキシサービスを作成します。

アラートメッセージを受け取ると、アラートをJMS Queueへ送信時にOSBが設定したJMSヘッダーを、プロキシサービスが取得します。このエントリでは、単にアラートメッセージのサービス名ヘッダを使って、このアラートを発行したビジネスサービスを発見することにしています。これを実現するためのXPath式は以下のようになります。
$inbound/ctx:transport/ctx:request/tp:headers/tp:user-header[@name="ServiceName"]/@value
ビジネスサービスの名前に基づいて、どのプロキシサービスが無効なのかを発見するためのパラメータを構成します。最後に、プロキシサービスを無効にするJavaコールアウトを作成します。このエントリではプロキシサービスをハードコーディングで決めうちにしています。

以下はプロキシサービスを無効にするJavaコードのサンプルです。Java APIを使って、プログラムでプロキシサービスを有効/無効にする方法を示しています。同じコードをビジネスサービスにも適用できます。
package com.oracle.ateam;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Hashtable;

import com.bea.wli.sb.management.configuration.SessionManagementMBean;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean;
import weblogic.management.jmx.MBeanServerInvocationHandler;

import com.bea.wli.config.Ref;
import com.bea.wli.sb.management.configuration.ProxyServiceConfigurationMBean;

public class ServiceManager {

    private static JMXConnector initConnection(String hostname, int port,
            String username, String password)
    throws IOException,MalformedURLException
    {
        JMXServiceURL serviceURL =
        new JMXServiceURL("t3", hostname, port,
        "/jndi/" + DomainRuntimeServiceMBean.MBEANSERVER_JNDI_NAME);

        Hashtable <string, string> h = new Hashtable<string, string>();
        h.put(Context.SECURITY_PRINCIPAL, username);
        h.put(Context.SECURITY_CREDENTIALS, password);
        h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");

        return JMXConnectorFactory.connect(serviceURL, h);
    }

    private static Ref convertServiceURI2Ref(String resType,String serviceuri){
        Ref ref = null;
        if((serviceuri.equals(""))||(serviceuri==null))
                return ref;

        String[] uriData = serviceuri.split("/");
        ref = new Ref(resType,uriData);
        return ref;
    }

    public static void changeProxyServiceStatus(String serviceref,boolean status)throws Exception{
        JMXConnector conn = null;
        SessionManagementMBean sm = null;
        String sessionName = "Session.ByApp." + System.currentTimeMillis();

        try{

            conn = initConnection("localhost", 7001, "weblogic", "welcome1");
            MBeanServerConnection mbconn = conn.getMBeanServerConnection();
            DomainRuntimeServiceMBean domainService = (DomainRuntimeServiceMBean) MBeanServerInvocationHandler.
                 newProxyInstance(mbconn, new ObjectName(DomainRuntimeServiceMBean.OBJECT_NAME));

            sm = (SessionManagementMBean) domainService.
                 findService(SessionManagementMBean.NAME,
                             SessionManagementMBean.TYPE, null);

            sm.createSession(sessionName);

            ProxyServiceConfigurationMBean proxyConfigMBean = (ProxyServiceConfigurationMBean) domainService.
             findService(ProxyServiceConfigurationMBean.NAME + "." + sessionName,
                     ProxyServiceConfigurationMBean.TYPE, null);
            Ref ref = convertServiceURI2Ref("ProxyService",serviceref);
            String msg = "";
            if(!status){
               proxyConfigMBean.disableService(ref);
               msg="Disabled the Proxy Service : " + serviceref;
            }
            else {             
                proxyConfigMBean.enableService(ref);   
                msg="enabled the Proxy Service : " + serviceref;
            }                                 

            sm.activateSession(sessionName, msg);
            System.out.println(msg);
            conn.close();
        }catch(Exception ex){
            if(null != sm) {
                try{
                    sm.discardSession(sessionName);
                }catch(Exception e) {
                    System.out.println("discard session error");
                }
            }
            throw ex;
        }finally{
            if(null != conn)
                try{
                    conn.close();
                }catch(Exception e) {
                    e.printStackTrace();
                }
        }
    }
}
SLAで定義した5秒よりも長い、10秒間のスリープをエンドポイントに配置すると、下図のように、プロキシサービスが自動的に無効になります。

エンドポイントを停止するという別のテストでも、期待通り同じ結果(自動的にプロキシサービスが無効になる)が得られます。同時に、OSBが自動的にエンドポイントをオフラインとマークしていることも確認できます。

このエントリで、エンドポイントが到達不能になったり、SLAに抵触する場合に自動的にプロキシサービスを無効にする方法を説明しました。しかし自動化を検討される場合にはご注意頂く必要があります。その理由は、プロキシサービスを無効にするべきかどうか、いつ無効にすべきかを判断するための、非常に多くの検討・評価すべき要素や基準があるからです。代わりに、上記サンプルに手を入れてアラート発行とJava APIを使ったプロキシサービスの無効化の2ステップに分け、その後人が決定するという手順を間に追加することもできます。

0 件のコメント:

コメントを投稿