Redis简介

缓存是互联网公司基本技术之一,使用缓存主要有两点好处,高性能和高并发,高性能是指可以把一些经常查询基本不变耗时的数据,放在缓存中,可以减少对数据库的依赖。在高并发的情况下,mysql的数据库可能会挂机。这种情况下可以将数据放到缓存中来应对高峰期高并发。

redis与memcached区别

从下面几个方面来归纳总结redis和memcached的区别

数据类型

memcached只支持string类型的数据存储,redis支持string,hash,list,set,zset五种数据类型。

数据持久化

Redis通过RDB和AOF两种方式支持数据的持久化,而memcached不支持持久化。

分布式

Redis通过一主多从的方式实现分布式。

memcached不支持分布式,只能通过客户端使用一致性哈希来实现分布式存储方式,这种方式在存储和查询时都需要在客户端计算一次数据所在的节点。

内存管理机制

在Redis中,会将value值存储在磁盘中,内存中存储key的值,而memcached会将所有的数据都保存在内存中。

Redis为什么是单线程还支持高并发:

主要有三点支持高并发,首先Redis是基于内存操作,其效率很高,其次Redis是基于非阻塞的IO多路复用机制NIO,最后使用单线程可以避免上下文切换。

Redis的五种数据类型

Redis共支持五种数据类型,以下会从每种的数据结构,底层的数据类型和使用场景进行详细的说明

String字符串类型

底层数据结构:String类型通过int和SDS(simple dynamic string)作为结构存储,其中int存储整数类型的数据,SDS存储字节/字符串和浮点型数据。

应用场景:普通的key/value存储都可以归为此类

1
2
3
4
5
set "test" test

get "test"

del "test"

hash类型

底层数据结构:数据量小的时候用ziplist,另外一种是hashtable。

应用场景:整体看作一个对象,每一个field - value相当于对象的属相和属性值。例如存储用户信息对象数据,包括用户ID,用户姓名,年龄和生日,通过ID我们希望获取用户的姓名年龄和生日。

image-w100

1
2
3
4
5
6
7
8
9
HSET userInfo1 username 'tom' 

HSET userInfo1 password '123456'

hmset name "qiutiangang"

hgetall name

hdel name

list列表类型

底层数据结构:before3.2 当list元素个数和单个元素长度比较小的时候,采用ziplist否则用linkedlist结构,after3.2 底层用quickList来实现。linkedlist在插入节点上时间复杂度低但内存开销比较大。ziplist存储在连续的内存上,存储率比较高。但是插入和删除都需要频繁的申请和释放内存。quicklist仍是双向链表,只每一个节点是ziplist。

quicklist ==> linkedlist + ziplist

应用场景:列表类型可以存储一个有序的字符串列表,常用的操作是向列表的两端添加元素或者获取列表的某一个片段。列表的内部使用一个双向链表实现,所以向列表两端添加元素的时间复杂度是o(1),获取越接近两端的元素就越来越快。这意味着即使几千万的元素,获取前几条元素也很快。可以应用与twitter的关注列表,粉丝列表。

1
2
3
4
5
Lpush testList qiutiangang

Lpop testList

lrange testlist 0 10

set集合

底层数据结构:当set找那个只包含整数型元素时采用intset来存储。否则炒菜用hashtable来存储,对于set来说,该hashtable的value值用于null,通过key来存储元素。

应用场景:与list类似是一个列表功能。set是自动排重的

1
2
3
sadd testSet aa

smembers testSet

zset有序集合

底层数据结构:采用ziplist或者hashtable

应用场景:有序自动排重列表

1
zadd testZ a

Redis的持久化方式

Redis支持两种方式的持久化,一种是RDB方式、另一种是AOF(append-only-file)方式。前者会根据指定的规则“定时”将内存中的数据存储在硬盘上,而后者在每次执行命令后将命令本身记录下来。两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。

RDB方式

当符合一定条件时,Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,等到持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方 式要比AOF方式更加的高效。RDB的缺点是后一次持久化后的数据可能丢失。

AOF方式

当使用Redis存储非临时数据时,一般需要打开AOF持久化来降低进程终止导致的数据丢失。AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。

Redis的内存淘汰策略

Redis的内存淘汰侧罗是指在Redis的用于缓存内存不足时,怎么处理需要重新申请额外的空间数据:

  1. no-envicition:当内存不足以容纳新写入的数据时,写入操作会报错。
  2. allkeys-Iru:当内存不足以容纳新写入数据时,在键空间找那个,移除最少使用的key.
  3. allkeys-random:当内存不足以容纳新写入的数据时,在键空间中,随机移除某个key。
  4. volatile-Iru:当内存不足以容纳新写入的数据时。在设置过期的时间的键空间中,移除最少使用的key。
  5. volatile-random:当内存不足以容纳新写入的数据时,在设置过期时间的键空间中,随机移除某个key。
  6. volatile-ttl:当内存空间不足以容纳新写入的数据时,在设置过期时间的键空间中,有更早过期时间的key优先移除

Redis过期策略

将Redis中的Key设置过期可以通过以下过期策略:

  1. 定时过期:每个设置过期时间的Key都需要创建一个定时器,到过期时间会立即清除,对内存很友好,但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的时间和吞吐量。
  2. 惰性过期:只有当访问一个Key时,才会判断Key是否已经过期。过期则清除。该策略最大化节省了CPU资源,却对内存非常不友好,极端情况下可能出现大量的key没有被访问,从而不会清除占用大量内存。
  3. 定期过期:每隔一段时间会扫描一定数量的数据库expires字典中的key,并清除其中已经过期的Key。

Redis使用了惰性过期和定时过期两种过期策略

Redis的高可用和高并发

在分布式的环境中,要保证系统的高可用和高并发,就需要部署集群。Redis的高可用采用主从模式,一主多从,每个实例都容纳完整的数据。在保证高并发的情况下,还需要容纳大量的数据,这时就需要将Redis部署集群模式。保证系统的高可用,是在部署主从模式之上加哨兵机制。就可以实现,任何一个实例宕机,自动会进行主备之间切换。

哨兵模式

将Redis部署为主从模式,如果master服务器宕机之后,可以手动的将slave服务器切换为mater服务器。这种人工切换的方式会使服务在一定时间内导致不可用。因此可以使用哨兵模式来完成。

哨兵是一个独立的进程,其原理是通过哨兵进行来进行对Redis实例发送消息,等待响应,从而监控运行的Redis实例。当master服务宕机之后,会自动将slave服务器切换为master服务器,并通过发布订阅模式通知其他服务修改配置。