Dogpile效应以及solution

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tt50335971/article/details/51707672

Redis/Memcached高并发访问下的缓存失效时可能产生Dogpile效应(Cache Stampede效应)。看代码:

# redis read-through cache
conn = redis.Redis()
data = conn.get('cachekey')
if not data:
    # long-running process
    data = generateData()
    conn.setex('cachekey', data, 10)


Dogpile 产生情况:

generateData()是耗时的运算过程或者复杂的数据库操作。当缓存失效或者redis-server不可用(服务器宕机/网络原因),此时恰好有大量的请求涌入,会直接穿透cache层从而导致CPU使用率或者数据库操作数短时间急剧攀升,可能会引发数据库/web服务器故障。

Solution:

1.      使用独立的进程\线程更新cache

实践:web应用中启动调度线程;单独进程Job(spring-boot)

// every ten seconds
@Scheduled(cron = "*/10 * * * * *")

现在我们的应用就是基于这样的方案,可靠,经历618考验^_^。

2.      使用”锁”

实践:cache失效,单一请求,其余等待;单一请求cache失效前更新

# redis read-through cache
conn = redis.Redis()

def get(key):
    data = conn.get(key)
    if data:
        return data
    # try lock
    if conn.setnx('lock:' + key, 'locked'):
        # long-running process
        data = generateData()
        conn.setex(key, data, 10)
        conn.delete('lock:' + key)
        return data
    else:
        # 'waiting & try get'
        loop = 10
        while loop > 0:
            time.sleep(0.1)
            data = conn.get(key)
            if data:
                print 'found'
                return data
            loop -= 1
        return None
或者是

# redis read-through cache
conn = redis.Redis()

def get(key):
    recache = 2
    data = conn.get(key)
    ttl = conn.ttl(key)

    if ttl < recache and conn.setnx('lock:' + key, 'locked'):
        print 'recache'
        # long-running process
        data = generateData()
        conn.setex(key, data, 10)
        conn.delete('lock:' + key)
    # normal return
    return data

这两者各有优势,看具体业务选取。我们应用涉及到实时或者重定向的功能采用的是第一种锁。

另外:按照具体的使用确定是否要对锁的冲突和异常进行特殊处理,代码中没有实现。

参考(力荐):http://www.linuxidc.com/Linux/2013-07/86960.htm (关于这次项目的实践,上线后才看到这篇文章,相见恨晚。本文只做实践,详解看这篇推荐。)

618值班顺利




阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页