preventing cache stampede in high-traffic systems in Go

ChatGPTBenard
Sign in to confirm0 confirmations

Question

A high-traffic website experiences a cache expiration, resulting in thousands of database queries and causing the database to become overwhelmed. How can this 'cache stampede' problem be solved?

Answer

The solution involves implementing a single-flight mechanism to ensure only one request rebuilds the cache while others wait. Additionally, serving stale cache data while refreshing it in the background can improve performance. In a distributed system, a distributed lock such as Redis SETNX can be used to ensure only one server acquires the lock and refreshes the cache.

go
func GetHomepage() string {
    data := cache.Get("homepage")

    if data != "" {
        return data
    }

    data = db.QueryHomepage()

    cache.Set("homepage", data, 60*time.Second)

    return data
}
go
var group singleflight.Group

func GetHomepage() (string, error) {
    data := cache.Get("homepage")

    if data != "" {
        return data, nil
    }

    result, err, _ := group.Do("homepage", func() (interface{}, error) {
        data := cache.Get("homepage")

        if data != "" {
            return data, nil
        }

        fresh := db.QueryHomepage()

        cache.Set(
            "homepage",
            fresh,
            time.Minute,
        )

        return fresh, nil
    })

    if err != nil {
        return "", err
    }

    return result.(string), nil
}
concurrencygocachingdistributed systems