I have a system which receives a lot of messages (by JMS) from a provider. The messages are consumed by currently up to 4 servers. The provider sends some of these messages doubled and at the same millisecond... some messages depends on each other. For example one message contains the customer information, the next about his products.
Currently the software, which is deployed on up to 4 servers, listens to the queue and processes the message. Processing means some mapping and storing the data into our database, which is a Oracle or PostGres Database (depends on the installation, but always a relational database). Concurrent modifications are detected by optimistic locking and we have an generic retry mechanism which fixes this issues, when they occur. So no big pain on updates.
But inserts are a problem... for example we receive 2 customer messages in the same ms... the software checks if the customer exists... if it not, it creates it... but if this happens at the same time, both of them try to create the customer. We solved this issue by DB-Constraints (the customerNumber must be unique) or in more complicated cases (where a DB-Constraints is not suitable) by pessimistic locking over a database table (an entry for insert is generated in the locking table, the other insert thread fails to create this entry and knows, that a insert is ongoing and stops it's processing). This worked so far... i guess not the best and prettiest solution, but it worked.
Problem is our processing load grows, we find more and more issues where inserts duplicates data... which causes a lot of problems with the rest of our business logic and must be prevented... the current way is to secure these methods with pessimistic locking by using locking db table...
Currently i'm not sure if we are going into the right direction and may be our design is wrong from the ground... can anyone offer me alternative ideas for this issue? May be some design patterns with advantages and disadvantages?
Our current alternative is to group and load balance the messages (for example with KAFKA). This should make sure that the messages of one customer are processed by one thread => so the concurrent insert is not possible. Opinions about this?
Environment: Java (EJB), Wildfly, Oracle/PostGre DB