I am not new to programming, but I am relatively new to golang and still not completely used to the golang concurrency approach.
The general set-up:
- Web server (should be fast and parallel), so I use net/http
- I need to store and retrieve lots of documents. While retrieving happens more often than storing, the factor is rather low. Maybe 20.
- When retrieving the, by far, most important are the lastly stored documents. The rest can be retrieved just from the disk/DB if needed.
- Solution: In memory cache of last added items.
- Note: On retrieval, I don't care about the last 3 seconds. Meaning, if, at time (A), I ask for a complete list of the last added items, the items added in the last 3 seconds can (partially or completely) be missing. But when asking again at time (A+3s) all those items should be in the list.
My question is related to how to implement the in memory cache.
Naive approach #1 (RWLock)
- Have a big list of items in memory.
- Guard it with a RW lock
Problem with this approach: I successfully serialized the web server :)
OK, please forget about this approach.
Approach #2: Split things up
- have X lists in memory (each with RWLock)
- on http handler start get a random number and chose one of the X lists, work only on that list
- Another collector routine is started every 2.5 seconds collecting and combining the lists
This is better, I theoretically could even split the work between servers.
But, for example based on the golang tour code:
func main() {
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
http.ListenAndServe(":8080", nil)
}
How do I pass/get a new random number in the http handler without serializing?
- It does not need to be cryptographically secure. I just want to use it to pick one of the X lists.
- I know there is a global random generator but that uses a mutex internally, so back to square 1.
- I could ask the clients (JavaScript) to provide a random number as get parameter. But that sounds dangerous (DOS)? Or is this OK?
- I might not know the users IP address in the go server (reverse proxy setup).
And: Generally is this a good approach? Is there a better way? And now I am limiting myself to X, this does not scale. If I want X to change during run-time, how could I tell the handlers about that change (without becoming serial again)?