Memcached介绍
背景
在系统中,会有大量的比较耗时的重复计算,这会导致系统性能的急剧下降,为了解决该问题,我们希望将这些计算结果存下来,使得在一定时间内,直接获取结果就好。
缓存的两种基本形式
1、不精确,定时缓存 直接将结果,缓存到一定时间周期,过期则重新计算获取。 优点:实现简单、效率高 缺点:源数据如果在缓存有效期内有更改,可能出现数据取出来是错误的 适用场景:对数据精确性要求不高 常见情况:浏览器静态缓存、nginx缓存、cdn缓存、dns缓存等等 特殊说明:如果并发量很高,比如每秒几千次请求,在不要求精确缓存的情况下,可以主动更新缓存。因为过期到重新写入期间如果有数据库操作,会导致很卡。 Memcache缓存绝大多数都是这么使用
2、预先生成,精确缓存 当源数据有更改的时候,同时更改缓存中的数据 优点:数据精准 缺点:实现复杂,有些情况下甚至不可实现(与缓存本身违背,比如浏览器缓存) 适用场景:系统高度可控,并且对精度要求很高的情况 场景情况:mysql内部查询缓存、短链计算统计等 Memcache如果要使用这种的话,有一个比较简单的办法,在第一种做法的前提下,更新、删除等操作的时候,将相应的缓存删除,这样也能实现数据精确,而且实现简单。(不适用更新非常频繁的情况,否则缓存也白加了)
常见问题
1、不要存大key
场景: 比如我要缓存用户数据,有两种办法 一种是每一个用户一个key,里面对应的用户信息 还有一种,我把所有用户信息写到一个key里,这样我只要一个key,节省了内存空间。 问题: 不要出现一个key里,存很大的数据,缓存粒度控制 但第二种其实是一个非常糟糕的设计,假设我有10W个用户,每个用户信息1Kb,那么这个key就将有100Mb。因此我每个页面取一次缓存,将会导致需要每次从memcache里取100M的数据,10个并发,内网千兆带宽就崩掉了
2、不要缓存执行次数很少的
场景: 有个统计,每天统计一下前一天的数据信息,大概要执行1分钟,太慢了,我要优化它,所以把他扔缓存里 问题: 这种就是一个非常典型的失败例子,缓存的数据后面压根不会用到,所有缓存能起效的前提,都必须是这个请求会是重复多次执行的
3、缓存可能不到时间就会失效(LRU替换算法,不要做精准的统计计算等操作)
场景: 记录页面的访问次数(精确的),因为mysql写太频繁导致锁严重,因此我把计数放在memcache里,很快,读取这些数据的时候我也通过memcache读取,一切都很美好。 问题: 某天你会突然发现,这统计数据不对啊,为什么昨天这个页面明明已经有5000多次了,今天怎么变300多了?而且缓存也没有过期啊,什么情况? 因为Memcahe会有内部的删除数据算法,在空间不够的情况下,会删除某些不常用的数据 解决办法: 持久层还是放在MYSQL里去实现,但可以把写合并,比如累加次数达到一定值的时候重新写回mysql
4、Memcache不做持久化,服务重启,数据会全部丢失,启动的时候可能会导致数据库压力狂涨
如果项目很大的情况下,可能会出现挂掉之后数据库马上报警,又挂了 这个时候可以少量放开部分用户访问,然后慢慢加量,一般情况下不用管,直接硬抗几分钟就好了
5、命名
同一个系统里,不要出现两个同名的,会导致数据变的莫名其妙,统一管理 命名最好语意清晰,不会和别人写的导致重复 同一个Memcache的key管理,可以统一在一个文件里定义使用,防止因为key名重复导致逻辑出错
可视化 管理系统
MemAdmin:基于php和jquery开发,简单易用
Memcache本身的一些限制
1、最大过期时间30天(设置永久也无效) 2、最大键长128字节(不要取太长的,这个是会占内存空间的) 3、单个key的最大数据1M(一般不缓太大的数据,memcache的访问频率很高,如果单个key很大,带宽会非常高) 4、连接操作等无需验证,因此必须放在防火墙后面,只允许内网访问
Last updated