## 背景
在系统中，会有大量的比较耗时的重复计算，这会导致系统性能的急剧下降，为了解决该问题，我们希望将这些计算结果存下来，使得在一定时间内，直接获取结果就好。

## 缓存的两种基本形式
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、连接操作等无需验证，因此必须放在防火墙后面，只允许内网访问