Redis

Redis

Scroll Down
  1. 什么是Redis

    • Redis是一个由C语言开发的的高性能数据库,采用键值对形式存储的内存数据库,可以作为数据库、缓存、消息中间件等来使用。
    • 是一种NoSQL(not-only sql)非关系型数据库
    • Redis作为一个内存型数据库,性能十分优秀。数据存储在内存中,读写速度非常快,支持高并发。官方数据表示Redis读的速度是110000次/s,写的速度是81000次/s 。单进程单线程,是线程安全的,采用I/O多路复用机制。同时支持多种数据类型,字符串(string)、散列(hash)、链表(list)、集合(set)、有序集合(zset)。
    • 同时支持数据的持久化,可以将内存中的数据保存在磁盘中,重启时进行加载。
    • 高可用,有主从复制、哨兵模式。
    • 可以用作分布式锁。
    • 可以作为消息中间件使用,支持发布订阅。
  2. Redis支持的五种数据类型

    • String ,字符串。是redis最基本的类型,一个key对应一个value。是二进制安全的。最大储存为512MB。value不光可以储存字符串,也可以是数字。
    • Hash ,是一个键值(kay-value)的集合。Redis的hash是一个String的key和value的映射表,Hash特别适合储存对象。常用的命令:hget、hset、hgetll等。
    • List ,是简单的字符串链表。按照插入顺序排序。可以添加一个元素到链表头部(左边),或者尾部(右边)。常用命令:lpush、rpush、lpop、rpop、lrange(获取指定区间的数据)等。
      应用场景:List的应用场景非常多,可以用来做消息队列使用。Redis提供了List和push和pop操作,还提供了操作某一段的API,可以直接查询或删除某一段的元素。
      实现方式:Redis List的实现是一个双向链表,可以支持方向查询和便利,更方便操作,不过来带了额外的内存开销。
    • Set ,是String类型的无序集合。通过hashtable实现。Set中的元素是没有顺序的,而且是无重复的。常用的命令:sdd、spop、smembers、sunion等。
      应用场景:Redis Set对外提供的功能和List一样是一个列表,特殊之处在于Set是自动去重的,而且Set提供了判断某个成员是否在一个Set集合中的方法。
    • Zset,和Set一样是String类型元素的集合,且不允许存在重复元素。常用命令:zadd、zrange、zrem、zcard等。
      应用场景:Sorted Set(Zset)可以通过用户额外提供的一个优先级(score)的参数来为成员排序,并且是有序插入,即自动排序。
      当你需要一个有序并且不重复的集合时,那么可以选择Zset的结构。和Set相比,Zset关联了一个Double类型权重的参数score,使得集合中的元素能够难找scroe进行有序排列,Redis正是通过分数来为集合中的成员进行从小到大的排序。
      实现方式:Redis Sorted Set的内部使用HashMap和跳跃表(skipList)来保证数据和储存和有序,HashMap中存放的是成员到Score的映射。
  3. Redis的优点

    • 因为是纯内存操作,所以性能非常出色,每秒可以处理超过10万次的读写操作,是已知性能最好的key-value数据库。
    • 单线程操作,避免了频繁的上下文切换
    • 采用了非阻塞I/O多路复用机制。I/O多路复用就是只有单个线程,通过跟踪每个I/O流的状态,来管理多个I/O流
  4. Redis的缺点

    缓存和数据库双写一致性问题
    因为加入了缓存之后,请求首先从redis中查询,如果redis中没有查询到,再进行查询数据库。那么如果redis存在数据,就不会走数据库进行查询,如果不能保证缓存跟数据库的数据一致,就会出现请求到的数据不是最新的数据。
    - 解决方案:
    1.编写删除缓存的接口,在更新数据库的同时,调用删除缓存的接口来删除缓存中的数据。这么做会有耦合高一级接口调用失败的情况。
    2.消息队列:AciveMQ,消息通知。

    缓存的并发竞争问题
    并发竞争,指的是同时又多个子系统去set同一个key值。
    - 解决方案:
    1.最简单的解决方案就是准备一个分布式锁,大家去抢锁,抢到锁的就做set操作即可。

    缓存雪崩问题
    缓存雪崩,即缓存在同一时间大面积失效,这时候如果有大量请求,那么都会到数据库中请求资源,从来导致数据库连接异常。
    - 解决方案:
    1.给缓存的失效时间添加一个随机值,避免缓存在同一时间集体失效。
    2.使用互斥锁,但是该方案吞吐量明显下降。
    3.搭建redis集群。

    缓存击穿(Redis穿透)问题
    缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都发送到数据库上,从而导致数据库连接异常
    - 解决方案:
    1.利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间后重试。
    2.采用异步更新策略,无论key是否得到值,都直接返回,value值中维护一个缓存失效时间,缓存如果过期,异步发起一个线程,去读数据库,更新缓存。