Memcache mutex设计模式[高并发解决方案]

1 篇文章 0 订阅
0 篇文章 0 订阅

场景

Mutex主要用于有大量并发访问并存在cache过期的场合,如

  • 首页top 10, 由数据库加载到memcache缓存n分钟
  • 微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
  • 需要执行多个IO操作生成的数据存在cache中, 比如查询db多次

问题

在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障

解决方法 

方法一

高并发时,增加data_lock信号标识,只充许一个用户update cache,在cache数据期间,其它并发用户等待,只到这个用户cache成功,当然这个地方需要设置最大等待时间,毕竟当很长时间cache不成功时,不能让用户一直等待:

function get_my_data2() {
        $cache_id = "mykey";
        $data = $memcache_obj->get($cache_id);
        if ( !$data ) {
            // check to see if someone has already set the lock
            $data_lock = $memcache_obj->get($cache_id . ‘_qry_lock’);
            if ( $data_lock ) {
                $lock_counter = 0;
                // loop until you find that the lock has been released.  that implies that the query has finished
                do while ( $data_lock ) {
                    // you may only want to wait for a specified period of time.
                    // one second is usually sufficient since your goal is to always have sub-second response time
                    // if you query takes more than 1 second, you should consider "warming" your cached data via a cron job
                    if ( $lock_counter > $max_time_to_wait ) {
                        $lock_failed = true;
                        break;
                    }
                    // you really want this to be a fraction of a second so the user waits as little as possible
                    // for the simplicity of example, I’m using the sleep function.
                    sleep(1);
                    $data_lock = $memcache_obj->get($cache_id . ‘_qry_lock’);
                }
                // if the loop is completed, that either means the user waited for too long
                // or that the lock has been removed.  try to get the cached data again; it should exist now
                $data = $memcache_obj->get($cache_id);
                if ( $data ) {
                    return $data;
                }
            }
            // set a lock for 2 seconds
            $memcache_obj->set($cache_id . ‘_qry_lock’, true, 2);
            $data = get_data_from_db_function();
            $memcache_obj->set($cache_id, $data, $sec_to_cache_for);
            // don’t forget to remove the lock
            $memcache_obj->delete($cache_id . ‘_qry_lock’);
        }
        return $data;
    }

方法二 

需要给数据增加一个cache过期时间标识,高并发时,在用户取数据时,检查cache是否快要过期,如果即将过期,则充许一个用户去更新cache,其它用户依然访问没有update的数据。


function get_my_data3() {
        $cache_id = "mykey";
        $data = $memcache_obj->get($cache_id);
        // if there is cached data and the expire timestamp has already expired or is within the next 2 minutes
        // then we want the user to freshen up the cached data
        if ( $data && ($data[‘cache_expires_timestamp’] – time()) < 120 ) {
            // if the semaphore lock has already been set, just return the data like you normally would.
            if ( $memcache_obj->get($cache_id . ‘_expire_lock’) ) {
                return $data;
            }
            // now we want to set the lock and have the user freshen the data.
            $memcache_obj->set($cache_id . ‘_expire_lock’, true, 2);
            // by unsetting the data it will cause the data gather logic below to execute.
            unset($data);
        }
        if ( !$data ) {
            // be sure to include all of the semaphore logic from example 2
            // set the _qry_lock for 2 seconds
            $memcache_obj->set($cache_id . ‘_qry_lock’, true, 2);
            $raw_data = get_data_from_db_function();
            $data[‘cache_expires_timestamp’] = time() + $sec_to_cache_for;
            $data[‘cached_data’] = $raw_data;
            $memcache_obj->set($cache_id, $data, $sec_to_cache_for);
            // remove the _qry_lock
            $memcache_obj->delete($cache_id . ‘_qry_lock’);
            // remove the _expires_lock
            $memcache_obj->delete($cache_id . ‘_expires_lock’);
        }
        return $data;
    }

更多资料:

Memcached FAQ中也有详细介绍 How to prevent clobbering updates, stampeding requests
http://www.grepmymind.com/2008/01/11/memcached-php-semaphore-cache-expiration-handling/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Memcache是一个快速、高效的分布式内存对象缓存系统,常用于提高网站性能和减轻数据库负载。要安装Memcache,需要进行以下步骤: 1. 下载安装包:首先需要下载Memcache的安装包。可以在官方网站上找到最新的稳定版本,并选择与操作系统和服务器兼容的安装包。 2. 解压安装包:下载完成后,将安装包解压到任意目录。解压后的文件夹中应该包含了安装所需的文件和脚本。 3. 安装依赖库:在安装Memcache之前,需要确保系统中已经安装了相应的依赖库。常见的依赖库有libevent和libevent-devel,可以通过包管理器安装,如yum或apt-get。 4. 编译和安装:进入解压后的Memcache文件夹,在命令行中执行编译和安装命令。通常是执行./configure,然后执行make和make install命令。这些命令会编译和安装Memcache到系统中。 5. 配置和启动:安装完成后,需要进行一些配置和启动操作。可以编辑配置文件,设置Memcache的监听地址、端口号和缓存大小等参数。然后,启动Memcache服务,可以通过执行memcached命令或使用脚本启动。 6. 测试和验证:安装完成并启动Memcache后,可以进行一些简单的测试和验证工作。可以使用telnet或memcached客户端工具连接到Memcache服务器,并进行一些数据操作,如set、get等。 总结: Memcache的安装包实际上是一个压缩文件,包含了安装所需的文件和脚本。安装Memcache之前,需要确保系统已经安装了相应的依赖库。安装过程包括解压安装包、安装依赖库、编译和安装、配置和启动、测试和验证等步骤。安装完成后,可以使用telnet或memcached客户端工具连接到Memcache服务器,并进行数据操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值