一、Null对象的处理
1.数据为空,是程序编写造成的。 避免直接使用try,catch,然后直接就返回null,或者一个空的集合。要定义完善的异常处理机制。
2.数据库返回空 缓存NullObject对象,设置比较短的超时时间(一般60s)。可以有效的避免缓存击穿(指查询一个根本不存在的数据,缓存和数据库都不会命中,压力全部打到数据库的现象)
二、尽量保证一份数据只缓存一份
尽量保证一份数据只缓存一份,而不是同一个数据缓存多个key,容易造成数据不一致 举例:有2个查询方法findByName(String name),findById(String uid)。还有一个更新的方法updateById(String name)。如果用户调用更新方法把缓存里面的对象修改了, 那么调用方findByName还是原来旧数据,出现了数据不一致。 解决方案: 修改findByName(String name)方法,返回uid,而不是对象。这样更新updateById的时候多查询一次,先findByName返回id,在用id调用findById方法返回对象。数据更新时, 就不需要再关心其它数据也要同步更新的问题了,更好地保证了数据的一致性。
三、缓存时间
命中率比较高的key,设置长一点的缓存时间,命中率比较低设置短一点的缓存时间。如:热门商品可以设置长一点时间,同时针对不同的热门商品设置不同的过期时间,防止大量 的热门key同一时间失效,请求都穿透到后台,出现致命的缓存雪崩效应。
四、预热
对于访问量高的缓存数据,需要先预热(从数据库load数据到缓存)
五、缓存使用场景
主要是缓存对象列表以及单个对象信息,如果有涉及到页面片段也可以临时存放到缓存中。
六、不能把缓存当作传参的工具
例如把全部数据字典存放到缓存中,前端直接调用缓存。应该避免这样使用缓存。 h)避免缓存出现大key。包含2个方面,单个简单string结构中存储的key的value很大,或者hash, set,zset,list结构中存储过多的元素(以万为单位)。大key会导致超时严重,甚至阻塞服务。建议每个key不要超过M级别。
1.针对单key值过大
可以分拆成几个key-value。也可以放到hash中,每个field代表一个属性,使用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性 。
2.针对hash、set、zset、list等结构中存储的元素过多
可以尝试将对象分拆成几个key-value,可以对field进行hash并通过质数N取余,将余数加到key上面。这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响;