← Назад к вопросам

Когда стоит использовать Hazelcast?

2.8 Senior🔥 101 комментариев
#Кэширование и NoSQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Когда использовать Hazelcast: практический анализ

Hazelcast — это открытый Java фреймворк для распределённого кеширования и обработки данных в памяти. Это не просто кеш, а мощная платформа для масштабируемых систем.

Что такое Hazelcast?

// Базовое использование Hazelcast
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;

public class HazelcastExample {
    public static void main(String[] args) {
        // Создание Hazelcast инстанса
        HazelcastInstance hz = Hazelcast.newHazelcastInstance();
        
        // Распределённая Map (кеш)
        IMap<String, String> map = hz.getMap("users");
        map.put("user1", "John Doe");
        System.out.println(map.get("user1"));  // John Doe
        
        // Распределённый Queue
        // Распределённый Lock
        // Распределённый Topic (pub/sub)
    }
}

Ключевые характеристики Hazelcast

1. Распределённость (In-Memory Data Grid)

  • Данные распределены по узлам кластера
  • Каждый узел имеет копию данных
  • Автоматическая синхронизация

2. Высокая доступность

  • Replicated backup на нескольких узлах
  • Восстановление при сбое узла
  • Zero-downtime deployment

3. Производительность

  • Всё в памяти (не на диске)
  • Минимальные сетевые задержки
  • Миллисекундные операции

Сценарий 1: Кеширование часто запрашиваемых данных

Когда использовать: Когда одни и те же данные запрашиваются очень часто из БД

public class UserService {
    private final HazelcastInstance hz;
    private final IMap<String, User> userCache;
    private final UserRepository userRepository;
    
    public UserService(HazelcastInstance hz, UserRepository repo) {
        this.hz = hz;
        this.userCache = hz.getMap("users");
        this.userRepository = repo;
    }
    
    public User getUserById(Long id) {
        String key = "user:" + id;
        
        // Сначала ищем в кеше
        User cached = userCache.get(key);
        if (cached != null) {
            return cached;  // Быстро из памяти
        }
        
        // Если нет — берём из БД
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
        
        // Кешируем с TTL (Time To Live)
        userCache.put(key, user, 1, TimeUnit.HOURS);
        return user;
    }
    
    public void updateUser(Long id, UserUpdateRequest request) {
        User user = userRepository.findById(id).orElseThrow();
        user.setName(request.getName());
        user.setEmail(request.getEmail());
        
        userRepository.save(user);
        
        // Инвалидируем кеш
        userCache.remove("user:" + id);
    }
}

Сценарий 2: Распределённая сессия в микросервисах

Когда использовать: Когда у вас несколько инстансов приложения и нужно делиться сессиями

// Spring конфигурация для Hazelcast сессий
@Configuration
@EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = 1800)
public class SessionConfig {
    @Bean
    public Config hazelcastConfig() {
        Config config = new Config();
        config.setInstanceName("hazelcast-instance")
              .addMapAttributeConfig(new MapAttributeConfig()
                  .setName(HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
                  .setExtractor(PrincipalNameExtractor.class));
        return config;
    }
    
    @Bean
    public HazelcastInstance hazelcastInstance(Config config) {
        return Hazelcast.newHazelcastInstance(config);
    }
}

// Использование в контроллере
@RestController
public class LoginController {
    @PostMapping("/login")
    public ResponseEntity<?> login(
            @RequestBody LoginRequest request,
            HttpSession session) {  // Сессия автоматически в Hazelcast
        
        User user = authenticateUser(request);
        session.setAttribute("user", user);
        
        return ResponseEntity.ok("Logged in");
    }
}

Сценарий 3: Распределённая блокировка (Distributed Lock)

Когда использовать: Когда нужно синхронизировать доступ к ресурсам между несколькими узлами

public class OrderService {
    private final HazelcastInstance hz;
    
    public void processOrder(Long orderId) {
        // Получаем распределённый lock
        ILock lock = hz.getLock("order:" + orderId);
        
        try {
            // Берём lock с timeout
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                // Критическая секция: только один узел за раз
                Order order = getOrder(orderId);
                order.setStatus(OrderStatus.PROCESSING);
                updateOrder(order);
                
                // Отправляем на обработку
                sendToProcessor(order);
            } else {
                throw new LockAcquisitionException("Could not acquire lock");
            }
        } finally {
            lock.unlock();
        }
    }
}

Сценарий 4: Pub/Sub система для событий

Когда использовать: Когда нужно отправлять сообщения между микросервисами в реальном времени

// Издатель события
@Service
public class UserCreatedPublisher {
    private final HazelcastInstance hz;
    
    public void publishUserCreated(User user) {
        ITopic<UserCreatedEvent> topic = hz.getTopic("user-created");
        topic.publish(new UserCreatedEvent(user.getId(), user.getEmail()));
    }
}

// Подписчик события
@Service
public class UserCreatedSubscriber {
    private final HazelcastInstance hz;
    
    @PostConstruct
    public void subscribe() {
        ITopic<UserCreatedEvent> topic = hz.getTopic("user-created");
        topic.addMessageListener(message -> {
            UserCreatedEvent event = message.getMessageObject();
            // Обработка события (например, отправка письма)
            sendWelcomeEmail(event.getUserId());
            // Или синхронизация с другим сервисом
            syncWithAnotherService(event);
        });
    }
}

Сценарий 5: Распределённый счётчик и метрики

Когда использовать: Для подсчёта событий в распределённой системе

public class MetricsService {
    private final HazelcastInstance hz;
    
    public void recordApiCall(String endpoint) {
        // Атомарный счётчик доступный со всех узлов
        IAtomicLong counter = hz.getCPSubsystem()
            .getAtomicLong("api:" + endpoint);
        counter.incrementAndGet();
    }
    
    public long getApiCallCount(String endpoint) {
        IAtomicLong counter = hz.getCPSubsystem()
            .getAtomicLong("api:" + endpoint);
        return counter.get();
    }
}

Сценарий 6: Real-time анализ больших данных

Когда использовать: Для обработки потоков событий с низкой задержкой

public class StreamProcessing {
    private final HazelcastInstance hz;
    
    public void analyzeStream() {
        IMap<String, EventData> events = hz.getMap("events");
        
        // Обработка большого объёма данных параллельно
        events.entrySet().parallelStream()
            .filter(entry -> entry.getValue().isImportant())
            .forEach(entry -> {
                processEvent(entry.getValue());
            });
    }
}

Когда НЕ использовать Hazelcast

❌ Неподходящие случаи:

СценарийПочему не подходитАльтернатива
Простое приложение на одном узлеИзбыточная сложностьCaffeine, EhCache
Нужна персистентность на дискHazelcast главно для памятиRedis, MongoDB
Огромные объёмы данных (>100GB)Ограничена доступная памятьSpark, Hadoop
Очень низкая задержка (<1ms)Сетевые задержки неизбежныЛокальный кеш (Caffeine)

Сравнение с альтернативами

Hazelcast vs Redis:

Hazelcast:
✅ Встроен в Java приложение (no extra infra)
✅ Богатый API (locks, queues, pub/sub)
❌ Требует больше памяти
❌ Сложнее развёртывание

Redis:
✅ Минимальное использование памяти
✅ Универсален для любого языка
✅ Простой и стабильный
❌ Внешняя система (отдельный сервер)
❌ Сетевые задержки

Hazelcast vs Caffeine:

Hazelcast:
✅ Распределённый кеш (несколько узлов)
✅ Встроенные распределённые структуры
❌ Больше памяти и CPU

Caffeine:
✅ Локальный кеш (быстро на одном узле)
✅ Минимальные зависимости
❌ Не распределённый

Рекомендуемая конфигурация

# hazelcast.yaml для production
hazelcast:
  cluster-name: my-cluster
  instance-name: node1
  
  network:
    port: 5701
    public-address: node1.example.com
    join:
      kubernetes:
        enabled: true
        namespace: default
        service-name: hazelcast-service
  
  map:
    users-cache:
      time-to-live-seconds: 3600
      max-idle-seconds: 1800
      eviction:
        max-size-policy: PER_NODE
        max-size: 10000
        eviction-policy: LRU
    
    order-locks:
      time-to-live-seconds: 300
      backup-count: 1

Заключение: Когда использовать Hazelcast

✅ Используй Hazelcast когда:

  1. Многоузловое приложение (микросервисы, горизонтальное масштабирование)
  2. Нужно делиться данными между инстансами приложения
  3. Требуется низкая задержка (микросекунды) при доступе к данным
  4. Нужны распределённые примитивы (locks, queues, pub/sub)
  5. Можно позволить использование дополнительной памяти
  6. Java экосистема с Spring Framework

❌ Не используй когда:

  • Одноузловое приложение
  • Нужна персистентность на диск
  • Очень большие данные (более доступной памяти)
  • Приложение на других языках (Python, Go, .NET)
  • Нужен простой кеш на одном узле

Итог: Hazelcast идеален для высоконагруженных распределённых Java приложений, где нужна скорость, отказоустойчивость и синхронизация данных между узлами.

Когда стоит использовать Hazelcast? | PrepBro