データベース
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();
}
}
}