Replies: 3 comments 6 replies
-
Hi @arnarg, great question. One baseline assertion I want to make is that given a stream and a consumer with a single subscription, you have guaranteed ordered processing per entity (barring redeliveries). Of course the events per entity are interleaved, but relative order per entity is maintained. How I am reading your question is more like you want to achieve some degree of concurrent processing of entity events? Have you benchmarked how fast a single stream and consumer can process these events to get a baseline? The one issue with the 100 goroutines within the application is that the degree of parallelism you will achieve is dependent on how many CPU cores you have. With the overhead of context switching, it will likely be more performant and use less memory if you have fewer. But again, I think getting a baseline for one should be a starting point. If you determine you need to scale out, I would recommend to define partitioning as a subject mapping and have N corresponding streams for each partition. Publishers can still publish to Then you would create one consumer per stream for totally ordered processed of all entities in that "partition". You could then choose to run N goroutines for the consumers in a single application or deploy an application per consumer so they get their own resources, etc. If you want to run multiple instances for HA, then you can still apply the MaxAckPending setting, but of course that will be significantly decrease your consumption throughput. There is a different strategy for active-failover that can be achieved by using a KV bucket to grab a "lease" which provides exclusivity of one instance in an HA setup.. let me know if you want to know more about that 😉 Hopefully this helps! |
Beta Was this translation helpful? Give feedback.
-
Thanks for you response @bruth. What I want is basically automatic partition rebalancing which is available in kafka and pulsar. But given that this is not possible out of the box in NATS Jetstream and I don't really want to implement the rebalancing myself, I was wondering if some stream and subject design is possible to achieve my needs. I want to be able to have high parallel processing if I scale the application up to many instances, but low parallelism in the application itself. I don't want to have to run more than 1 instance to cover all partitions and I don't want to have to statically configure my application to choose which partition subjects to subscribe to. My application is running an external process (terraform) per entity which is why I don't want to have to have high parallel processing in a single instance as it will require each instance to need a lot of resources, which would often be idle. But if there are a lot of pending messages on the stream the system could automatically scale the application to run more instances and then scale back to 1 once the queue is empty. But when the load is low a single instance can process every entity message. I hope any of this makes sense. This is all solved with automatic partition rebalancing in other systems and is in my opinion a short-coming in NATS Jetstream (but in every other aspect it is better). |
Beta Was this translation helpful? Give feedback.
-
@bruth could you explain more about the different strategies for active-failover using a KV bucket for HA setup? thanks! |
Beta Was this translation helpful? Give feedback.
-
I need to process events for an "entity", and these events are just metadata for said entity. There are "entity creation", "entity modification" and "entity deletion" event types, all going on the same subject (per entity ID). The processing involves creating some resources in a cloud environment so can take up to 10-20 seconds but the destruction can take up to a minute.
In order to add some scalability but still strict ordering per entity ID I have constructed the following idea:
APPLICATION.entity.*
and has a re-publish rule with sourceAPPLICATION.entity.*
and destinationAPPLICATION.q.entity.{{partition(100,1)}}.{{wildcard(1)}}
to enable partitioning by the entity ID.WorkQueuePolicy
captures subjectAPPLICATION.q.entity.*.*
.MaxAckPending
of 1.This gives me the ordering guarantees per entity but still some parallel processing happening. I however saw some problems with this approach.
Is there any way of achieving my goals without these issues. I do not want to have to run many instances of the application, 1 instance should be able to process all of them but scaling it to more instances should be faster. I don't want keep a huge amount of state myself, ideally.
Thanks in advance!
Beta Was this translation helpful? Give feedback.
All reactions