分布式缓存--redis

redis 的优势

命令参考:http://doc.redisfans.com/

功能

  1. 可以为每个key设置超时时间;
  2. 可以通过列表类型来实现分布式队列的操作
  3. 支持发布订阅的消息模式

自带工具

  1. Redis-server 启动服务
  2. Redis-cli 访问到redis的控制台
  3. redis-benchmark 性能测试的工具
  4. redis-check-aof aof文件进行检测的工具
  5. redis-check-dump rdb文件检查工具
  6. redis-sentinel sentinel 服务器配置

多数据库支持

默认支持16个数据库;可以理解为一个命名空间,跟关系型数据库不一样的点

  1. redis不支持自定义数据库名词
  2. 每个数据库不能单独设置授权
  3. 每个数据库之间并不是完全隔离的。 可以通过flushall命令清空redis实例面的所有数据库中的数据

通过 select dbid 去选择不同的数据库命名空间 。 dbid的取值范围默认是0 -15

存储结构

字符类型

一个字符类型的key默认存储的最大容量是512M

1
2
SET key  value
GET key

递增数字

错误示范:

1
2
3
int value= get key;
value =value +1;
set key value;

原子性操作递增,如果value是数字类型,可以对值进行递增

1
incr key

散列类型

HashMap, 不支持数据类型的嵌套, 比较适合存储对象

1
2
3
4
5
6
7
8
9
hset key field value
hget key filed
hmset key filed value [filed value …] 一次性设置多个值
hmget key field field … 一次性获得多个值
hgetall key 获得hash的所有信息,包括key和value
hexists key field 判断字段是否存在。 存在返回1. 不存在返回0
hincryby
hsetnx
hdel key field [field …] 删除一个或者多个字段

列表类型

list类型, 可以存储一个有序的字符串列表
内部使用双向链表数据结构

1
2
3
4
5
6
LPUSH/RPUSH key value value 从左边或者右边push数据
llen num 获得列表的长度
lrange key start stop 索引可以是负数 -1表示最右边的第一个元素
lrem key count value
lset key index value
LPOP/RPOP : 取数据

应用场景

用来做分布式消息队列

集合类型

set 跟list 不一样的点。 集合类型不能存在重复的数据。而且是无序的

1
2
3
4
5
sadd key member [member ...] 增加数据; 如果value已经存在,则会忽略存在的值,并且返回成功加入的元素的数量
srem key member 删除元素
smembers key 获得所有数据
sdiff key key … 对多个集合执行差集运算
sunion 对多个集合执行并集操作, 同时存在在两个集合里的所有值

有序集合

sortSet

1
2
zadd key score member
zrange key start stop [withscores] 去获得元素。 withscores是可以获得元素的分数

如果两个元素的score是相同的话,那么根据(0<9<A<Z<a<z) 方式从小到大, 使用场景:网站访问的前10名。

redis的事务处理

1
2
MULTI 去开启事务
EXEC 去执行事务

过期时间

1
2
expire key seconds 
ttl key 获得key的过期时间

发布订阅

1
2
publish channel message
subscribe channel […]

redis应用场景

数据缓存(商品数据、新闻、热点数据)

单点登录

秒杀、抢购

网站访问排名

redis实现分布式锁

多路复用机制

inux的内核会把所有外部设备都看作一个文件来操作,对一个文件的读写操作会调用内核提供的系统命令,返回一个 file descriptor(文件描述符)。对于一个socket的读写也会有响应的描述符,称为socketfd(socket 描述符)。而IO多路复用是指内核一旦发现进程指定的一个或者多个文件描述符IO条件准备好以后就通知该进程
IO多路复用又称为事件驱动,操作系统提供了一个功能,当某个socket可读或者可写的时候,它会给一个通知。当配合非阻塞socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据。操作系统的功能通过select/pool/epoll/kqueue之类的系统调用函数来使用,这些函数可以同时监视多个描述符的读写就绪情况,这样多个描述符的I/O操作都能在一个线程内并发交替完成,这就叫I/O多路复用,这里的复用指的是同一个线程
多路复用的优势在于用户可以在一个线程内同时处理多个socket的 io请求。达到同一个线程同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到目的

redis中使用lua脚本

待补充… …

持久化机制

两种持久化策略可以同时使用,也可以使用其中一种。如果同时使用的话, 那么Redis重启时,会优先使用AOF文件来还原数据

RDB

RDB的持久化策略: 按照规则定时讲内从的数据同步到磁盘
redis在指定的情况下会触发快照(snapshot)

  1. 自己配置的快照规则
1
2
3
4
save <seconds> <changes>
save 900 1 当在900秒内被更改的key的数量大于1的时候,就执行快照
save 300 10
save 60 10000
  1. save或者bgsave
1
2
save: 执行内存的数据同步到磁盘的操作,这个操作会阻塞客户端的请求
bgsave: 在后台异步执行快照操作,这个操作不会阻塞客户端的请求
  1. 执行flushall的时候
    清除内存的所有数据,只要快照的规则不为空,也就是第一个规则存在。那么redis会执行快照
  2. 执行复制的时候

快照的实现原理

  1. redis使用fork函数复制一份当前进程的副本(子进程)
  2. 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件
  3. 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。

redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。 这就使得我们可以通过定时备份RDB文件来实现redis数据库的备份, RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。

优缺点

  1. 使用RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这个时候我们就需要根据具体的应用场景,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受范围。如果数据相对来说比较重要,希望将损失降到最小,则可以使用AOF方式进行持久化
  2. RDB可以最大化Redis的性能:父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无序执行任何磁盘I/O操作。同时这个也是一个缺点,如果数据集比较大的时候,fork可以能比较耗时,造成服务器在一段时间内停止处理客户端的请求;

配置

修改redis.conf

  • appendonly yes ; 重启后执行对数据的变更命令, 会在bin目录下生成对应的.aof文件, aof文件中会记录所有的操作命令、如下两个参数可以去对aof文件做优化
  • auto-aof-rewrite-percentage 100 表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以启动时aof文件大小为准
  • auto-aof-rewrite-min-size 64mb 限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化

AOF

AOF可以将Redis执行的每一条写命令追加到硬盘文件中,这一过程显然会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能

配置

默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数启用,在redis.conf中找到 appendonly yes
开启AOF持久化后每执行一条会更改Redis中的数据的命令后,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是apendonly.aof. 可以在redis.conf中的属性 appendfilename appendonlyh.aof修改

redis每次更改数据的时候, aof机制都会讲命令记录到aof文件,但是实际上由于操作系统的缓存机制,数据并没有实时写入到硬盘,而是进入硬盘缓存。再通过硬盘缓存机制去刷新到保存到文件

  • appendfsync always 每次执行写入都会进行同步 , 这个是最安全但是是效率比较低的方式
  • appendfsync everysec 每一秒执行
  • appendfsync no 不主动进行同步操作,由操作系统去执行,这个是最快但是最不安全的方式

重写的原理

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松

aof文件损坏以后如何修复

服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。
当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:

  1. 为现有的 AOF 文件创建一个备份。
  2. 使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复。(redis-check-aof --fix)
    重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。

RDB 和 AOF 如何选择

一般来说,如果对数据的安全性要求非常高的话,应该同时使用两种持久化功能。如果可以承受数分钟以内的数据丢失,那么可以只使用 RDB 持久化。有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快 。