转载:http://blog.51yip.com/php/729.html
一,在说出我的困惑时,先罗嗦一下memcache
memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,最初为了加速 LiveJournal 访问速度而开发的,后来被很多大型的网站采用。目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的压力。起初作者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一种分布式的,也就是可以允许不同主机上的多个用户同时访问这个缓存系统, 这种方法不仅解决了共享内存只能是单机的弊端,同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcache作者对分布式 cache的理解和解决方案。 memcache完全可以用到其他地方 比如分布式数据库, 分布式计算等领域。
二,memcahce的key如何关理,更合适
大家都知道,memcache缓存的数据放在内存中,用的key=>value的方式,来查找和更新value的值,从这里可以看出对于key的管理直接影响到value的值,影响到内存的利用率和效率,以及程序员写代码的难度,怎么样才做到最优化呢,这也是我一直思考的问题,我想了二种方案,但是觉得都不完美。先说一说我的方案吧
1,对单表进行缓存
优点:
a,对于key的维护很简单
key对应一张表的数据,所以key是根这张表有关的sql或者其他。如果是我,我会用取整表的sql语句经过hash后来当key。注意一点hash过程中,如果sql有一点点不同,hash出来就会不同,包括空格,字母大小字等。所以建议将sql建行封装。
b,就同一张表来说,内存中不会有重复数据
缺点:
a,加大程度开发难度
举个例子来说,如果我想对二张表或者更多表,进行联合查寻时,正常情况,我可以用left join或者其他来进行查寻就行了,也许一个sql语句就能搞定,但是现在对单表进行缓存时,就要把单表的数据取出来,用php的循环进行查找数据了。这样对于程序员来说是一件很痛苦的事。
b,加大系统负担,影响memcache效果
这个缺点很明显,因为多表操作时,用php的循环套循环,会加大系统负担,如果一张表有几百M, 另一张表也有几十M,你用php循环来把你想要的数据找到时,所花的时间也许比直接用联合查寻访问数据库所用的时间更长,这样我就没必要用memcache,这个也是致命缺点。
个人觉得这种对key进行管理的方式,比较适合写入,或者更新操作比较多的网页,因为对于key的update很容易,key根表名是一一对应关系,这样找起来就容易多了。
2,对数据段,数据点进行缓存
优点:
a,查找效率高
我想memcache设计的目的也就是这个了,通过key找到value,就是我们所要的数据,不要进行任何处理。不要对数据库进行操作,不要用php循环来取数据,可以说省了很多事情。
b,开发效率高
对于程序员来说,以前是怎么开发现在还怎么开发,就当memcache不存在就行了。
缺点:
a,内存利用率差
举个例子来说吧,数据段A和数据B有重复数据,内存中的二个数据段都会包括相同的数据,这对内存利用率来说是不好的。如果你的memcach所占内存是1G的话,并且你用这种方法来进行key的管理的话,1G内存中重复数据有可能占了一半。
b ,key的管理难
为什么对key的管理难呢,因为key受很多因素的影响。不像上面的那种方法,key和表名是一对一关系。在这里,key受表名,可能是多个表名,where后面所带的参数所影响,所以管理起来相当的不方便。当你更新一个数据时,入库的同时,key对应的value就要相应的改动,不然用户会认为网站有bug。根这张表有关系的key很多,很有可能你就没有把所有key对应的value都更新掉
个人觉得这种对key的管理方式比较适合,读取比较多的,写入比较少的网站,如果经常写入的话,更新key所耗的资源也很大,不如用上面的那一种对key的管理方式。
如果读取比较大,写入也比较频繁呢,怎么办呢,个人觉得这二种方法都不合适,如果非要做个选择的话,我会选择第二种,有没有别的方法来,综合上面二种方法的优点,去除上面二种方法的缺点的方法呢。思考中
===============================================================================================================
====================================================================================
http://blog.csdn.net/chuan122345/article/details/5134509
Memcached的批量删除,向来是Memcached使用者很头疼的事情,因为Memcached采取的缓存方案是哈希表结构,所以没有办法实现delete from tablename where key like ‘%XX%’类似这样的批量删除功能。所以不得不自己采取一些策略实现批量删除。常见的删除方案主要有以下两种:
第一种方案:通过记录KEY到DB然后循环删除。
其实这也是最常规的删除方法,最容易想到,可能大部分人首先都会这么考虑。具体方法如下:
1. 添加业务数据时,在向Memcached缓存set数据的时候,将其key记录到数据库(或内存中,或文件中,由于数据量大,内存中基本不可行),也就是每set一条数据到Memcached缓存中,就向记录key的数据表(这类专门用于辅助删除缓存的表可以按业务分类建表,为了方便,我们下文简称keytable,因为不可能所有的key都用一张表,即使按业务分类建,数据量也是很庞大的)insert一条记录。数据表结构可以设计为这两个字段:key(对应缓存key), id(对应业务实体id),这里的存储id主要是方便批量查询出需要从缓存删除的KEY时方便,也可以根据实际业务设计。
2. 删除业务数据时,首先从数据库的业务数据表删除数据,然后从keytable 中查询出keyList.查询语句类似,select key from keytable where 条件 ,再然后循环keyList从Memcached缓存中remove掉相应的记录,最后删除keytable表中相应的记录,删除语句类似delete key from keytable where 条件.
这种方法的优点:方案设计思路简单,符合常规思维,而且能达到精确删除的目的。
这种方法的缺点:删除代价比较高,需要数据库或其他存储介质辅助,而且实际应用中,缓存量是很大的,会导致大量频繁的对keytable表的insert操作,性能问题将会很严重,需要根据具体情况运用。
第二种方案:利用Memcached的LRU算法进行懒清理
这种方案主要是利用Memcached缓存根据LRU算法进行定期自动清理不用或少用的缓存,通过对key增加版本管理来实现。
该方案的具体方法如下(拿商品数据举例说明):
1. 对缓存中的每个key进行版本管理,比如缓存商品数据的key为product_10001.0,这里的product表示商品这类业务数据,product_10001表示具体的商品对象10001,0表示版本号。
2. 在Memcached中维护一版本记录数据,这个很简单,比如整个系统只有商品,订单,用户这三类缓存数据,则在Memcached中只维护三个key,类似product_version,book_version,user_version.他们的取值范围为0-99之间循环,之所有循环是防止数据版本多了无限增大,管理麻烦,而且数字大了占用空间大(要对应到每个key的值)。
3. 删除商品数据时,首先从数据库删除对应商品数据的记录。然后更新对应商品的版本:product_version = product_version+1(记得当product_version=99时,product_version=0)。
4. 从Memcached中get数据时,需要get两次,首次按get对应业务数据的版本号,如product_version,然后根据数据本身的key+ 最新的product_version作为真正的key去取数据。这样删除了的数据自动为过期数据,Memcached会根据LRU算法清理。
5. 向Memcached中set数据时,也是先取最新的product_version,然后将数据本身的key+product_version作为key保存数据到缓存。
这种方案的优点:减少了批量删除从Memcached真正删除数据的麻烦。利用Memcached自身的特点解决删除问题,符合Memcached的设计思想。
这种方案的缺点:a.每次set数据都要,先get版本,然后set,性能上差不多降低了1倍,虽然性能方面还是不错。不过这个问题好像没有办法解决,原先考虑在客户端缓存版本,因为版本毕竟不是时时都变,但是考虑到版本数据时多进程间共享数据,所以不能这样做,每次必须从Memcached中取版本。否则难以保证是最新的。b.这种方案对内存上有点浪费,虽然Memcached会根据LRU算法清理低版本的垃圾数据,但是毕竟不是实时清理,所以必然浪费内存,所以内存不足的情况下,要仔细考虑采取此方案。