前言
欢送各位进群973961276一起聊聊技术吹吹牛,每周都会有几次抽奖送专业书籍的流动,奖品虽不甚值钱,但也可搏个彩头
1.什么是redis?
Redis 是一个基于内存的高性能key-value数据库。
2.Reids的特点
Redis实质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库通通加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保留。因为是纯内存操作,Redis的性能十分杰出,每秒能够解决超过 10万次读写操作,是已知性能最快的Key-Value DB。
Redis的杰出之处不仅仅是性能,Redis最大的魅力是反对保留多种数据结构,此外单个value的最大限度是1GB,不像 memcached只能保留1MB的数据,因而Redis能够用来实现很多有用的性能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能音讯队列服务,用他的Set能够做高性能的tag零碎等等。另外Redis也能够对存入的Key-Value设置expire工夫,因而也能够被当作一 个性能加强版的memcached来用。
Redis的次要毛病是数据库容量受到物理内存的限度,不能用作海量数据的高性能读写,因而Redis适宜的场景次要局限在较小数据量的高性能操作和运算上。
零根底和大三大四的敌人看这里>>c/c++ 企业级我的项目实战
曾经工作了想持续自我晋升跳槽涨薪的工程师看这里>>c/c++ linux服务器高级架构师学习
3.应用redis有哪些益处?
1.速度快,因为数据存在内存中,相似于HashMap,HashMap的劣势就是查找和操作的工夫复杂度都是O(1)
2.反对丰盛数据类型,反对string,list,set,sorted set,hash
1)String
常用命令:set/get/decr/incr/mget等;
利用场景:String是最罕用的一种数据类型,一般的key/value存储都能够归为此类;
实现形式:String在redis外部存储默认就是一个字符串,被redisObject所援用,当遇到incr、decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。
2)Hash
常用命令:hget/hset/hgetall等
利用场景:咱们要存储一个用户信息对象数据,其中包含用户ID、用户姓名、年龄和生日,通过用户ID咱们心愿获取该用户的姓名或者年龄或者生日;
实现形式:Redis的Hash理论是外部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口。Key是用户ID, value是一个Map。这个Map的key是成员的属性名,value是属性值。这样对数据的批改和存取都能够间接通过其外部Map的Key(Redis里称外部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就能够操作对应属性数据。
以后HashMap的实现有两种形式:当HashMap的成员比拟少时Redis为了节俭内存会采纳相似一维数组的形式来紧凑存储,而不会采纳真正的HashMap构造,这时对应的value的redisObject的encoding为zipmap,当成员数量增大时会主动转成真正的HashMap,此时encoding为ht。
3)List
常用命令:lpush/rpush/lpop/rpop/lrange等;
利用场景:Redis list的利用场景十分多,也是Redis最重要的数据结构之一,比方twitter的关注列表,粉丝列表等都能够用Redis的list构造来实现;
实现形式:Redis list的实现为一个双向链表,即能够反对反向查找和遍历,更不便操作,不过带来了局部额定的内存开销,Redis外部的很多实现,包含发送缓冲队列等也都是用的这个数据结构。
4)Set
常用命令:sadd/spop/smembers/sunion等;
利用场景:Redis set对外提供的性能与list相似是一个列表的性能,非凡之处在于set是能够主动排重的,当你须要存储一个列表数据,又不心愿呈现反复数据时,set是一个很好的抉择,并且set提供了判断某个成员是否在一个set汇合内的重要接口,这个也是list所不能提供的;
实现形式:set 的外部实现是一个 value永远为null的HashMap,理论就是通过计算hash的形式来疾速排重的,这也是set能提供判断一个成员是否在汇合内的起因。
5)Sorted Set
常用命令:zadd/zrange/zrem/zcard等;
利用场景:Redis sorted set的应用场景与set相似,区别是set不是主动有序的,而sorted set能够通过用户额定提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即主动排序。当你须要一个有序的并且不反复的汇合列表,那么能够抉择sorted set数据结构,比方twitter 的public timeline能够以发表工夫作为score来存储,这样获取时就是主动按工夫排好序的。
实现形式:Redis sorted set的外部应用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里寄存的是所有的成员,排序根据是HashMap里存的score,应用跳跃表的构造能够取得比拟高的查找效率,并且在实现上比较简单。
3.反对事务,操作都是原子性,所谓的原子性就是对数据的更改要么全副执行,要么全副不执行
4.丰盛的个性:可用于缓存,音讯,按key设置过期工夫,过期后将会主动删除
4.redis相比memcached有哪些劣势?
- memcached所有的值均是简略的字符串,redis作为其替代者,反对更为丰盛的数据类型
- redis的速度比memcached快很多 (3) redis能够长久化其数据
5.Memcache与Redis的区别都有哪些?
- 存储形式 Memecache把数据全副存在内存之中,断电后会挂掉,数据不能超过内存大小。Redis有部份存在硬盘上,这样能保证数据的持久性。
- 数据反对类型 Memcache对数据类型反对绝对简略。Redis有简单的数据类型。
- 应用底层模型不同 它们之间底层实现形式 以及与客户端之间通信的利用协定不一样。Redis间接本人构建了VM 机制 ,因为个别的零碎调用零碎函数的话,会节约肯定的工夫去挪动和申请。
6.redis实用于的场景?
Redis最适宜所有数据in-momory的场景,如:
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 操作。
如果你疾速的在Google中搜寻“Redis queues”,你马上就能找到大量的开源我的项目,这些我的项目的目标就是利用Redis创立十分好的后端工具,以满足各种队列需要。例如,Celery有一个后盾就是应用Redis作为broker,你能够从这里去查看。
4.排行榜/计数器
Redis在内存中对数字进行递增或递加的操作实现的十分好。汇合(Set)和有序汇合(Sorted Set)也使得咱们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,咱们要从排序汇合中获取到排名最靠前的10个用户–咱们称之为“user_scores”,咱们只须要像上面一样执行即可:
当然,这是假设你是依据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你须要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是应用Redis来存储数据的,你能够在这里看到。
5.公布/订阅
最初(但必定不是最不重要的)是Redis的公布/订阅性能。公布/订阅的应用场景的确十分多。举荐浏览:Redis 的 8 大利用场景。
7、redis的缓存生效策略和主键生效机制
作为缓存零碎都要定期清理有效数据,就须要一个主键生效和淘汰策略.
在Redis当中,有生存期的key被称为volatile。在创立缓存时,要为给定的key设置生存期,当key过期的时候(生存期为0),它可能会被删除。
1、影响生存工夫的一些操作
生存工夫能够通过应用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令笼罩原来的数据,也就是说,批改key对应的value和应用另外雷同的key和value来笼罩当前,以后数据的生存工夫不同。
比如说,对一个 key 执行INCR命令,对一个列表进行LPUSH命令,或者对一个哈希表执行HSET命令,这类操作都不会批改 key 自身的生存工夫。另一方面,如果应用RENAME对一个 key 进行改名,那么改名后的 key的生存工夫和改名前一样。
RENAME命令的另一种可能是,尝试将一个带生存工夫的 key 改名成另一个带生存工夫的 another_key ,这时旧的 another_key (以及它的生存工夫)会被删除,而后旧的 key 会改名为 another_key ,因而,新的 another_key 的生存工夫也和本来的 key 一样。应用PERSIST命令能够在不删除 key 的状况下,移除 key 的生存工夫,让 key 从新成为一个persistent key 。
2、如何更新生存工夫
能够对一个曾经带有生存工夫的 key 执行EXPIRE命令,新指定的生存工夫会取代旧的生存工夫。过期工夫的精度曾经被管制在1ms之内,主键生效的工夫复杂度是O(1),EXPIRE和TTL命令搭配应用,TTL能够查看key的以后生存工夫。设置胜利返回 1;当 key 不存在或者不能为 key 设置生存工夫时,返回 0 。
最大缓存配置,在 redis 中,容许用户设置最大应用内存大小
server.maxmemory
默认为0,没有指定最大缓存,如果有新的数据增加,超过最大内存,则会使redis解体,所以肯定要设置。redis 内存数据集大小回升到肯定大小的时候,就会履行数据淘汰策略。
redis 提供 6种数据淘汰策略:
- volatile-lru:从已设置过期工夫的数据集(server.db[i].expires)中筛选最近起码应用的数据淘汰
- volatile-ttl:从已设置过期工夫的数据集(server.db[i].expires)中筛选将要过期的数据淘汰
- volatile-random:从已设置过期工夫的数据集(server.db[i].expires)中任意抉择数据淘汰
- allkeys-lru:从数据集(server.db[i].dict)中筛选最近起码应用的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意抉择数据淘汰
- no-enviction(驱赶):禁止驱赶数据
留神这里的6种机制,volatile和allkeys规定了是对已设置过期工夫的数据集淘汰数据还是从全副数据集淘汰数据,前面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略。
应用策略规定:
- 如果数据出现幂律散布,也就是一部分数据拜访频率高,一部分数据拜访频率低,则应用allkeys-lru
- 如果数据出现平等散布,也就是所有的数据拜访频率都雷同,则应用allkeys-random
三种数据淘汰策略:
ttl和random比拟容易了解,实现也会比较简单。次要是Lru最近起码应用淘汰策略,设计上会对key 按生效工夫排序,而后取最先生效的key进行淘汰
8.为什么redis须要把所有数据放到内存中?
Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的形式将数据写入磁盘。所以redis具备疾速和数据长久化的特色。如果不将数据放在内存中,磁盘I/O速度为重大影响redis的性能。在内存越来越便宜的明天,redis将会越来越受欢迎。
如果设置了最大应用的内存,则数据已有记录数达到内存限值后不能持续插入新值。
9.Redis是单过程单线程的
redis利用队列技术将并发拜访变为串行拜访,打消了传统数据库串行管制的开销
10.redis的并发竞争问题如何解决?
Redis为单过程单线程模式,采纳队列模式将并发拜访变为串行拜访。Redis自身没有锁的概念,Redis对于多个客户端连贯并不存在竞争,然而在Jedis客户端对Redis进行并发拜访时会产生连贯超时、数据转换谬误、阻塞、客户端敞开连贯等问题,这些问题均是因为客户端连贯凌乱造成。对此有2种解决办法:
- 客户端角度,为保障每个客户端间失常有序与Redis进行通信,对连贯进行池化,同时对客户端读写Redis操作采纳外部锁synchronized。
- 服务器角度,利用setnx实现锁。
注:对于第一种,须要应用程序本人解决资源的同步,能够应用的办法比拟艰深,能够应用synchronized也能够应用lock;第二种须要用到Redis的setnx命令,然而须要留神一些问题。
11、redis常见性能问题和解决方案:
1.Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比拟大时对性能影响是十分大的,会间断性暂停服务,所以Master最好不要写内存快照。
2.Master AOF长久化,如果不重写AOF文件,这个长久化形式对性能的影响是最小的,然而AOF文件会一直增大,AOF文件过大会影响Master重启的复原速度。Master最好不要做任何长久化工作,包含内存快照和AOF日志文件,特地是不要启用内存快照做长久化,如果数据比拟要害,某个Slave开启AOF备份数据,策略为每秒同步一次。
3.Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,呈现短暂服务暂停景象。
4.Redis主从复制的性能问题,为了主从复制的速度和连贯的稳定性,Slave和Master最好在同一个局域网内。
12.redis事物的理解CAS(check-and-set 操作实现乐观锁 )?
和泛滥其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是咱们实现事务的基石。置信对有关系型数据库开发教训的开发者而言这一概念并不生疏,即便如此,咱们还是会简要的列出Redis中事务的实现特色:
1). 在事务中的所有命令都将会被串行化的程序执行,事务执行期间,Redis不会再为其它客户端的申请提供任何服务,从而保障了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令依然会被继续执行。
3). 咱们能够通过MULTI命令开启一个事务,有关系型数据库开发教训的人能够将其了解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最初咱们能够通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。
4). 在事务开启之前,如果客户端与服务器之间呈现通信故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是产生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
5). 当应用Append-Only模式时,Redis会通过调用零碎函数write将该事务内的所有写操作在本次调用中全副写入磁盘。然而如果在写入的过程中呈现零碎解体,如电源故障导致的宕机,那么此时兴许只有局部数据被写入到磁盘,而另外一部分数据却曾经失落。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现相似问题,就会立刻退出并给出相应的谬误提醒。此时,咱们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具能够帮忙咱们定位到数据不统一的谬误,并将曾经写入的局部数据进行回滚。修复之后咱们就能够再次重新启动Redis服务器了。
13.WATCH命令和基于CAS的乐观锁?
在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)性能。假如咱们通过WATCH命令在事务执行之前监控了多个Keys,假使在WATCH之后有任何Key的值产生了变动,EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以告诉调用者事务执行失败。例如,咱们再次假如Redis中并未提供incr命令来实现键值的原子性递增,如果要实现该性能,咱们只能自行编写相应的代码。
其伪码如下:
val = GET mykey val = val + 1 SET mykey $val
以上代码只有在单连贯的状况下才能够保障执行后果是正确的,因为如果在同一时刻有多个客户端在同时执行该段代码,那么就会呈现多线程程序中经常出现的一种谬误场景--竞态争用(race condition)。
比方,客户端A和B都在同一时刻读取了mykey的原有值,假如该值为10,尔后两个客户端又均将该值加一后set回Redis服务器,这样就会导致mykey的后果为11,而不是咱们认为的12。为了解决相似的问题,咱们须要借助WATCH命令的帮忙,见如下代码:
WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC
和此前代码不同的是,新代码在获取mykey的值之前先通过WATCH命令监控了该键,尔后又将set命令突围在事务中,这样就能够无效的保障每个连贯在执行EXEC之前,如果以后连贯获取的mykey的值被其它连贯的客户端批改,那么以后连贯的EXEC命令将执行失败。这样调用者在判断返回值后就能够获悉val是否被从新设置胜利。
14.应用过Redis分布式锁么,它是什么回事?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期工夫避免锁遗记了开释。
这时候对方会通知你说你答复得不错,而后接着问如果在setnx之后执行expire之前过程意外crash或者要重启保护了,那会怎么样?
这时候你要给予诧异的反馈:唉,是喔,这个锁就永远得不到开释了。紧接着你须要抓一抓本人得脑袋,故作思考片刻,如同接下来的后果是你被动思考进去的,而后答复:我记得set指令有非常复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的!对方这时会露出笑容,心里开始默念:摁,这小子还不错。
15.如果Redis外面有1亿个key,其中有10w个key是以某个固定的已知的前缀结尾的,如果将它们全副找进去?
应用keys指令能够扫出指定模式的key列表。
对方接着诘问:如果这个redis正在给线上的业务提供服务,那应用keys指令会有什么问题?
这个时候你要答复redis要害的一个个性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会进展,直到指令执行结束,服务能力复原。这个时候能够应用scan指令,scan指令能够无阻塞的提取出指定模式的key列表,然而会有肯定的反复概率,在客户端做一次去重就能够了,然而整体所破费的工夫会比间接用keys指令长。
16.应用过Redis做异步队列么,你是怎么用的?
个别应用list构造作为队列,rpush生产音讯,lpop生产音讯。当lpop没有音讯的时候,要适当sleep一会再重试。
如果对方诘问可不可以不必sleep呢?list还有个指令叫blpop,在没有音讯的时候,它会阻塞住直到音讯到来。
如果对方诘问能不能生产一次生产屡次呢?应用pub/sub主题订阅者模式,能够实现1:N的音讯队列。
如果对方诘问pub/sub有什么毛病?在消费者下线的状况下,生产的音讯会失落,得应用业余的音讯队列如rabbitmq等。
如果对方诘问redis如何实现延时队列?我预计当初你很想把面试官一棒打死如果你手上有一根棒球棍的话,怎么问的这么具体。然而你很克服,而后神态自若的答复道:应用sortedset,拿工夫戳作为score,音讯内容作为key调用zadd来生产音讯,消费者用zrangebyscore指令获取N秒之前的数据轮询进行解决。
到这里,面试官暗地里曾经对你竖起了大拇指。然而他不晓得的是此刻你却竖起了中指,在椅子背地。
17.如果有大量的key须要设置同一时间过期,个别须要留神什么?
如果大量的key过期工夫设置的过于集中,到过期的那个工夫点,redis可能会呈现短暂的卡顿景象。个别须要在工夫上加一个随机值,使得过期工夫扩散一些。
18.Redis如何做长久化的?
bgsave做镜像全量长久化,aof做增量长久化。因为bgsave会消耗较长时间,不够实时,在停机的时候会导致大量失落数据,所以须要aof来配合应用。在redis实例重启时,会应用bgsave长久化文件从新构建内存,再应用aof重放近期的操作指令来实现残缺复原重启之前的状态。
对方诘问那如果忽然机器掉电会怎么?取决于aof日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会失落数据。然而在高性能的要求下每次都sync是不事实的,个别都应用定时sync,比方1s1次,这个时候最多就会失落1s的数据。
对方诘问bgsave的原理是什么?你给出两个词汇就能够了,fork和cow。fork是指redis通过创立子过程来进行bgsave操作,cow指的是copy on write,子过程创立后,父子过程共享数据段,父过程持续提供读写服务,写脏的页面数据会逐步和子过程拆散开来。
19.Pipeline有什么益处,为什么要用pipeline?
能够将屡次IO往返的工夫缩减为一次,前提是pipeline执行的指令之间没有因果相关性。应用redis-benchmark进行压测的时候能够发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。
20.Redis的同步机制理解么?
Redis能够应用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续批改操作记录到内存buffer,待实现后将rdb文件全量同步到复制节点,复制节点承受实现后将rdb镜像加载到内存。加载实现后,再告诉主节点将期间批改的操作记录同步到复制节点进行重放就实现了同步过程。
21.是否应用过Redis集群,集群的原理是什么?
Redis Sentinal着眼于高可用,在master宕机时会主动将slave晋升为master,持续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,应用Cluster进行分片存储。