一、redis简介

  Redis是当前比较热门的NOSQL系统之一,它是一个开源的使用ANSI c语言编写的key-value存储系统(区别于MySQL的二维表格的形式存储。)。和Memcache类似,但很大程度补偿了Memcache的不足。和Memcache一样,Redis数据都是缓存在计算机内存中,不同的是,Memcache只能将数据缓存到内存中,无法自动定期写入硬盘,这就表示,一断电或重启,内存清空,数据丢失。所以Memcache的应用场景适用于缓存无需持久化的数据。而Redis不同的是它会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,实现数据的持久化。

 

二、redismeamache区别

1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。

2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。

3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘

4、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)

5、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复

6、Redis支持数据的备份,即master-slave模式的数据备份。

 

三、redis为什么这么快

1、纯内存操作;

2、单线程操作,避免了频繁的上下文切换;

3、采用C语言编写,而C语言由于更加接近计算机的底层,所以速度更快;

4、采用了非阻塞I/O多路复用机制: 我们的redis-client在操作的时候,会产生具有不同事件类型的socket。在服务端,有一段I/0多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。

 

四、redis的应用场景

1、缓存

2、任务队列

3、网站访问统计

4、数据过期处理

5、应用排行榜

6、分布式集群架构中的session分离

 

五、redis的数据类型

Redis一共支持五种数据类:string(字符串),hash(哈希),list(列表),set(集合)和zset(sorted set有序集合)。

1、String:

常用命令:set(赋值)/get(查询)/decr (自减)/incr(自增)/mget(查询多个key)

这个其实没啥好说的, value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。

 

2、hash

命令:hset(添加赋值)/hget(查询)/hgetall(查询所有字段和值)等。

这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。

 

3、list

常用命令:lpush(列表头部添加元素)/rpush(列表尾部添加元素)/lpop(头部删除元素)/rpop(尾部删除元素)/lrange(查询元素)等.

Redis列表是字符串列表,不支持嵌套其他数据类型,是redis中有序可重复结构。可以向列表的头部或者尾部进行添加和删除操作;应用的场景非常多,比如存储文章评论列表,存储用户的粉丝列表,黑名单列表等,也可以作为重要的消息队列来使用。

 

4、set

常用命令有sadd(添加元素)/spop(删除)/smembers(查询)/sunion(添加多个集合)等,基本示例如下所示。

使用:Redis集合是字符串集合,不支持嵌套其他数据类型,不重复无序结构。与list的功能相似,但是提供了自动去重功能,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

 

5、sorted set

使用:Redis有序集合是在集合的基础上增加了排序功能,规则是按照该元素对应的Score进行排序。实际应用来讲主要是涉及到排序的功能场景都可以使用,例如实现文章按点击量排序,微博热搜榜,论坛热帖等。sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。sorted set在set基础上为每个元素都关联了一个分数score,通过score来实现排序功能。常用命令:zadd/zrange/zrem/zcard,

 

六、redis的缺点

其实是缓存都有下面四个问题,一般的企业,说实话,缓存雪崩、缓存击穿很能遇到。

1、缓存和数据库双写一致性问题

2、缓存雪崩问题: 缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。

解决方案:

a、给缓存的失效时间,加上一个随机值,避免集体失效。

b、使用互斥锁,但是该方案吞吐量明显下降了。

c、双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点

I 从缓存A读数据库,有则直接返回

II A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程。

III 更新线程同时更新缓存A和缓存B。

3、缓存击穿问题: 请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。

解决方案:

a、利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试

b、采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。

c、提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。

4、缓存的并发竞争问题

 

七、redis的持久化

  redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库,就像memcache一样。

1、RDB

  RDB方式,是将redis某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。对于RDB方式,redis会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何IO操作的,这样就确保了redis极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

  虽然RDB有不少优点,但它的缺点也是不容忽视的。如果你对数据的完整性非常敏感,那么RDB方式就不太适合你,因为即使你每5分钟都持久化一次,当redis故障时,仍然会有近5分钟的数据丢失。所以,redis还提供了另一种持久化方式,那就是AOF。

 

2、AOF

  AOF,英文是Append Only File,即只允许追加不允许改写的文件。如前面介绍的,AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。我们通过配置redis.conf中的appendonly yes就可以打开AOF功能。如果有写操作(如SET等),redis就会被追加到AOF文件的末尾。默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的处理性能,即使redis故障,也只会丢失最近1秒钟的数据。如果在追加日志时,恰好遇到磁盘空间满、inode满或断电等情况导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志修复。因为采用了追加方式,如果不做任何处理的话,AOF文件会变得越来越大,为此,redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了100次INCR指令,在AOF文件中就要存储100条指令,但这明显是很低效的,完全可以把这100条指令合并成一条SET指令,这就是重写机制的原理。在进行AOF重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响AOF文件的可用性,这点大家可以放心。

   AOF方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作redis时,不小心执行了FLUSHALL,导致redis内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件还没有被重写(rewrite),我们就可以用最快的速度暂停redis并编辑AOF文件,将最后一行的FLUSHALL命令删除,然后重启redis,就可以恢复redis的所有数据到FLUSHALL之前的状态了。是不是很神奇,这就是AOF持久化方式的好处之一。但是如果AOF文件已经被重写了,那就无法通过这种方法来恢复数据了。

  虽然优点多多,但AOF方式也同样存在缺陷,比如在同样数据规模的情况下,AOF文件要比RDB文件的体积大。而且,AOF方式的恢复速度也要慢于RDB方式。如果你直接执行BGREWRITEAOF命令,那么redis会生成一个全新的AOF文件,其中便包括了可以恢复现有数据的最少的命令集。如果运气比较差,AOF文件出现了被写坏的情况,也不必过分担忧,redis并不会贸然加载这个有问题的AOF文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:

1).备份被写坏的AOF文件

2).运行redis-check-aof –fix进行修复

3).用diff -u来看下两个文件的差异,确认问题点

4).重启redis,加载修复后的AOF文件

 

八、redis的主从复制

  像MySQL一样,redis是支持主从同步的,而且也支持一主多从以及多级从结构。主从结构,一是为了纯粹的冗余备份,二是为了提升读性能,比如很消耗性能的SORT就可以由从服务器来承担。redis的主从同步是异步进行的,这意味着主从同步不会影响主逻辑,也不会降低redis的处理性能。主从架构中,可以考虑关闭主服务器的数据持久化功能,只让从服务器进行持久化,这样可以提高主服务器的处理性能。在主从架构中,从服务器通常被设置为只读模式,这样可以避免从服务器的数据被误修改。但是从服务器仍然可以接受CONFIG等指令,所以还是不应该将从服务器直接暴露到不安全的网络环境中。如果必须如此,那可以考虑给重要指令进行重命名,来避免命令被外人误执行。

  主从复制的原理:从服务器会向主服务器发出SYNC指令,当主服务器接到此命令后,就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作,也就是将主服务器的数据写入RDB文件中。在数据持久化期间,主服务器将执行的写指令都缓存在内存中。在BGSAVE指令执行完成后,主服务器会将持久化好的RDB文件发送给从服务器,从服务器接到此文件后会将其存储到磁盘上,然后再将其读取到内存中。这个动作完成后,主服务器会将这段时间缓存的写指令再以redis协议的格式发送给从服务器。另外,要说的一点是,即使有多个从服务器同时发来SYNC指令,主服务器也只会执行一次BGSAVE,然后把持久化好的RDB文件发给多个下游。在redis2.8版本之前,如果从服务器与主服务器因某些原因断开连接的话,都会进行一次主从之间的全量的数据同步;而在2.8版本之后,redis支持了效率更高的增量同步策略,这大大降低了连接断开的恢复成本。

  主服务器会在内存中维护一个缓冲区,缓冲区中存储着将要发给从服务器的内容。从服务器在与主服务器出现网络瞬断之后,从服务器会尝试再次与主服务器连接,一旦连接成功,从服务器就会把“希望同步的主服务器ID”和“希望请求的数据的偏移位置(replication offset)”发送出去。主服务器接收到这样的同步请求后,首先会验证主服务器ID是否和自己的ID匹配,其次会检查“请求的偏移位置”是否存在于自己的缓冲区中,如果两者都满足的话,主服务器就会向从服务器发送增量内容。增量同步功能,需要服务器端支持全新的PSYNC指令。这个指令,只有在redis-2.8之后才具有。