データベース

Hazelcast

概要

Hazelcastは、Javaで開発されたオープンソースのインメモリデータグリッドプラットフォームです。分散キャッシュ、計算、ストレージを統合したソリューションを提供し、高性能でスケーラブルなアプリケーションの構築を支援します。

リアルタイムアプリケーション向けに設計されており、低レイテンシでの大量データ処理、分散コンピューティング、ストリーム処理を一つのプラットフォームで実現できるのが特徴です。

詳細

  • 開発: Hazelcast社によって開発・保守
  • アーキテクチャ: P2P分散アーキテクチャ(マスター/スレーブなし)
  • データ分散: 自動シャーディングと複製
  • 高可用性: 自動フェイルオーバーとデータ復旧
  • 言語サポート: Java(ネイティブ)、.NET、C++、Python、Go、Node.js
  • CPサブシステム: 分散ロック、セマフォ、アトミック操作をサポート
  • ストリーム処理: Hazelcast Jet統合による高性能ストリーム処理
  • セキュリティ: TLS/SSL、JAAS、Kerberos認証対応
  • クラウド対応: AWS、Azure、GCP、Kubernetes環境をサポート
  • 管理: Management CenterによるWebベース管理UI

メリット・デメリット

メリット

  • 自動分散: データとコンピューティングの自動分散・複製
  • P2Pアーキテクチャ: 単一障害点がないピアツーピア構成
  • 高いパフォーマンス: メモリベースによる低レイテンシ処理
  • スケーラビリティ: ノード追加による線形スケーラビリティ
  • 豊富な機能: Map、Queue、Topic、Lock等の多様なデータ構造
  • エンタープライズレディ: 商用サポートと管理ツール完備

デメリット

  • メモリ消費: 大量データ保存時の高いメモリ要件
  • Java依存: JVMベースのため他言語との統合に制約
  • 複雑さ: 分散システム特有の設定・運用の複雑さ
  • 永続化コスト: データ永続化のための追加設定とオーバーヘッド
  • ライセンス: 商用機能には有償ライセンスが必要

主要リンク

書き方の例

セットアップ・設定

<!-- Maven依存関係(pom.xml) -->
<dependencies>
    <dependency>
        <groupId>com.hazelcast</groupId>
        <artifactId>hazelcast</artifactId>
        <version>5.4.0</version>
    </dependency>
</dependencies>
// 基本的なHazelcastインスタンスの起動
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;

public class HazelcastServer {
    public static void main(String[] args) {
        // デフォルト設定でHazelcastインスタンス起動
        HazelcastInstance hz = Hazelcast.newHazelcastInstance();
        
        System.out.println("Hazelcast instance started");
        
        // アプリケーション終了時
        // hz.shutdown();
    }
}

基本操作(CRUD)

// 分散マップ(IMap)の基本操作
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;

public class BasicMapOperations {
    public static void main(String[] args) {
        HazelcastInstance hz = Hazelcast.newHazelcastInstance();
        
        // 分散マップの取得
        IMap<String, String> customerMap = hz.getMap("customers");
        
        // データの保存(PUT)
        customerMap.put("user:1001", "田中太郎");
        customerMap.put("user:1002", "佐藤花子");
        
        // データの取得(GET)
        String customer = customerMap.get("user:1001");
        System.out.println("Customer: " + customer);
        
        // データの更新
        customerMap.put("user:1001", "田中次郎");
        
        // データの削除
        customerMap.remove("user:1002");
        
        // 全データサイズ
        System.out.println("Map size: " + customerMap.size());
        
        hz.shutdown();
    }
}

クライアント接続設定

// Hazelcastクライアント設定
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
import com.hazelcast.core.HazelcastInstance;

public class HazelcastClientExample {
    public static void main(String[] args) {
        // クライアント設定
        ClientConfig clientConfig = new ClientConfig();
        clientConfig.setClusterName("my-cluster");
        clientConfig.getNetworkConfig().addAddress("127.0.0.1:5701", "127.0.0.1:5702");
        
        // クライアント接続
        HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);
        
        // 分散マップへのアクセス
        IMap<String, String> map = client.getMap("example-map");
        map.put("key1", "value1");
        
        System.out.println("Value: " + map.get("key1"));
        
        client.shutdown();
    }
}

分散データ構造の活用

// 複数のデータ構造を使用した例
import com.hazelcast.core.*;
import com.hazelcast.collection.IQueue;
import com.hazelcast.topic.ITopic;
import com.hazelcast.cp.IAtomicLong;

public class DistributedDataStructures {
    public static void main(String[] args) {
        HazelcastInstance hz = Hazelcast.newHazelcastInstance();
        
        // 分散キュー
        IQueue<String> queue = hz.getQueue("task-queue");
        queue.put("task1");
        queue.put("task2");
        String task = queue.take(); // ブロッキング操作
        
        // 分散トピック(Pub/Sub)
        ITopic<String> topic = hz.getTopic("notifications");
        topic.addMessageListener(message -> {
            System.out.println("受信: " + message.getMessageObject());
        });
        topic.publish("新しい通知");
        
        // 分散アトミック変数
        IAtomicLong counter = hz.getCPSubsystem().getAtomicLong("global-counter");
        long newValue = counter.incrementAndGet();
        System.out.println("カウンター: " + newValue);
        
        // 分散ロック
        FencedLock lock = hz.getCPSubsystem().getLock("shared-resource");
        lock.lock();
        try {
            // クリティカルセクション
            System.out.println("リソースへの排他アクセス");
        } finally {
            lock.unlock();
        }
        
        hz.shutdown();
    }
}

設定ファイルによる詳細設定

<!-- hazelcast.xml -->
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.hazelcast.com/schema/config 
           http://www.hazelcast.com/schema/config/hazelcast-config-5.4.xsd">
    
    <cluster-name>production-cluster</cluster-name>
    
    <network>
        <port auto-increment="true" port-count="20">5701</port>
        <join>
            <multicast enabled="false"/>
            <tcp-ip enabled="true">
                <member>192.168.1.100</member>
                <member>192.168.1.101</member>
                <member>192.168.1.102</member>
            </tcp-ip>
        </join>
    </network>
    
    <map name="customer-cache">
        <backup-count>1</backup-count>
        <eviction eviction-policy="LRU" max-size-policy="PER_NODE" size="10000"/>
        <time-to-live-seconds>300</time-to-live-seconds>
    </map>
    
    <cp-subsystem>
        <cp-member-count>3</cp-member-count>
        <group-size>3</group-size>
    </cp-subsystem>
    
</hazelcast>

実用例(キャッシュとしての活用)

// Springアプリケーションでのキャッシュ統合例
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#userId")
    public User getUserById(Long userId) {
        // データベースからユーザー情報を取得(重い処理)
        return userRepository.findById(userId);
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    public void updateUser(User user) {
        userRepository.save(user);
    }
}

// Hazelcast設定
@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        return new HazelcastCacheManager(hazelcastInstance());
    }
    
    @Bean
    public HazelcastInstance hazelcastInstance() {
        Config config = new Config();
        config.getMapConfig("users")
              .setTimeToLiveSeconds(3600)
              .setBackupCount(1);
        return Hazelcast.newHazelcastInstance(config);
    }
}

ベストプラクティス

// プロダクション向け設定例
import com.hazelcast.config.*;

public class ProductionConfig {
    public static Config createProductionConfig() {
        Config config = new Config();
        
        // クラスター名
        config.setClusterName("production-cluster");
        
        // ネットワーク設定
        NetworkConfig network = config.getNetworkConfig();
        network.setPort(5701).setPortAutoIncrement(true);
        
        // セキュリティ設定
        SecurityConfig security = config.getSecurityConfig();
        security.setEnabled(true);
        
        // メトリクス有効化
        MetricsConfig metrics = config.getMetricsConfig();
        metrics.setEnabled(true)
               .setCollectionFrequencySeconds(5)
               .setJmxConfig(new MetricsJmxConfig().setEnabled(true));
        
        // 管理センター設定
        ManagementCenterConfig mcConfig = config.getManagementCenterConfig();
        mcConfig.setConsoleEnabled(true)
                .addTrustedInterface("192.168.1.*");
        
        // マップ設定(TTLとバックアップ)
        MapConfig mapConfig = new MapConfig("session-cache");
        mapConfig.setTimeToLiveSeconds(1800)  // 30分TTL
                 .setBackupCount(1)
                 .setAsyncBackupCount(1)
                 .setReadBackupData(true);
        
        config.addMapConfig(mapConfig);
        
        return config;
    }
}

CLI操作とモニタリング

# Hazelcast CLIツールの使用例
hz-cli

# クラスター情報確認
hz-cli cluster list

# マップの統計情報表示
hz-cli map stats -n myMap

# クラスターメンバー確認
hz-cli member list

# SQLクエリ実行
hz-cli sql "SELECT * FROM customers WHERE age > 25"
// JMXによるモニタリング
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;

public class HazelcastMonitoring {
    public void printMapStatistics(String mapName) {
        try {
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            ObjectName objectName = new ObjectName(
                "com.hazelcast:instance=_hzInstance_1_dev,type=IMap,name=" + mapName
            );
            
            long size = (Long) server.getAttribute(objectName, "Size");
            long hits = (Long) server.getAttribute(objectName, "Hits");
            long misses = (Long) server.getAttribute(objectName, "Misses");
            
            System.out.println("Map: " + mapName);
            System.out.println("Size: " + size);
            System.out.println("Hits: " + hits);
            System.out.println("Misses: " + misses);
            System.out.println("Hit Rate: " + (hits * 100.0 / (hits + misses)) + "%");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}