Preview to Redis OM Spring using RedisJson
/ / Reading Time: 11 MinuteJust a few days ago, Redis CEO Ofer Bengal announced the global availability of RedisJson 2.0. Wondering why that is all cool and worth your time? Well scroll a bit further down and I’ll tell ya!
As always, feel free to skip ahead and check out the Github Repository containing all the code.
What is RedisJson
RedisJson is an in-memory document store that provides real-time access to and processing of JSON documents. RedisJson 2.0 adds native indexing, querying, and full-text search capabilities, all leveraging RediSearch which makes it a very powerfull tool for us Computer Geeks. While document-based databases are becoming a trend because of their flexibility in dynamic scheming, they are still struggling with the performance requirements a relational database offers.
RedisJson seeks these gaps where a document-based database fails to meet the performance requirement, but is perfect for its use-case because of its dynamic scheming.
What is Redis OM Spring
You’re probably wondering.. well how do we use it then? Well it’s true that when you look at the latest version of the Spring Data Redis library it will just use @RedisHash annotations not leveraging any of the features mentioned above. Which is why you need to add the Redis OM Spring library to add all these nice features. Redis Object Mapping, or Redis OM for short, provides annotations like @Document
to map Spring Data models to Redis JSON documents.
Example
Alright so let’s dive into a use-case and see how it works!
Assume we have a webstore that sells all different kinds of things: books, games, good old fashion dvd’s, and more. Everything is going easy peasy, but with the rising amount of orders coming in we start to retroactively cancel, or delay orders because items went out of stock faster than we could update our webstore.
Since we live in this hyper modern world we decide to have a look at live stock updates, which need to be fast, reliable but also dynamic to our articles.
Setup
1 |
|
Every item that we have in our store comes down to being in a certain category, having a price, and the amount of stock that is left. Dependend on the category we can have some specific implementation of details like you can see in the StockItem
above.
We can then define the details specific implementations per category like the examples below.
1 |
|
1 |
|
Alright! So in order to use and save our RedisJson documents we will need to specify our Repository.
1 | import com.redis.om.spring.repository.RedisDocumentRepository; |
Important:
Redis OM Spring will only pickup the repository if you add the @EnableRedisDocumentRepositories
annotation, however as of today, you also need to specify the basePackages
property in order for it to be picked up.
1 |
|
Seeding
We can’t start updating the stock without having actual StockItems in Redis, so we create an event listener that seeds Redis on startup using our Redis Repository.
1 |
|
When we start our application and have a look in redis we can now see we have two StockItems!
1 | $ redis-cli -h localhost -p 6379 --raw |
Updating
We have our data setup, and we can now start updating our stock whenever a new order is placed.
Unfortunately the Redis OM Spring library doesn’t (yet) allow partial document updates using the Repository, or a dedicated template bean. Fortunately it does allow us to autowire a JSONOperations<?>
bean that is capable of doing partial document updates.
Let’s say we have an order coming in, and we need to update the stock right away.
1 | POST /api/v1.0/orders |
We have an OrderService
which will process all incoming orders, and pick every item on the order from the stock.
1 |
|
When picking from the Stock, we call the responsible StockService
.
1 |
|
The StockService
will use the JSONOperations<?>
bean to fetch the stock property from the StockItem and reduce it with the amount that was ordered.
Unfortunately RedisJson does not offer a way (yet) of reducing a numeric property in a single operation, which means theoretically there could be enough stock when we call the get
operation, when while updating the stock another (outside) process could have already claimed it.
Since in this case we are the only running instance, and we are the only one updating these documents, we can manage by declaring the pick method as synchronized
to make sure there is no other thread interfering.
Result
Using the monitor
command in the redis-cli
we can monitor every command that is being executed on our redis-server and see whether our stock is being correctly updated.
1 | 1648204926.982903 [0 xxx.xx.x.x:61670] "SISMEMBER" "nl.vreijsenj.redisjson.stock.StockItem" "01FZ0APKZ9SW1MAPXCPCY3HHK6" |
We can see that our CatalogSeeder
creates the initial StockItems, and keeps an index on the id property.
1 | 1648204941.548383 [0 xxx.xx.x.x:61670] "JSON.GET" "nl.vreijsenj.redisjson.stock.StockItem:01FZ0APM02XF8NAHTXW6PXTYAC" "stock" |
After that when placing the order, we can see that the JSON.GET
and the JSON.SET
operations are called to update the stock in just 5 miliseconds.
Considering this was run from my humble local environment, I say that is pretty damn fast.
That’s all folks! As always if you want to see the full implementation, or just sniff around the codebase, here is the Github Repository.
Cheerios!