I have a simple use case:
- Newsfeeds aggregated based on posts that are linked to geopoints
- Users can comment on feed posts
- Users can like feed posts and comments
I'm certain that Redis as a cache can provide me with what I need if this app were to come under high load, however I am a bit puzzled about the following options:
Write-through cache
Java app -> Redis -> DB
Seems like the best option data consistency-wise, in that the request will only return when the database has been updated. However the disadvantage implies that no batch updates are possible.
If the app were to come under heavy load, this doesn't seem to be the best option.
Write-behind cache
Java app -> Redis -> Java app (batch config) -> DB
Seems like the best option performance wise. In case of heavy load, data is transferred from the cache to the DB through Java (configuring batch sizes, delay etc).
However, the disadvantage seems that if there is a system failure on Redis, all in-memory data is gone (?)!
My question is simple:
- Does a high-availability cluster with write-behind cache solve all of my problems?
- Does high-availability write to disk (Redis), guaranteeing that no data will be lost?
- Even with write-behind cache, is it the safest course of action to add a message queue (eg RabbitMq) or is this generally not necessary even under high load?
Missing posts in a user app like this in case of failure is a big no-no, so I wonder what is your view on this, and what is the best resolution of the problem.
Best Answer
Your question is specific, so I'll answer it head-on first.
I anticipate that "write-behind" cache will be better. "write-through" might help with occasional spikes in ingress data, but won't alleviate the problem of disk throughput (and transaction throughput).
Of course, this would need to be verified in real-life with benchmarking.
My recommended implementation
I strongly recommend that you don't overengineer your architecture. Less is more.
YAGNI: Start simple and tunable, then update your architecture as needed.
1. Bypass the Java and Redis, and write directly to the database
select * from View_DataWebGateways order by RAND() limit 1;
posts
table today, and be able to change that in the future. Query something like:insert into WriteView_Posts (...) values (...)
. The same goes forPostComments
andPostReactions
2. Optimise DB and Hardware
Right off the bat, you need a DBA and SysOps person who you can call on to scale up your DB and VM/Hardware and stay ahead of your growth curve. You'll probably find that starts happening in say 2 years anyway. If it happens sooner, your business is doing great and you can now hire more programmers yay!
3. Logical Sharding
With posts, you have a natural shard topic - the post. You won't have PostComments that belong to two posts, they will have an affinity for the Post. You also have Geo affiliated data, so I am guessing that people close to those locations will want that data more - with Sharding you can master that data in a closer data center.
Create a "Management" database to hold a Shards table, as well as the DataWebGateways table. This will be a replicated database with one master, and each new shard will have a read-replica of this.
For each new shard:
Now, you can make the View_DataWebGateways view a bit smarter. Let the client get all of the records, so that it can randomly choose one to use, while pinging the others to see which is closest (by latency), then switch to that.
4. Staging Table
It's probably best that you just create another shard, but if you do testing, and find that batching greatly improves insert performance, then you can do the following:
WriteView_Posts
to point toPostStaging
instead ofPosts
table.PostStaging
table that optimise for Insert performance. This table can be configured to a dedicated Disk Volume that is also benchmarked to perform best for the simulated load (sequential reads).Now, if the power goes out, you don't have to lose your "cached" posts. This also helps because you can also redirect posts to the appropriate shard by geography at this point.
5. "High load" probably means Reads not writes
6. Curate feeds with FeedViews
Avoid caching at all costs - https://colossal.gitbook.io/microprocess/building/caching
If you would like to curate specific geographic feeds (eg. Germany, France, ...). While a geography shard server is great, Germans might want a mix of posts from around the world, while the French only want French posts - that's up to you to figure out.
To make this work:
View_CountryFeed
and use it likeselect * from View_CountryFeed order by post_id desc limit 10;
. This will only work on a single shard to begin with.When that is reaching its limits, improve your algorithm and also introduce manual materialisation with the following:
7. Realtime Notifications
Database Web Gateway will be able to help here to in the future. see https://colossal.gitbook.io/microprocess/database-system/feature-gaps. When the CountryFeed table is updated, a trigger will fire and notify the DWebG which will rerun subscribed Views and send new records to the subscribed web clients.