Статьи

Кластерный идемпотентный потребительский паттерн с Infinispan

Я создал небольшой проект, который показывает, как использовать JBoss Infinispan с Apache Camel и Идемпотентный шаблон потребителя, чтобы гарантировать, что сообщение не будет обрабатываться дважды в кластерной среде.
Представьте, что у вас есть приложение, которое можно легко масштабировать, развернув его на нескольких контейнерах. Но приложение должно обрабатывать каждый уникальный запрос только один раз в кластере.
Решение простое: используйте Idempotent Consumer Pattern в Camel с хранилищем, которое можно легко масштабировать. Здесь Infinispan вступает в игру. Infinispan является чрезвычайно масштабируемым, высокодоступным хранилищем ключей / значений и сеткой данных. Если вы используете InfinispanIdempotentRepository с идемпотентным потребителем, он создаст кэш в памяти для хранения запросов, и в момент запуска другого экземпляра приложения экземпляры кэша синхронизируются, а идемпотентные потребители во всех приложениях не будут обрабатывать существующие запросы. больше

IdempotentConsumer (2)
С помощью этого проекта (idempotent consumer demo5) вы можете запустить столько контейнеров, сколько хотите, каждый контейнер запустит конечную точку отдыха на новом порту, начиная с 8080 (http: // localhost: 8080 / idempotent / KEY), и если вы выполните запрос GET с ключом, последующие запросы с тем же ключом к любому другому контейнеру будут отклонены. За кулисами Infinispan реплицирует все обработанные ключи в кластере приложений Camel и обеспечивает согласованность.

Основой приложения является следующее определение маршрута, которое находит новый номер свободного порта для каждого экземпляра приложения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class IdempotentRoute extends RouteBuilder {
    private static final transient Logger LOGGER = LoggerFactory.getLogger(IdempotentRoute.class);
 
    private InfinispanIdempotentRepository infinispanRepo;
    private int port;
 
    @Override
    public void configure() throws Exception {
        from("restlet:http://localhost:" + port + "/idempotent/{key}?restletMethods=GET")
 
                .idempotentConsumer(header("key"), infinispanRepo)
                    .setBody(simple("UNIQUE REQUEST ACCEPTED: ${header.key}"))
                    .stop()
                 .end()
 
                .setBody(simple("REQUEST REJECTED: ${header.key}"));
    }
 
    public InfinispanIdempotentRepository getInfinispanRepo() {
        return infinispanRepo;
    }
 
    public void setInfinispanRepo(InfinispanIdempotentRepository infinispanRepo) {
        this.infinispanRepo = infinispanRepo;
    }
 
    public void start() {
         port = AvailablePortFinder.getNextAvailable(8080);
         LOGGER.info("Using port: " + port);
    }
}

Просто, не правда ли?