Technical Works

ASC Technical support site

*

Infinispanの紹介

      2014/11/25

はじめに

Infinispanはオープンソースデータグリッドプラットフォームで、分散型のインメモリキーと値のNoSQLストアです。ソフトウェアアーキテクトとして、高価なデータストアの前でパフォーマンス強化、分散インメモリキャッシュとして使用します。または分散型のNoSQLデータストアとしてソフトリレーショナルデータベースの代わりに使用する場合もあります。ウェアアーキテクチャでデータグリッドを検討する主な理由は、パフォーマンスです。データへの高速かつ低レイテンシのアクセスの必要性がますます一般的になってきています。

概要

Infinispanは、ミドルウェアと呼ばれるソフトウェアのカテゴリに分類されます。ミドルウェアは、ウェブサイトなどのアプリケーション、およびオペレーティングシステムやデータベースとの間で位置します。ミドルウェアを利用してアプリケーション開発者はより生産的、効果的、かつ速いペースで開発を行うようにしています。Infinispanは、多くの場合、任意のアプリケーション処理やビジネス·ロジックとデータ·ストレージ階層間に配置されデータストレージのボトルネックや競合、潜在的な単一障害点を解消するために使用します。

特徴

  1. 大量のデータをオンメモリで高速処理
  2. 高い耐障害性
  3. 高いスケーラビリティ

まず、Infinispanは大容量のデータをオンメモリで保持することができます。多くのデータを複数のインスタンスで分散して保持します。また、基本的にすべてのデータがメモリ上(JavaVMヒープ上)に格納されているため、非常に高速に処理することができます。次に、Infinispanは複数のインスタンスを立ち上げ、その複数のインスタンスにデータを重複して保持することができます。また、メモリ上のデータをファイルやDBに永続化する機能も備えております。最後に、Infinispanは負荷状況やデータ量に合わせ、動的にノードの追加・削除を行うことができます。同じグループで設定されている場合、インスタンスが起動したタイミングで、自動的にグループに追加されます。

使用モード

Infinispanは、Java(およびいくつかのスカラ)で実装され、2つの異なる方法で使用することができます。Infinispanを含むことにより、Javaアプリケーションに埋め込​​まれた「ライブラリモード」と、Infinispanのインスタンスを起動し、それらがクラスタを形成できるようにする「リモートクライアントサーバモード」があります。

infinisan_libライブラリモード

ライブラリモードはリモートクライアントサーバモードと比べて機能が豊富で、利用可能なAPIも多いためアプリケーションからきめ細かい制御ができます。デメリットを上げるとすれば、Javaアプリケーション以外からはアクセスできない点や、アプリケーション層とデータ層を分けることが出来ないことによる、管理・運用面での弊害等が考えられます。また、データとアプリケーションが同様のJavaヒープを利用することになるため、GC戦略をたてる上で、チューニングが複雑になる傾向があります。

リモートクライアントサーバモードリモートクライアントサーバモード

リモートクライアントサーバモードは、アプリケーションからデータ層を独立して構成できるため、データ量が多く、多数のJDGインスタンスを起動しなければならない場合等には非常に有効なモードです。また、複数アプリケーションからデータ層を共有化できるのもこのモードです。

インストール方法

InfinispanのDownloadサイト(http://infinispan.org/download/)から現時点での安定版である「Infinispan6.0.x」をダウンロードします。

Infinispanダウンロード

上記画面から「All」ボタンを選択し、「infinispan-6.0.2.Final-all.zip」ファイルをダウンロードします。

Infinispanライブラリ

 ダウンロードしたファイルを解凍し、その中に含まれている「infinispan-core.jar」ファイルと「lib」ディレクトリ配下にあるすべてのファイルをクラスパスに通すことでInfinispanを使用することができます。

サンプルコード

 以下のサンプルコードをEditor(もしくは、Eclipse等のIDE)を利用してソースを作成します。

import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class Node {

   private final String cacheName;
   private final String nodeName;
   private volatile boolean stop = false;

   public Node(String cacheName, String nodeName) {
      this.cacheName = cacheName;
      this.nodeName = nodeName;
   }

   public static void main(String[] args) throws Exception {
      String cache = "repl";
      String nodeName = null;

      for (String arg : args) {
         if ("-d".equals(arg)) {
            cache = "dist";
         } else if ("-r".equals(arg)) {
            cache = "repl";
         } else {
            nodeName = arg;
         }
      }
      new Node(cache, nodeName).run();
   }

   public void run() throws IOException, InterruptedException {
      EmbeddedCacheManager cacheManager = createCacheManager();
      final Cache<String, String> cache = cacheManager.getCache(cacheName);
      System.out.printf("Cache %s started on %s, cache members are now %s\n", cacheName, cacheManager.getAddress(), cache.getAdvancedCache().getRpcManager().getMembers());
      printCacheContents(cache);

      Thread putThread = new Thread() {
         @Override
         public void run() {
            int counter = 0;
            while (!stop) {
               try {
                  cache.put("key-" + counter, "" + cache.getAdvancedCache().getRpcManager().getAddress() + "-" + counter);
               } catch (Exception e) {
                  System.out.println("Error inserting key into the cache");
               }
               counter++;
               try {
                  Thread.sleep(1000);
               } catch (InterruptedException e) {
                  break;
               }
            }
         }
      };
      putThread.start();
      System.out.println("Press Enter to print the cache contents, Ctrl+Z to stop.");
      while (System.in.read() > 0) {
         printCacheContents(cache);
      }
      stop = true;
      putThread.join();
      cacheManager.stop();
      System.exit(0);
   }

   private void printCacheContents(Cache<String, String> cache) {
      System.out.printf("Cache contents on node %s\n", cache.getAdvancedCache().getRpcManager().getAddress());
      ArrayList<Map.Entry<String, String> entries = new ArrayList<Map.Entry<String, String>(cache.entrySet());
      Collections.sort(entries, new Comparator<Map.Entry<String, String>() {
         @Override
         public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
            return o1.getKey().compareTo(o2.getKey());
         }
      });
      for (Map.Entry<String, String> e : entries) {
         System.out.printf("\t%s = %s\n", e.getKey(), e.getValue());
      }
      System.out.println();
   }

   private EmbeddedCacheManager createCacheManager() throws IOException {
      System.setProperty("nodeName", nodeName);
      return new DefaultCacheManager("infinispan.xml");
   }
}

 

上記のソースを「Node.java」として保存します。以下のJavaコマンドを利用してコンパイルを行います。Javaは「C:\Dev\Java」配下にインストールした場合の想定です。他にInfinispanのライブラリはまとめてソースがあるディレクトリの「lib」ディレクトリ

JavaコンパイルJavaコンパイル:C:\Dev\Java\jdk1.7.0_72\bin\javac.exe -cp .;lib\* Node.java

コンパイルしたプログラムを実行する場合は、引数としてノード名を指定すればOKです。以下はコマンド窓を2個立ち上げてそれぞれのコマンド窓からプログラムを実行した結果です。

Java実行実行例:
C:\Dev\Java\jdk1.7.0_72\bin\java.exe -cp .;lib\* Node NodeA
C:\Dev\Java\jdk1.7.0_72\bin\java.exe -cp .;lib\* Node NodeB

設定ファイル

上記ソースを実行するための設定ファイルです。まずは、Infinispanの設定ファイル(infinispan.xml)で、クラスタリング設定を行うことができます。他には、ノード間での通信を担う設定ファイル(jgroups.xml)です。

<infinispan.xml>

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:6.0 http://www.infinispan.org/schemas/infinispan-config-6.0.xsd"
    xmlns="urn:infinispan:config:6.0">
  <global>
    <transport nodeName="${nodeName}">
      <properties>
        <property name="configurationFile" value="jgroups.xml"/>
      </properties>
    </transport>
  </global>

  <default>
    <clustering mode="replication">
      <sync/>
    </clustering>
  </default>

  <namedCache name="repl">

  </namedCache>

  <namedCache name="dist">
    <clustering mode="distribution">
      <sync/>
      <hash numOwners="2"/>
    </clustering>
  </namedCache>
</infinispan>

 

<jgroups.xml>

<config xmlns="urn:org:jgroups"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:org:jgroups file:schema/JGroups-3.2.xsd">

    <UDP
            mcast_addr="${jgroups.udp.mcast_addr:228.6.7.8}"
            mcast_port="${jgroups.udp.mcast_port:46655}"
            tos="8"
            ucast_recv_buf_size="200k"
            ucast_send_buf_size="200k"
            mcast_recv_buf_size="200k"
            mcast_send_buf_size="200k"
            loopback="true"
            max_bundle_size="64000"
            max_bundle_timeout="30"
            ip_ttl="${jgroups.udp.ip_ttl:2}"
            enable_diagnostics="false"
            bundler_type="old"

            thread_naming_pattern="pl"

            thread_pool.enabled="true"
            thread_pool.min_threads="2"
            thread_pool.max_threads="30"
            thread_pool.keep_alive_time="60000"
            thread_pool.queue_enabled="true"
            thread_pool.queue_max_size="100"
            thread_pool.rejection_policy="Discard"

            oob_thread_pool.enabled="true"
            oob_thread_pool.min_threads="2"
            oob_thread_pool.max_threads="30"
            oob_thread_pool.keep_alive_time="60000"
            oob_thread_pool.queue_enabled="false"
            oob_thread_pool.queue_max_size="100"
            oob_thread_pool.rejection_policy="Discard"
            />

    <PING timeout="3000" num_initial_members="3"/>
    <MERGE2 max_interval="30000" min_interval="10000"/>
    <FD_SOCK/>
    <FD_ALL timeout="15000"/>
    <VERIFY_SUSPECT timeout="5000"/>
    <pbcast.NAKACK2
            xmit_interval="1000"
            xmit_table_num_rows="100"
            xmit_table_msgs_per_row="10000"
            xmit_table_max_compaction_time="10000"
            max_msg_batch_size="100"/>
    <UNICAST2
            stable_interval="5000"
            xmit_interval="500"
            max_bytes="1m"
            xmit_table_num_rows="20"
            xmit_table_msgs_per_row="10000"
            xmit_table_max_compaction_time="10000"
            max_msg_batch_size="100"
            conn_expiry_timeout="0"/>
    <pbcast.STABLE stability_delay="500" desired_avg_gossip="5000" max_bytes="1m"/>
    <pbcast.GMS print_local_addr="false" join_timeout="3000" view_bundling="true"/>
    <UFC max_credits="200k" min_threshold="0.20"/>
    <MFC max_credits="200k" min_threshold="0.20"/>
    <FRAG2 frag_size="8000"  />
    <RSVP timeout="60000" resend_interval="500" ack_on_delivery="true" />
</config>

最後に

ネットワーク越しでデータを同期したり、ネットワーク内の複数プロセスで同じデータを保持することが簡単にできます。

The following two tabs change content below.

最新記事 by 李 (全て見る)

 - JBoss

Loading Facebook Comments ...

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


*

  関連記事

Infinispanの応用

今回はInfinispanを利用した応用編となります。 今回紹介する機能は以下の …

Active MQ紹介

1.Message Queueとは まず、メッセージとはアプリケーションにとって …

Drools(Java Rules Engine)の紹介

ルール・エンジンとは ルール・エンジンとは、ビジネス上のルールといった「分岐処理 …

Jbossを利用したWebアプリケーションローカル環境構築手順(1/3)

Webアプリケーションの、ちょっとした動作確認や 自由に利用できる自分専用のデー …