题外话
最近计划对Memcached做一些尝试性的改造,主要是针对Memcached在处理过期数据的时候进行改造,以实现在一个缓存的过期时间达到的时候,可以对该缓存的数据进行一个验证和存储的处理。

这个需求,主要是为了解决MySQL的写入瓶颈,通过延期、合并写入请求来减少MySQL的并发写入量。现在逐渐记录出来和有需要的朋友一起讨论。当然,今天的主要内容是关于LRU的部分。

LRU算法
LRU是Least Recently Used最近最少使用算法。源于操作系统使用的一种算法,对于在内存中但最近又不用的数据块叫做LRU,操作系统会将那些属于LRU的数据移出内存,从而腾出空间来加载另外的数据。

我们来看Memcached(版本 1.4.9)的相关代码:

/* expires items that are more recent than the oldest_live setting. */
void do_item_flush_expired(void) {
    int i;
    item *iter, *next;
  if (settings.oldest_live == 0)
  return;
    for (i = 0; i < LARGEST_ID; i++) {
  /* The LRU is sorted in decreasing time order, and an item's timestamp
         * is never newer than its last access time, so we only need to walk
  * back until we hit an item older than the oldest_live time.
         * The oldest_live checking will auto-expire the remaining items.
  */
        for (iter = heads[i]; iter != NULL; iter = next) {
  if (iter->time >= settings.oldest_live) {
  next = iter->next;
  if ((iter->it_flags & ITEM_SLABBED) == 0) {
  do_item_unlink(iter);
                }
            } else {
  /* We've hit the first old item. Continue to the next queue. */
                break;
  }  
        }  
    }
}

属于LRU的item是被时间逆序排序了,一个item的失效时间应该是永远比它自身上次被访问的时间大。所以在找到一个item的失效时间比oldest_live这个时间小之前,我们只需要把已经逆序排序的item继续往结尾遍历即可,一旦找到这个item,其他剩余的item也就可以判定为过期了。

如何改动?
我们的思路是让Memcached来作为MySQL的中间承接方,其实LRU算法并不是最适合。列举两种方案:

  1. 继续采用LRU算法,我们需要对Memcached进行改造的是do_item_flush_expired这个函数的执行频度,同时改造do_item_unlink函数来适应需求。
  2. 改用FIFO(先入先出)算法,彻底放弃Memcachd的整个过期处理机制或者另外添加一个FIFO算法序列,来专门为我们的业务需要服务。

为什么写这篇文章?
想写出来和大家一起讨论,看有没有其他的一些更好的用来解决MySQL写入并发的方案。

Tags: MySQL效率, 算法

版权声明:原创作品,欢迎转载,转载时请务必以超链接形式标明文章原始地址、作者信息和本声明。


已有 15 条评论 »

  1. ElmerZhang
    2011-10-26 at 16:12:07

    你的意思是要改造Memcache,当其中某个数据过期被删除前,先将它存入Mysql?
    这样不太好吧。Memcache本身就是一个高速缓存,把他和Mysql绑起来,难免会有问题。假如Memcache满了,然后有大量新数据涌进来,那么Memcache中过期数据往Mysql中转存这一步就有可能会是一个瓶颈,旧数据被清掉的太慢,新数据保存失败。
    我觉得还是单独写个脚本定时将MC中的数据转存入Mysql比较好。
    另外Memcache也可以考虑换成Redis,Redis可以做执久化和replication,防止进程重启或者突然挂掉导致数据丢失。

    1. kimi
      2011-10-26 at 16:57:41

      怪我没说清楚,比如我们的业务模型就是社交游戏,社交游戏的用户特点,就是上线之后开始游戏,操作时候十分钟之内关闭游戏下线。我们先定义PHP和MySQL之间有个中间件叫Mcache

      在这个过程中,比如用户刚上线

      SELECT money,exp FROM user WHERE uid = ‘1’;

      于是PHP把这个query通过PHP扩展发给了Mcache,Mcache接到这个query,发现没有数据,于是就向MySQL查到数据存下来再返回给PHP;
      几分钟之后,又来了一个操作,加了4个金币

      UPDATE  user SET money=money+4 WHERE uid = ‘1’;

      这时候,Mcache接到这个query,发现已经有数据了,就直接在Mcache中对这个数据修改;
      几分钟之后,又来了一个操作,加了10个金币 5点经验

      UPDATE  user SET money=money+4, exp=exp+5 WHERE uid = ‘1’;

      这时候,Mcache接到这个query,发现已经有数据了,就直接在Mcache中对这个数据修改;
      又来了一个操作,请求用户当前的金币和经验

      SELECT money,exp FROM user WHERE uid = ‘1’;

      这时候,Mcache直接就把最新的query发给PHP去了。

      当30分钟之后,Mcache自动将这条记录update给MySQL。

      这样能减少对MySQL的写入并发,之所以不用NOSQL的方案,是目前NOSQL的方案无法解决回档的问题。而MySQL在热备、增量备份方面的优势是NOSQL方案无法比拟的。你说呢?

      1. ElmerZhang
        2011-10-26 at 17:34:40

        明白了。那么将数据读到缓存,更新缓存,将缓存数据持久化到Mysql,都应该是Mcache这个中间件做的事情,而不是Memcached做的,所以只要把这个中间件做好就OK了呀。
        我提到Redis的意思是让它替代Memcache做缓存,而不是做持久化存储。
        关键数据确实仍然应该用Mysql存储,NoSQL在数据备份、恢复等方面比Mysql还差点。

        1. kimi
          2011-10-26 at 19:15:33

          确实,关键性的数据还是得用MySQL存储。为了避免制造重复车轮,计划是在Memcached代码上去做Mcache这个东西。然后开源发出来。有木有兴趣的说~

          回复
        回复
      2. kaka
        2011-10-26 at 23:18:36

        思路确实不错,“写”也可以放内存中执行了。。。

        不过如何应对灾难情况呢?比如:

        “当30分钟之后,Mcache自动将这条记录update给MySQL” ---

        这半小时内,会用内存来存一些金币或经验的操作数据,如果出现了XXX问题造成了机器重启,内存数据丢失又如何应对呢?

        1. kimi
          2011-10-27 at 09:35:25

          在这种情况下每个用户会最多丢失半个小时的数据。任何不在计划内的机器重启对MySQL都有可能造成致命性的损害。当然这种不在计划内的机器重启对Mcache也会造成致命性的损害(丢失半个小时的数据)。

          1. kaka
            2011-10-27 at 18:23:42

            任何不在计划内的机器重启是可能会造成致命伤害,不过如果是从怎样把这种伤害降到最小的角度来讨论呢??

            比如,若用redis是不是出现XXX情况会好一些?

            redis也是基于内存存储的,不过同时具有以下特点:

            1、redis具有持久化机制,可以定期将内存中的数据持久化到硬盘上。

            2、redis具备binlog功能,可以将所有操作写入日志,当redis出现故障,可依照binlog进行数据恢复。

            1. kimi
              2011-10-27 at 18:41:09

              说的有道理,主要是我之前读过Memcached的代码,所以就直接想到用Memcached了。利用Memcached处理过期数据的时候将数据写入MySQL中去。

              我来研究下Redis的代码,看什么时候做这个写入MySQL的操作比较合适。

            2. kaka
              2011-10-27 at 22:49:30

              redis这2年很火的,sina微博就是用的redis。。

              不过我的项目没达到那个量级,所以只是看过一些资料,没有实践经验。。希望以后可以看到kimi兄的分享哦~~~ :)

            3. kimi
              2011-10-28 at 16:22:00

              之前公司有研究过redis,主要是当时redis需要内存完全大于数据,否则会有性能问题,持久化的特点数据亦不会自动过期,所以就没过多关注,在这点上,Membase就完全超过redis。

            4. kaka
              2011-10-30 at 00:14:38

              Membase 能搜到的资料还是比较少的,在你的一篇blog上看到过介绍,貌似优点很多。。。

              想请教下kimi兄在生产环境实践中,有无遇到什么问题或者瓶颈??如果现在一个项目想选择nosql的缓存方案,

              是否是首推Membase??

            5. kimi
              2011-10-30 at 18:17:06

              看数据量吧,目前是各有优缺点,我们是在生产环境采用的Membase,放弃Tokyotyrant、Redis也是有原因的,推荐采用Membase,但是Membase的资料却是太少了。

            6. tcl
              2011-11-20 at 01:19:25

              1.个人觉得哪有完美的方案,没有。都是看实际需求,可以不可以满足。出现错误情况能不能忍受,能忍受到什么程度的错误
              2.当时做游戏的时候也是将数据写到memcached,然后后台有个程序定时的从memcached中取数据,写到mysql,往memcached中的写数据的时候设置永不过期,后台程序取走数据,写到mysql的时候再设置memcached中数据过期。但是数据都放到了memcached中了。万一memcached挂了,就歇菜了。这块是不是写的时候写到两个memcached中,还是说写到一个memcached集群里面。

            回复
          回复
        回复
      回复
    回复
  2. sogo
    2012-01-30 at 11:55:10

    cache 除了解决高并发方面的问题,想请教一下,读cache 与读取mysql 的时间上面,那个更快,如果评测?

    回复
  3. freeacger
    2012-03-30 at 19:17:12

    博主.你的代码插件用的是啥,能否告知?

Memcached的LRU算法相关推荐

  1. Redis的LRU算法

    2019独角兽企业重金招聘Python工程师标准>>> 整理自官方文档:将redis当做使用LRU算法的缓存来使用 当Redis被当做缓存来使用,当你新增数据时,让它自动地回收旧数据 ...

  2. 将redis当做使用LRU算法的缓存来使用

    当Redis被当做缓存来使用,当你新增数据时,让它自动地回收旧数据是件很方便的事情.这个行为在开发者社区非常有名,因为它是流行的memcached系统的默认行为. LRU是Redis唯一支持的回收方法 ...

  3. Memcached的LRU策略

    前言 从 Memcached1.5 开始,实现了一个改良的 LRU 算法,也叫做分段 LRU(Segmented LRU)算法,新算法主要是为了更好的利用内存,并提升性能.包含了二个重要的线程:mai ...

  4. LRU算法 -- 链表 完整实现

    LRU算法(Least Recently Used) 算是我们经常遇到的一种淘汰算法,其中内存管理模块进行内存页回收时有用到,针对不经常使用的内存页,LRU淘汰策略能够将该内存页回收给操作系统. 属于 ...

  5. 漫画:什么是LRU算法?

    本期封面作者:A17 -----  两个月前  ----- 用户信息当然是存在数据库里.但是由于我们对用户系统的性能要求比较高,显然不能每一次请求都去查询数据库. 所以,小灰在内存中创建了一个哈希表作 ...

  6. 【腾讯三面】你能现场写一下LRU算法吗?

    " 金三银四,又到了换工作的黄金期.各位小伙伴们都准备好了吗? " 这句话大家是不是最近已经要看吐了呢? 每当这个时候,就证明招聘旺季又来啦~ 春招.校招.社招-- 那你真的准备好 ...

  7. LRU算法确定最后使用时间的顺序

    LRU算法是经常采用的页面置换算法,并被认为是相当好的,但是存在如何实现它的问题.LRU算法需要实际硬件的支持.其问题是怎么确定最后使用时间的顺序,对此有两种可行的办法: 1.计数器. 2.栈.

  8. java 最少使用(lru)置换算法_「面试」LRU了解么?看看LinkedHashMap如何实现LRU算法...

    以下内容均是本人原创,希望你看完之后能有更多更深入的了解,欢迎关注➕ 问题:使用Java完成一个简单的LRU算法 什么是LRU算法 LRU(Least Recently Used),也就是最近最少使用 ...

  9. Android图片缓存之Lru算法

    前言: 上篇我们总结了Bitmap的处理,同时对比了各种处理的效率以及对内存占用大小.我们得知一个应用如果使用大量图片就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发 ...

最新文章

  1. opencv-python图像处理之让你的照片变旧
  2. java生成excel_java生成excel并下载功能
  3. 常见 Serverless 架构模式
  4. RocketMQ-什么是死信队列?怎么解决
  5. 进程有一个全局变量 i,还有有两个线程。i++ 在两个线程里边分别执行 100 次,能得到的最大值和最小值分别是多少?
  6. 牛逼!不得不服,第一次有人把Java 反射机制讲解这么透!
  7. 【Floyed】【匈牙利算法】导弹(jzoj 1610)
  8. CleanMyMac for mac之偏好设置
  9. CASE WHEN语句中加IN应该如何使用
  10. 最简单爬虫rvest_告别复制粘贴
  11. 求n!的位数以及求n!具体的值(C or C++)
  12. Spket,eclipse下安装Spket插件,格式化js
  13. 【Unity3D】计算二维向量夹角(-180到180)
  14. Git正解 脱水版 【7. Git命令】
  15. 机房服务器巡视项目,年底,机房巡检不能少
  16. 使用安全浏览器将网页保存为pdf的方法步骤
  17. win10 uwp 相机的分辨率设置方法
  18. 计算机专业个税,税后工资个税计算器
  19. mysql过载保护_腾讯后台开发技术总监浅谈过载保护 小心雪崩效应
  20. 音质好的蓝牙耳机有哪些?音质好的蓝牙耳机推荐

热门文章

  1. 论文中可以让代码变得非常好看的工具
  2. C/C++面试题-2 之2/2
  3. Android “adb”不是内部或外部命令,也不是可运行的程序或批处理文件
  4. illustrator cs5 for mac 官方简体中文版 破解
  5. 怎样两个网络互远程连接计算机,两个电脑怎么远程控制两个方法教你
  6. iOS 自定义导航栏 NavigationBar
  7. 爬虫抓取某饿了app商铺的评论数据
  8. 你真的了解getline()的返回值吗?—— basic_istream::getline() 与 string::getline
  9. 前端、后台、客户端以及服务器
  10. 高端大气的艺术海报的ps教程