我在这里搜索了一个好的模式,但是找不到任何东西。
首先,我在订阅主题的群集中有多个节点。因为我正在与外部API接口,所以我无法将此主题更改为队列(这将解决我的问题)。当消息进入该主题时,订阅者会做出反应,但我需要确保只有一个订阅者真正做任何工作。
我有多个节点用于持久性和可扩展性。我想过只选一个主节点,但随着时间的推移会有多个主题,而且我不希望只有一个节点一直负责所有消息。这里不需要Hazelcast。
@Named
public class MessageProcessorImpl
implements MessageProcessor
{
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance();
private final Lock lock;
private final List<Message> messageListCache;
private final IAtomicLong cachePositionCounter;
private final Long maximumRecentlyProcessedCachedSize = 10L;
private static final Logger logger = LoggerFactory.getLogger(MessageProcessorImpl.class);
private final ExternalMessageService externalMessageService;
@Inject
public MessageProcessorImpl(final ExternalMessageService externalMessageService)
{
lock = hazelcastInstance.getLock("test-lock");
messageListCache = hazelcastInstance.getList("test-list");
cachePositionCounter = hazelcastInstance.getAtomicLong("test-atomic-long");
this.externalMessageService = externalMessageService;
}
@Override
public void processMessage(final Message message) {
try {
logger.trace("Acquiring lock");
lock.lock();
if (!messageListCache.contains(message)) {
Long currentIndex = cachePositionCounter.getAndIncrement();
if (currentIndex >= maximumRecentlyProcessedCachedSize) {
currentIndex = 0L;
cachePositionCounter.set(currentIndex);
}
messageListCache.add(toIntExact(currentIndex), message);
externalMessageService.doSomething(message);
}
}
finally {
logger.trace("releasing lock");
lock.unlock();
}
}
}
正如您所看到的,我正在使用最近处理的邮件列表来防止重复工作。这里的问题很明显,如果该列表不堪重负会怎样。我可以设置相对较高的缓存,但不是无限的,因此列表不会永远增长。此外,检查消息是否在列表中会有一些开销。
是否有更好的解决方案或方法可以避免该列表的边缘情况被淹没并导致重复工作?我甚至不确定这是否是一个有效的问题,很难推理。我应该尝试不同的方法吗?
答案 0 :(得分:0)
这个答案很晚。但是,在这种情况下可能有用的模式是领导选举。也就是说,选择一个节点来处理来自主题的消息,而其他节点则等待直到成功处理了该消息。领导随每条信息而变化。
Apache Zooker可以进行分布式锁定/领导者选举,请参阅here