Redis

182 阅读5分钟

版本升级

  • 3.0开始支持cluster集群模式;
  • 4.0开发的lazyfree和PSYNC2解决了Redis长久的大key删除阻塞问题(详见lazyfree)及同步中断无法续传的问题;
  • 5.0新增了stream数据结构使Redis具备功能完整的轻量级消息队列能力;
  • 6.0更是发布了诸多企业级特性如threaded-io、TLS和ACL等,大幅提升了Redis的性能和安全性。

Value类型

我们都知道 Redis 提供了丰富的数据类型,常见的有五种:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)

随着 Redis 版本的更新,后面又支持了四种数据类型: BitMap(2.2 版新增)、HyperLogLog(2.8 版新增)、GEO(3.2 版新增)、Stream(5.0 版新增)

Redis集群部署模式

  1. 主从模式
  2. 哨兵模式: 一主多从+多个哨兵 关键配置项:slaveof主redis的ip,readonly从redis设置,主从切换需要n个哨兵认为master失效(客观下线),然后进行主从切换(选出领头哨兵;通过优先级、同步偏移量、run id选出主数据库A;升级A为主数据库,并通知其他哨兵更新主数据库。)
  3. 分布式存储
  • Redis Cluster模式 采用hash slot分片(16384个slot,每个Key通过CRC16校验后对16384取模),P2P模式(至少3个节点,推荐3主3从),完全去中心化
  • 豌豆荚的Codis(与Redis Cluster模式类似)
  • Twitter的Twemproxy
  • 客户端分片(不易维护)

详解参见

Redis事务和lua脚本

严格意义上讲Redis是没有事务的

要解决的问题

缓存穿透

数据不存在

数据不存在,无法缓存到Redis(可能是黑客攻击),一直访问数据库,造成数据库负载过高。 解决办法:

正常访问

  1. 对空值给null缓存,设置短过期时间(一般不超过5分钟)

网络攻击

  1. 设置白名单:使用bitmaps包含正常的用户id,非正常用户id则过滤
  2. 布隆过滤器:类似白名单,效率更高,但命中率不准确
  3. 实时监控:找到命中率特别低的ip,设置黑名单过滤

缓存击穿

数据存在,但因缓存过程比较长,缓存过期后,刚好有大量访问,此时都访问不到缓存,出现大量访问都去数据库取数据,造成数据库负载过高。

防止大量Key同时过期

  1. 根据热度动态调整过期时间
  2. 分页缓存减少加载时间(一般用户不会一直翻页)
  3. 爬虫搞鬼:识别爬虫禁止(会影响SEO和推广)或监控应对

防止热数据突然大量访问

  1. 热数据提前加载,增加过期时长
  2. 使用分布式锁,同一时间只有 1 个请求可以访问到数据库:第1个检测到值没有缓存的加锁,其他请求检测到锁后等待一段时间后重复调用。

缓存雪崩

  1. 使用分布式锁(可能不适合高并发)
  2. 后台更新:将无缓存数据的缓存过程变为消息通知的形式,后台在缓存前对重复缓存进行过滤
  3. 在缓存过期前,异步触发主动更新缓存
  4. 设置随机失效时间,避免大量key在同一时间失效
  5. 多级缓存(缺点比较大)

缓存热点

明星微博可能某天短时间上千万用户访问,可缓存多份,通过在key里加上分区号,将用户进行分区访问某一份缓存。

锁的误释放

设置锁时加了超时自动解锁,等程序反应过来后可能会解了别人的锁(锁的key相同) 解决办法: set lockkey server-uuid nx ex 10 程序先检测锁是自己的uuid,再解锁。这里存在操作原子性问题,所以应改成在redis的lua脚本中检测+删除。

其他问题

其他问题

持久化

redis本身就是缓存,一般不需要完全的持久化,即使丢一部分数据,通过mysql读过来也没有太大问题,所以一般AOF的appendfsync选择everysec或no(no依赖系统策略,可能是30秒)

类型优点缺点
RDB磁盘占用小,恢复速度快最后一段时间的数据可能丢失
AOF磁盘占用大,恢复速度慢数据不丢(appendfsync 3种模式:everysec,always,no)
RDB-AOF混合(v4.0开始)恢复速度比RDB稍慢,但有限数据不丢

Value类型

下面内容细节可参考

类型操作特殊操作使用场景
Stringset、get、exists、strlen、del、mset(批量设置)、incr、decr、incrby(增加指定值)expire、ttl、setex(同时设置值和过期时间)、setnx(不存在就插入)缓存对象(整个和分离2种)、常规计数、分布式锁(使用setnx加锁、lua解锁)、共享Session信息(支持42亿条)
List(双链)lpush/rpush/lpop/rpop/lrangeblpop/brpop消息队列,但有严重缺陷
Hash(KV集合)hset/hget/hmset/hmget/hdel/hlen/hgetall/hincrby---缓存对象、购物车
Set(无序并唯一的KV集合)sadd/srem(删除)/smenbers(获取整个集合)/scard(获取集合元素个数)/sismenber(元素是否存在集合中)/srandmenber(从集合中随机选出n个元素)/spopsinter(交集)/sinterstore(交集并存到新集合中)/sunion/sunionstore/sdiff/sdiffstore可存42亿条、点赞、共同关注、抽奖活动
Zset---排行榜、电话姓名排序
GEOGEOPOS(从给定的key里返回所有指定名称的位置)/GEODIST(返回两个给定位置之间的距离)/GEORADIUS(根据给定坐标获取指定范围的地理位置集合)---查找附近的地理位置
BigMap------统计签到、判断用户登录态(5kw用户只需要6M)、连续签到用户数
HyperLogLog------百万级网页UV计数(误差标准差是0.81%)
Stream------同一消息可以被多个组消费。缺点:1、但持久化和主从复制都是异步的可能会丢数据 2、因Redis使用的是内存,消息堆积量有限