Redis知识点汇总

Q:什么是redis,有什么特点?
A:redis是一款基于C语言编写的key-value类型的内存数据库,很像memcached,整个数据库都加载在内存中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。
因为是纯内存的操作,redis性能出色,每秒可处理10w次的读写操作,是已知性能最快的key-value DB。
(1.速度快,是因为数据存在内存中,类似于HashMap,HashMap的优势在于查找和操作的时间复杂度都是O(1)。redis是单进程单线程的:redis利用队列技术将并发访问变为串行访问,避免了不必要的上下文切换和竞争条件,消除了传统数据库串行控制的开销,也不存在多进程或者多线程导致的切换而消耗CPU。多路IO复用模型-非阻塞IO。使用的底层模型不同他们之间底层实现方式以及客户端之间通信的应用协议不一样。redis直接自己构建了VM机制,因为一般的系统调用系统函数的话会浪费一定的时间去移动和请求。
2.支持丰富的数据类型:String、List、Set、Sorted Set、hash;
3.支持事务,操作都是原子性的:对数据的更改要么全部执行,要么全部不执行;
4.丰富的特性:可用于缓存、消息、按key设置过期时间,过期后会自动删除)
redis不仅性能出色,而且支持保存多种数据结构,并且单个value的最大限制是1GB(memcached只能保存1MB的数据),因此redis可以用来实现很多功能。
redis中的List可做FIFO双向链表,实现一个轻量级的高性能消息队列服务。Set可做高性能的tag系统。另外,redis可以对存入的key-value设置expire时间,因此也可以被当做一个功能加强版的memcached来用。
1.会话缓存(Session Cache)最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的;
2.全页缓存(FPC)。除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC;
3.队列。Reids在内存存储引擎领域的一大优点是提供list和set操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对list的push/pop 操作;
4.排行榜。Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:ZRANGE user_scores 0 10。当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:ZRANGE user_scores 0 10 WITHSCORES;
5.发布/订阅。发布/订阅的使用场景非常多。已有人在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统;
6.计数器可使用String(decr、incr)实现,String还可以用于分布式锁(setnx,del、expire);
7.购物车可使用hash类型实现(hset、hdel、hincrby、hgetall),数据经常变化适合使用hash实现;
8.好友、粉丝、感兴趣的人集合可使用set实现(sismember、scard、smove),还可以用于实现随机展示(sranmember)、黑白名单(sismember)等

redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此redis适合的场景主要局限在较小数据量的高性能操作和运算上。

Q:redis的并发竞争问题如何解决?
A:redis是单进程单线程模式(这里的单线程指的是网络请求模块使用了一个线程,所以不需考虑并发安全性,即一个线程处理所有网络请求,其他模块仍用了多个线程。),采用队列模式将并发访问变为串行访问。redis本身没有锁的概念,redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。有两种解决方法:
1.客户端角度,应用程序自己处理资源的同步。为保证每个客户端正常有序与redis进行通信,对连接进行池化,同时对客户端读写redis操作采用内部锁sychronized、lock;
2.服务器角度,利用setnx实现锁;
redis的分布式锁实现:
利用redis命令(不存在就插入):setnx key value,所有节点的key都相同,value随便写什么,1代表成功拿到锁,0代表失败
释放锁就是删除key命令:del key
存在的问题:节点获得锁之后,宕机了,导致锁得不到释放,就形成了死锁
解决办法:
1.设置key过期:expire key timeout,相当于把锁持有的有效期交给redis控制,超过这个时间锁会自动释放,避免死锁;
2.把删除key的权利交给其他服务器,这时value设置成过期时间:expiretime,如果服务器2发现expiretime已经过期,则删除key,再执行setnx命令获得锁;
但是这里又有另外一个问题,就是在服务器2删除key,执行setnx命令后,如果服务器3紧接着删除key并执行setnx,这时服务器2和服务器3都拿到锁了;
可以用命令(获取旧值,设置新值):getset key value解决:调用getset命令,获取expiretime字段后判断是否过期,过期了则拿到锁,否则可能是服务器3先执行了getset操作拿到了锁,设置了过期时间。这里其实有个小问题,就是服务器3修改了有效期拿到了锁后,服务器2也修改了有效期,但没拿到锁,相当于有效期多了一点,但是这种影响一般很小

Q:为什么redis需要把所有数据放在内存中?
A:redis为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以Redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度会严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记录数达到内存限值之后不能继续插入新值。

Q:redis比memcached比有哪些优势?
A:
1.memcached所有的值均是简单的字符串,redis支持更丰富的数据类型,使用的底层模型不同他们之间底层实现方式以及客户端之间通信的应用协议不一样。redis直接自己构建了VM机制,因为一般的系统调用系统函数的话会浪费一定的时间去移动和请求;
2.redis支持数据的持久化,memcached把数据全部存在内存之中,断点之后会挂掉,数据不能超过内存大小;redis可以将内存的数据保存在磁盘中,重启时再次加载进行使用,数据存在硬盘上,这样能保证数据的持久性;
3.redis支持数据的备份,即master-slave模式的数据备份;
4.redis速度比memcached快很多;

Q:redis常见性能问题和解决方案?
A:
1.Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响很大,会间断性暂停服务,所以Master最好不要写内存快照;
2.Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份策略为每秒同步一次;
3.Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源导致服务负载过高,出现短暂服务暂停现象;
4.redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内;

Q:mySQL中有2000w数据,redis只存20w的数据,如何保证redis中的数据都是热点数据?
A:redis内存数据集大小上升到一定大小时,会施行数据淘汰策略。redis提供6种数据淘汰策略:
1.volatile-lru 从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰;
2.volatile-ttl 从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰;
3.volatile-random 从已设置过期时间的数据集(server.db[i].expires)中随机选择数据淘汰;
4.allkeys-lru 从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰;
5.allkeys-random 从数据集(server.db[i].dict)中随机选择数据淘汰;
6.no-enviction 禁止驱逐数据;
使用策略规则:
如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用allkeys-lru;
如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random;
lru会对key按失效时间排序,然后取最先失效的key进行淘汰。

Q:使用redis和任意语言实现一段恶意登录保护代码:限制一小时内每个用户Id最多只能登录5次;
A:可使用列表List实现:列表中每个元素代表登录时间,只要列表长度大于等于5且最后的第5次登录时间和现在时间差不超过1小时就禁止登录。

Q:redis的高级事务CAS(check-and-set操作实现乐观锁)了解吗?
A:和众多数据库一样,redis作为NoSql数据库也提供了事务机制。在redis中,multi/exec/discard/watch这四个命令是我们实现事务的基石。在redis事务中,watch命令可用于提供CAS(check-and-set)功能。假设我们通过watch命令在事务执行之前监控了多个keys,倘若在watch之后有任何key的值发生了变化,exec命令执行的事务都将被放弃,同时返回null multi-bulk应答以通知调用者事务执行失败。

Redis相关特性:
1.多数据库
一个redis实例可以包含多个数据库(最多可提供16个),一个redis客户端可以指定连接某个redis实例的某个数据库。默认使用0号数据库。
127.0.0.1:6379>select 1 --选择1号数据库
127.0.0.1:6379>move mykey 1 --将现在数据库的mykey这个数据移动到1号数据库

2.Redis提供事务机制:	在事务中所有的命令都将串行化顺序执行,事务执行期间redis不会为其他客户端提供任何服务,从而保证事务中的所有命令都被原子化执行。
和关系型数据库中的事务相比,redis中如果某个命令执行失败,该命令后面的命令还会被执行。
	使用multi开启事务(相当于关系型数据库的begin);在该语句之后的命令都被视为是事务里的操作,直到exec语句。
	exec(==关系型数据库的commit):
	discard(==关系型数据库的rollback)
	
3.redis持久化(为了保证redis在重启后数据不丢失,需要将数据从内存保存到磁盘上)
	持久化使用的方式:
	a)RDB方式,默认支持,生成dump.rdb,不需要配置。在指定的时间间隔内,将内存中的数据集快照写入磁盘;
	b)AOF方式。以日志的形式记录服务器进行的每一次操作,在redis服务器启动之初会读取该文件重新构建数据库;
	c)无持久化。只做缓存的作用
	d)同时使用RDB和AOF
RDB的优势
	a)一旦采用该方式,那么你的整个Redis数据库将包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性的故障,我们可以非常容易的进行修复。
	b)对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
	c)性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork(分叉)出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大避免服务进程执行IO操作了。
	d)相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB的劣势
	a)如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
	b)由于RDB是通过fork子进程来协助完成数据持久化工作,因此,如果当数据集较大时,可能会导致整个服务器停止服务器几百毫秒,甚至1秒钟。
	
AOF的优势					
	a)该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是,一旦系统出现了宕机现象,那么这一秒钟之内修改的数据会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确理解它。
	b)由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃的问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
	c)如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
	d)AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们可以通过该文件完成数据的重建。
AOF的劣势
	a)对于相同数量的数据集而言,AOF文件通常要大于RDB文件;		b)根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
	c)需要配置,redis.conf中修改appendonly no改为appendonly yes,选择AOF的策略(有appendfsync always、appendfsync everysec、appendfsync no)就会生成appendonly.aof文件
	d)

Q:为什么建议淘汰缓存而不是更新缓存?
A:若是更新缓存,则可能出现:
有A、B两个线程并发写,因为无法保证时序,不管是先操作缓存还是先操作数据库,都可能出现(1)A先操作数据库,B后操作数据库(2)B先set了缓存,A后set了缓存。导致数据库与缓存之间的数据不一致。

Q:为什么建议先操作数据库再操作缓存?
A:如果先操作缓存再操作数据库可能会有:A写,B读,(1)A写时先淘汰缓存(2)A还未修改数据库/A修改了主数据库,但数据库主从同步未完成(3)这时B读缓存没有命中(4)B数据库读取到原数据/B从从库中读取了原数据(5)B将原数据更新至缓存(6)A修改数据库为新数据/数据库主从同步完成。导致数据库与缓存数据不一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值