为什么说Redis是单线程的以及Redis为什么这么快!Redis、面试、缓存、雪崩、分布式锁实现一篇文章搞定!

Redis面试题汇总 什么是Redis? ​Redis 是一个使用 C 语言开发的 非关系型 数据库,Redis 的数据是存在内存中的,读写速度非常快。Redis 经常用来做缓存、分布式锁,消息队列。Redis 支持多种数据类型,事务 持久化、Lua 脚本、多种集群方案。 什么是分布式缓存? ​分布式缓存主要解决的是单机缓存的容量受服务器限制并且无法保存通用的信息。因为,本地缓存只在当前服务里有效,比如如果你部署了两个相同的服务,他们两者之间的缓存数据是无法共享的。主要的技术是 Memcached 和 Redis。 .. 阅读详情

什么是Redis及其重要性?

Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久化的高性能键值对数据库。

Redis的之父是来自意大利的西西里岛的Salvatore Sanfilippo,Github网名antirez,笔者找了作者的一些简要信息并翻译了一下,如图:

从2009年第一个版本起Redis已经走过了10个年头,目前Redis仍然是最流行的key-value型内存数据库的之一。

优秀的开源项目离不开大公司的支持,在2013年5月之前,其开发由VMware赞助,而2013年5月至2015年6月期间,其开发由毕威拓赞助,从2015年6月开始,Redis的开发由Redis Labs赞助。

笔者也使用过一些其他的NoSQL,有的支持的value类型非常单一,因此很多操作都必须在客户端实现,比如value是一个结构化的数据,需要修改其中某个字段就需要整体读出来修改再整体写入,显得很笨重,但是Redis的value支持多种类型,实现了很多操作在服务端就可以完成了,这个对客户端而言非常方便。

当然Redis由于是内存型的数据库,数据量存储量有限而且分布式集群成本也会非常高,因此有很多公司开发了基于SSD的类Redis系统,比如360开发的SSDB、Pika等数据库,但是笔者认为从0到1的难度是大于从1到2的难度的,毋庸置疑Redis是NoSQL中浓墨重彩的一笔,值得我们去深入研究和使用。

Redis提供了Java、C/C++、C#、 PHP 、JavaScript、 Perl 、Object-C、Python、Ruby、Erlang、Golang等多种主流语言的客户端,因此无论使用者是什么语言栈总会找到属于自己的那款客户端,受众非常广。

笔者查了datanyze.com网站看了下Redis和MySQL的最新市场份额和排名对比以及全球Top站点的部署量对比(网站数据2019.12):

可以看到Redis总体份额排名第9并且在全球Top100站点中部署数量与MySQL基本持平,所以Redis还是有一定的江湖地位的。

简述Redis常用的数据结构及其如何实现的?

Redis支持的常用5种数据类型指的是value类型,分别为:字符串String、列表List、哈希Hash、集合Set、有序集合Zset,但是Redis后续又丰富了几种数据类型分别是Bitmaps、HyperLogLogs、GEO。

由于Redis是基于标准C写的,只有最基础的数据类型,因此Redis为了满足对外使用的5种数据类型,开发了属于自己独有的一套基础数据结构,使用这些数据结构来实现5种数据类型。

Redis底层的数据结构包括:简单动态数组SDS、链表、字典、跳跃链表、整数集合、压缩列表、对象。

Redis为了平衡空间和时间效率,针对value的具体类型在底层会采用不同的数据结构来实现,其中哈希表和压缩列表是复用比较多的数据结构,如下图展示了对外数据类型和底层数据结构之间的映射关系:

从图中可以看到ziplist压缩列表可以作为Zset、Set、List三种数据类型的底层实现,看来很强大,压缩列表是一种为了节约内存而开发的且经过特殊编码之后的连续内存块顺序型数据结构,底层结构还是比较复杂的。

Redis的SDS和C中字符串相比有什么优势?

在C语言中使用N+1长度的字符数组来表示字符串,尾部使用'\0'作为结尾标志,对于此种实现无法满足Redis对于安全性、效率、丰富的功能的要求,因此Redis单独封装了SDS简单动态字符串结构。

在理解SDS的优势之前需要先看下SDS的实现细节,找了github最新的src/sds.h的定义看下:

typedef char *sds;/*这个用不到 忽略即可*/struct __attribute__ ((__packed__)) sdshdr5 {    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */    char buf[];};/*不同长度的header 8 16 32 64共4种 都给出了四个成员len:当前使用的空间大小;alloc去掉header和结尾空字符的最大空间大小flags:8位的标记 下面关于SDS_TYPE_x的宏定义只有5种 3bit足够了 5bit没有用buf:这个跟C语言中的字符数组是一样的,从typedef char* sds可以知道就是这样的。buf的最大长度是2^n 其中n为sdshdr的类型,如当选择sdshdr16,buf_max=2^16。*/struct __attribute__ ((__packed__)) sdshdr8 {    uint8_t len; /* used */    uint8_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};struct __attribute__ ((__packed__)) sdshdr16 {    uint16_t len; /* used */    uint16_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};struct __attribute__ ((__packed__)) sdshdr32 {    uint32_t len; /* used */    uint32_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};struct __attribute__ ((__packed__)) sdshdr64 {    uint64_t len; /* used */    uint64_t alloc; /* excluding the header and null terminator */    unsigned char flags; /* 3 lsb of type, 5 unused bits */    char buf[];};#define SDS_TYPE_5  0#define SDS_TYPE_8  1#define SDS_TYPE_16 2#define SDS_TYPE_32 3#define SDS_TYPE_64 4#define SDS_TYPE_MASK 7#define SDS_TYPE_BITS 3复制代码

看了前面的定义,笔者画了个图:

从图中可以知道sds本质分为三部分:header、buf、null结尾符,其中header可以认为是整个sds的指引部分,给定了使用的空间大小、最大分配大小等信息,再用一张网上的图来清晰看下sdshdr8的实例:

在sds.h/sds.c源码中可清楚地看到sds完整的实现细节,本文就不展开了要不然篇幅就过长了,快速进入主题说下sds的优势:

O(1)获取长度: C字符串需要遍历而sds中有len可以直接获得;

防止缓冲区溢出bufferoverflow: 当sds需要对字符串进行修改时,首先借助于len和alloc检查空间是否满足修改所需的要求,如果空间不够的话,SDS会自动扩展空间,避免了像C字符串操作中的覆盖情况;

有效降低内存分配次数:C字符串在涉及增加或者清除操作时会改变底层数组的大小造成重新分配、sds使用了空间预分配和惰性空间释放机制,说白了就是每次在扩展时是成倍的多分配的,在缩容是也是先留着并不正式归还给OS,这两个机制也是比较好理解的;

二进制安全:C语言字符串只能保存ascii码,对于图片、音频等信息无法保存,sds是二进制安全的,写入什么读取就是什么,不做任何过滤和限制;

老规矩上一张黄健宏大神总结好的图:

Redis的字典是如何实现的?简述渐进式rehash过程

字典算是Redis中常用数据类型中的明星成员了,前面说过字典可以基于ziplist和hashtable来实现,我们只讨论基于hashtable实现的原理。

字典是个层次非常明显的数据类型,如图:

有了个大概的概念,我们看下最新的src/dict.h源码定义:

//哈希节点结构typedef struct dictEntry {    void *key;    union {        void *val;        uint64_t u64;        int64_t s64;        double d;    } v;    struct dictEntry *next;} dictEntry;//封装的是字典的操作函数指针typedef struct dictType {    uint64_t (*hashFunction)(const void *key);    void *(*keyDup)(void *privdata, const void *key);    void *(*valDup)(void *privdata, const void *obj);    int (*keyCompare)(void *privdata, const void *key1, const void *key2);    void (*keyDestructor)(void *privdata, void *key);    void (*valDestructor)(void *privdata, void *obj);} dictType;/* This is our hash table structure. Every dictionary has two of this as we * implement incremental rehashing, for the old to the new table. *///哈希表结构 该部分是理解字典的关键typedef struct dictht {    dictEntry **table;    unsigned long size;    unsigned long sizemask;    unsigned long used;} dictht;//字典结构typedef struct dict {    dictType *type;    void *privdata;    dictht ht[2];    long rehashidx; /* rehashing not in progress if rehashidx == -1 */    unsigned long iterators; /* number of iterators currently running */} dict;复制代码

C语言的好处在于定义必须是由最底层向外的,因此我们可以看到一个明显的层次变化,于是笔者又画一图来展现具体的层次概念:

关于dictEntry

dictEntry是哈希表节点,也就是我们存储数据地方,其保护的成员有:key,v,next指针。key保存着键值对中的键,v保存着键值对中的值,值可以是一个指针或者是uint64_t或者是int64_t。next是指向另一个哈希表节点的指针,这个指针可以将多个哈希值相同的键值对连接在一次,以此来解决哈希冲突的问题。

如图为两个冲突的哈希节点的连接关系:

关于dictht

从源码看哈希表包括的成员有table、size、used、sizemask。table是一个数组,数组中的每个元素都是一个指向dictEntry结构的指针, 每个dictEntry结构保存着一个键值对;size 属性记录了哈希表table的大小,而used属性则记录了哈希表目前已有节点的数量。sizemask等于size-1和哈希值计算一个键在table数组的索引,也就是计算index时用到的。

如上图展示了一个大小为4的table中的哈希节点情况,其中k1和k0在index=2发生了哈希冲突,进行开链表存在,本质上是先存储的k0,k1放置是发生冲突为了保证效率直接放在冲突链表的最前面,因为该链表没有尾指针。

关于dict

从源码中看到dict结构体就是字典的定义,包含的成员有type,privdata、ht、rehashidx。其中dictType指针类型的type指向了操作字典的api,理解为函数指针即可,ht是包含2个dictht的数组,也就是字典包含了2个哈希表,rehashidx进行rehash时使用的变量,privdata配合dictType指向的函数作为参数使用,这样就对字典的几个成员有了初步的认识。

字典的哈希算法

//伪码:使用哈希函数,计算键key的哈希值hash = dict->type->hashFunction(key);//伪码:使用哈希表的sizemask和哈希值,计算出在ht[0]或许ht[1]的索引值index = hash & dict->ht[x].sizemask;//源码定义#define dictHashKey(d, key) (d)->type->hashFunction(key)复制代码

redis使用MurmurHash算法计算哈希值,该算法最初由Austin Appleby在2008年发明,MurmurHash算法的无论数据输入情况如何都可以给出随机分布性较好的哈希值并且计算速度非常快,目前有MurmurHash2和MurmurHash3等版本。

普通Rehash重新散列

哈希表保存的键值对数量是动态变化的,为了让哈希表的负载因子维持在一个合理的范围之内,就需要对哈希表进行扩缩容。

扩缩容是通过执行rehash重新散列来完成,对字典的哈希表执行普通rehash的基本步骤为分配空间->逐个迁移->交换哈希表,详细过程如下:

为字典的ht[1]哈希表分配空间,分配的空间大小取决于要执行的操作以及ht[0]当前包含的键值对数量:扩展操作时ht[1]的大小为第一个大于等于ht[0].used*2的2^n;收缩操作时ht[1]的大小为第一个大于等于ht[0].used的2^n ;扩展时比如h[0].used=200,那么需要选择大于400的第一个2的幂,也就是2^9=512。

将保存在ht[0]中的所有键值对重新计算键的哈希值和索引值rehash到ht[1]上;

重复rehash直到ht[0]包含的所有键值对全部迁移到了ht[1]之后释放 ht[0], 将ht[1]设置为 ht[0],并在ht[1]新创建一个空白哈希表, 为下一次rehash做准备。

渐进Rehash过程

Redis的rehash动作并不是一次性完成的,而是分多次、渐进式地完成的,原因在于当哈希表里保存的键值对数量很大时, 一次性将这些键值对全部rehash到ht[1]可能会导致服务器在一段时间内停止服务,这个是无法接受的。

针对这种情况Redis采用了渐进式rehash,过程的详细步骤:

为ht[1]分配空间,这个过程和普通Rehash没有区别;

将rehashidx设置为0,表示rehash工作正式开始,同时这个rehashidx是递增的,从0开始表示从数组第一个元素开始rehash。

在rehash进行期间,每次对字典执行增删改查操作时,顺带将ht[0]哈希表在rehashidx索引上的键值对rehash到 ht[1],完成后将rehashidx加1,指向下一个需要rehash的键值对。

随着字典操作的不断执行,最终ht[0]的所有键值对都会被rehash至ht[1],再将rehashidx属性的值设为-1来表示 rehash操作已完成。

渐进式 rehash的思想在于将rehash键值对所需的计算工作分散到对字典的每个添加、删除、查找和更新操作上,从而避免了集中式rehash而带来的阻塞问题。

看到这里不禁去想这种捎带脚式的rehash会不会导致整个过程非常漫长?如果某个value一直没有操作那么需要扩容时由于一直不用所以影响不大,需要缩容时如果一直不处理可能造成内存浪费,具体的还没来得及研究,先埋个问题吧!

讲讲4.0之前版本的Redis的单线程运行模式

本质上Redis并不是单纯的单线程服务模型,一些辅助工作比如持久化刷盘、惰性删除等任务是由BIO线程来完成的,这里说的单线程主要是说与客户端交互完成命令请求和回复的工作线程。

至于Antirez大佬当时是怎么想的设计为单线程不得而知,只能从几个角度来分析,来确定单线程模型的选择原因。

50道Redis面试题史上最全,以后面试再也不怕问Redis了

1、什么是Redis?

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适合的场景主要局限在较小数据量的高性能操作和运算上。

2、Redis相比memcached有哪些优势?

(1) memcached所有的值均是简单的字符串,redis作为其替代者, 支持更为丰富的数据类型

(2) redis的速度比memcached快很多

(3) redis可以持久化其数据

3、Redis支持哪几种数据类型?

String、List、Set、Sorted Set、hashes

4、Redis主要消耗什么物理资源?

redis是一种基于内存高性能的数据库--- 主要依赖于内存内存。

5、Redis的全称是什么?

Remote Dictionary Server

6、Redis有哪几种数据淘汰策略?

noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。allkeys-random: 回收随机的键使得新添加的数据有空间存放。volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

7、Redis官方为什么不提供Windows版本?

因为目前Linux版本已经相当稳定,而且用户量很大,无需开发windows版本,反而会带来兼容性等问题。

8、一个字符串类型的值能存储最大容量是多少?

512M

9、为什么Redis需要把所有数据放到内存中?

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。

如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

10、Redis集群方案应该怎么做?都有哪些方案?

1.twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通redis无任何区别,设置好它下属的多个redis实例后,使用时在本需要连接redis的地方改为连接twemproxy,它会以一个代理的身份接收请求并使用一致性hash算法,将请求转接到具体redis,将结果再返回twemproxy。使用方式简便(相对redis只需修改连接端口),对旧项目扩展的首选。 问题:twemproxy自身单端口实例的压力,使用一致性hash后,对redis节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。

2.codis,目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在 节点数量改变情况下,旧节点数据可恢复到新hash节点。

3.redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。

4.在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key 进行hash计算,然后去对应的redis实例操作数据。 这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。

11、Redis集群方案什么情况下会导致整个集群不可用?

有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用。

12、MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?

redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

13、Redis有哪些适合的场景?

(1)、会话缓存(Session Cache)最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。

(2)、全页缓存(FPC)除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

(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 WITHSCORESAgora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。

(5)、发布/订阅最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。

14、Redis支持的Java客户端都有哪些?官方推荐用哪个?

Redisson、Jedis、lettuce等等,官方推荐使用Redisson。

15、Redis和Redisson有什么关系?

Redisson是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

16、Jedis与Redisson对比有什么优缺点?

Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

17、Redis如何设置密码及验证密码?

设置密码:config set requirepass 123456授权密码:auth 123456

18、说说Redis哈希槽的概念?

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

19、Redis集群的主从复制模型是怎样的?

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.

20、Redis集群会有写操作丢失吗?为什么?

Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。

21、Redis集群之间是如何复制的?

异步复制

22、Redis集群最大节点个数是多少?

16384个。

23、Redis集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。

24、怎么测试Redis的连通性?

ping

25、Redis中的管道有什么用?

一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。

26、怎么理解Redis事务?

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

27、Redis事务相关的命令有哪几个?

MULTI、EXEC、DISCARD、WATCH ##28、Redis key的过期时间和永久有效分别怎么设置? EXPIRE和PERSIST命令。

29、Redis如何做内存优化?

尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面.

30、Redis回收进程如何工作的?

一个客户端运行了新的命令,添加了新的数据。Redi检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。一个新的命令被执行,等等。所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。**

31、Redis回收使用的是什么算法?

**LRU算法

32、Redis如何做大量数据插入?

Redis2.6开始redis-cli支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。

33、为什么要做Redis分区?

分区可以让Redis管理更大的内存,Redis将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力通过简单地增加计算机得到成倍提升,Redis的网络带宽也会随着计算机和网卡的增加而成倍增长。

34、你知道有哪些Redis分区实现方案?

客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端已经实现了客户端分区。代理分区 意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy查询路由(Query routing) 的意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。

35、Redis分区有什么缺点?

涉及多个key的操作通常不会被支持。例如你不能对两个集合求交集,因为他们可能被存储到不同的Redis实例(实际上这种情况也有办法,但是不能直接使用交集指令)。同时操作多个key,则不能使用Redis事务.分区使用的粒度是key,不能使用一个非常长的排序key存储一个数据集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set).当使用分区的时候,数据处理会非常复杂,例如为了备份你必须从不同的Redis实例和主机同时收集RDB / AOF文件。分区时动态扩容或缩容可能非常复杂。Redis集群在运行时增加或者删除Redis节点,能做到最大程度对用户透明地数据再平衡,但其他一些客户端分区或者代理分区方法则不支持这种特性。然而,有一种预分片的技术也可以较好的解决这个问题。

36、Redis持久化数据和缓存怎么做扩容?

如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。

37、分布式Redis是前期做还是后期规模上来了再做好?为什么?

既然Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有一台服务器,你也可以一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的Redis实例从第一台机器迁移到第二台机器。

38、Twemproxy是什么?

Twemproxy是Twitter维护的(缓存)代理系统,代理Memcached的ASCII协议和Redis协议。它是单线程程序,使用c语言编写,运行起来非常快。它是采用Apache 2.0 license的开源软件。 Twemproxy支持自动分区,如果其代理的其中一个Redis节点不可用时,会自动将该节点排除(这将改变原来的keys-instances的映射关系,所以你应该仅在把Redis当缓存时使用Twemproxy)。 Twemproxy本身不存在单点问题,因为你可以启动多个Twemproxy实例,然后让你的客户端去连接任意一个Twemproxy实例。 Twemproxy是Redis客户端和服务器端的一个中间层,由它来处理分区功能应该不算复杂,并且应该算比较可靠的。

39、支持一致性哈希的客户端有哪些?

Redis-rb、Predis等。

40、Redis与其他key-value存储有什么不同?

Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,应为数据量不能大于硬件内存。在内存数据库方面的另一个优点是, 相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。 同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

41、Redis的内存占用情况怎么样?

给你举个例子: 100万个键值对(键是0到999999值是字符串“hello world”)在我的32位的Mac笔记本上 用了100MB。同样的数据放到一个key里只需要16MB, 这是因为键值有一个很大的开销。 在Memcached上执行也是类似的结果,但是相对Redis的开销要小一点点,因为Redis会记录类型信息引用计数等等。当然,大键值对时两者的比例要好很多。64位的系统比32位的需要更多的内存开销,尤其是键值对都较小时,这是因为64位的系统里指针占用了8个字节。 但是,当然,64位系统支持更大的内存,所以为了运行大型的Redis服务器或多或少的需要使用64位的系统。

42、都有哪些办法可以降低Redis的内存使用情况呢?

如果你使用的是32位的Redis实例,可以好好利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。

##43、查看Redis使用情况及状态信息用什么命令?info44、Redis的内存用完了会发生什么? 如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回。)或者你可以将Redis当缓存来使用配置淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。## 45、Redis是单线程的,如何提高多核CPU的利用率? 可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU,你可以考虑一下分片(shard)。

46、一个Redis实例最多能存放多少的keys?

List、Set、Sorted Set他们最多能存放多少元素?理论上Redis可以处理多达232的keys,并且在实际中进行了测试,每个实例至少存放了2亿5千万的keys。我们正在测试一些较大的值。任何list、set、和sorted set都可以放232个元素。换句话说,Redis的存储极限是系统中的可用内存值。

47、Redis常见性能问题和解决方案?

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件 (2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次 (3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内 (4) 尽量避免在压力很大的主库上增加从库 (5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

48、Redis提供了哪几种持久化方式?

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始。

49、如何选择合适的持久化方式?

一般来说, 如果想达到足以媲美PostgreSQL的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。有很多用户都只使用AOF持久化,但并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外, 使用RDB还可以避免之前提到的AOF程序的bug。

50、修改配置不重启Redis会实时生效吗?

针对运行实例,有许多配置选项可以通过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。 从 Redis 2.2 开始,可以从 AOF 切换到 RDB 的快照持久性或其他方式而不需要重启 Redis。检索 ‘CONFIG GET *’ 命令获取更多信息。但偶尔重新启动是必须的,如为升级 Redis 程序到新的版本,或者当你需要修改某些目前 CONFIG 命令还不支持的配置参数的时候。

更多面试题以及答案我以文档的形式保存,面试不懂?赶紧来领取面试资料多刷题吧!

面试资料获取方式:添加小助手VX:xuanwo008

Nginx面试专题

Nginx参考答案

 

Netty的面试专题

Netty参考答案

 

Redis面试专题

Redis参考答案

 

Dubbo面试专题

Dubbo参考答案

 

ZooKeeper面试专题 添加小助手VX:xuanwo008

 

 

[每周一更]-(第124期):模拟面试|缓存面试思路解析 最少使用策略。缓存会优先淘汰访问频率最低的数据,即被访问次数最少的元素。:最近最少使用策略。优先淘汰一段时间内没有被访问的数据,即最近最少使用的元素。示例代码展示一个简单的 LRU 缓存,可以使用 Python 的python复制代码from collections import OrderedDictreturn -1self.cache.move_to_end(key) # 将访问的 key 移到末尾self.cache.popitem(last=False) # 删除最旧的# 使用示例。 阅读详情

相关推荐

缓存之redis面试题

文章目录1、redis和memcached什么区别?为什么高并发下有时单线程的redis比多线程的memcached效率要高?2、redis主从复制如何实现的?redis的集群模式如何实现?redis的key是如何寻址的?3、使用redis如何设计分布式锁?说一下实现思路?使用zk可以吗?如何实现?这两种有什么区别?4、知道redis的持久化吗?底层如何实现的?有什么优点缺点?5、redis过期策略都有哪些?LRU算法知道吗?写一下java代码实现?6、缓存穿透、缓存击穿、缓存雪崩解决方案?7、在选择缓存时

用文字记录下每一个瞬间的感动和每一次思考的火花 18万+

java面试题

java面试题

m0_57472151的博客 204

Python爬虫实战:5分钟搞定政府网站公开数据抓取(附完整代码)

本文详细介绍了如何使用Python爬虫快速抓取政府网站公开数据,包括环境配置、网站结构分析、请求头构建、数据处理与存储等关键步骤。通过实战案例和完整代码,帮助开发者高效获取结构化数据,适用于数据分析、市场研究等场景。

weixin_29057065的博客 941

基于Lucene查询原理分析Elasticsearch的性能

前言 Elasticsearch是一个很火的分布式搜索系统,提供了非常强大而且易用的查询和分析能力,包括全文索引、模糊查询、多条件组合查询、地理位置查询等等,而且具有一定的分析聚合能力。因为其查询场景非常丰富,所以如果泛泛的分析其查询性能是一个非常复杂的事情,而且除了场景之外,还有很多影响因素,包括机型、参数配置、集群规模等等。本文主要是针对几种主要的查询场景,从查询原理的角度分析这个场景下的查...

xuciyisheng的博客 1023

华为交换机与思科/华三设备LACP对接实战:手把手教你配置链路聚合

本文详细解析了华为交换机与思科、华三设备间的LACP链路聚合配置实战,涵盖核心原理、配置步骤及排错技巧。通过对比不同厂商的实现差异,提供可落地的跨厂商对接方案,助力企业网络工程师高效部署高可靠性链路聚合。

weixin_30836759的博客 426

pyecharts可视化图表-tree:从入门到精通

本文系统介绍了树图(Tree Chart)的可视化技巧,包含基础实现、方向定制和环形布局等实例。树图能清晰展示层次结构数据,适用于组织架构、文件系统等场景。教程详细解析了pyecharts树图的核心配置项,包括数据准备、方向设置(下上、右左)和样式定制,并提供了完整代码示例。通过本指南,读者可快速掌握专业树图的构建方法,实现复杂层次数据的可视化呈现。

大数据内容个人总结与分享 1970

2020-04-20 RedissonRedLock的redis分布式锁

学习资料:https://www.jianshu.com/p/f302aa345ca8 今天工作上遇到需要用分布式锁的一个问题,然后当然不是自己写一个分布式锁,公司有中间件可以直接用(封装好的),用起来分分钟,但是不知道其原理,那就不行了,所以根据源码一直走下去和看别人博客,了解了下RedissonRedLock的原理。 查看人家的源码,学习别人的写法是很有必要的。公司的源码就不贴出来了。记录...

hq091117的博客 647

Field-Oriented Control (FOC) 矢量控制 磁场定向控制

Field-Oriented Control (FOC) 磁场定向控制(FOC),也称为矢量控制,是一种用于控制永磁同步电动机(PMSM)和交流感应电动机(ACIM)的技术。 FOC在整个扭矩和速度范围内都具有良好的控制能力。 FOC的实现需要将定子电流从固定参考系转换为转子磁通参考系(也称为d-q参考系)。 速度控制和转矩控制是FOC最常用的控制模式。位置控制模式不太常见。大多数牵引应用使用转矩控制模式,在该模式下,电动机控制系统遵循参考转矩值。在速度控制模式下,电机控制器遵循参考速度值,并生成用于形成内

>>> 1万+

java学习系列 redis详知详解

想详细学习一下redis系列的知识,特此记录。 通过以下整理 https://blog.youkuaiyun.com/Design407/article/details/103242874 https://zhuanlan.zhihu.com/p/89620471 https://blog.youkuaiyun.com/xiaozhegaa/article/details/80692017 1、redis是什么 Redi...

不想做咸鱼的咸鱼的专栏 855

ICM42670 IIC驱动与卡尔曼+四元数姿态解算实战

惯性测量单元(IMU)是运动控制、无人机飞控和AR/VR设备的核心传感器,其数据质量直接取决于底层硬件通信可靠性与姿态估计算法鲁棒性。IIC(I²C)作为嵌入式系统中最常用的低速串行总线,需满足确定性时序、抗干扰与实时采样要求;卡尔曼滤波则通过状态建模与噪声协方差优化,在动态环境中融合加速度计与陀螺仪数据;而四元数因其无万向锁、插值平滑、旋转合成高效等优势,成为高精度姿态解算的数学基础。本文以高性能六轴IMU ICM42670为载体,深入剖析IIC硬件设计要点、裸机级驱动优化、Allan方差驱动的卡尔曼参数

weixin_27076351的博客 257

Minio HTTPS证书配置实战:从申请到部署全流程

本文详细介绍了Minio HTTPS证书配置的全流程,从申请到部署,确保对象存储服务的安全性。内容包括证书类型选择、文件处理、服务配置调整及常见问题解决,帮助用户在生产环境中快速实现HTTPS加密传输,提升数据安全。

weixin_42638178的博客 433

Redis持久化数据和缓存怎么做扩容?

如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。 如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系,节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据再平衡的一套系统,而当前只有Redis集群可以做到这样。 ...

yanganbang880605的博客 1621

【WLAN】【调试】如何使用Wireshark分析加密的WiFi数据包

- 当配置网卡为monitor 模式的情况下,可以使用 wireshark来抓取空口报文; - 如果WiFi采用非Open加密方式,则从报文中仅能分析到 802.11协议层,更底层(如DHCP、ICMP、TCP等)被加密,此时可以使用 wireshark 来完成解密。 - 解密之后,可以通过icmp、tcp等关键词过滤报文。

一介草民,只为生活。 2986

为什么说Redis是单线程的以及Redis为什么这么快!Redis、面试、缓存、雪崩、分布式锁实现一篇文章搞定

其它面试题(springboot、mybatis、并发、java中高级面试总结等)网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2401_84434975的博客 1099

1.1 了解Spring框架 -《SSM深入解析与项目实战》

文章目录第1篇 基础概念第1章 谈谈SSM框架和Redis1.1 了解Spring框架1.1.1 如何学习Spring1.1.2 IoC(Inversion of Control 控制反转)1.1.3 AOP(Aspect Oriented Programing面向切面编程) 项目中所有的源码都可以在此链接的仓库中找到:https://github.com/chenhaoxiang/uifuture-ssm 本章非常形象的介绍了Springn中最核心的两个概念,IoC和AOP,使用了现实中的例子

谙忆-陈浩翔 2136

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

为什么说Redis是单线程的以及Redis为什么这么快!Redis、面试、缓存、雪崩、分布式锁实现一篇文章搞定!...

一、前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”、什么是“热数据和冷数据”,复杂一点的会问到缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题,这些看似不常见的概念,都与我们的缓存服务器相关,一般常用的缓存服务器有Redis、Memcached等,而笔者目前最常用的也只有Redis这一种。 如果你...

Java架构技术交流 858

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

redis实现轮询算法_为什么说Redis是单线程的以及Redis为什么这么快!Redis、面试、缓存、雪崩、分布式锁实现一篇文章搞定!...

一、前言近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”、什么是“热数据和冷数据”,复杂一点的会问到缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题,这些看似不常见的概念,都与我们的缓存服务器相关,一般常用的缓存服务器有Redis、Memcached等,而笔者目前最常用的也只有Redis这一种。如果你在以前面试的时候还没有遇到过面试官问你《为什么说Redis...

weixin_39763033的博客 353

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Java 面试篇-Redis 专题(Redis 常见的面试专题:缓存击穿、缓存雪崩、缓存穿透、什么是布隆过滤器、什么是延时双删、持久化的方式、Redis 分布式锁、I/O 多路复用等等)

缓存穿透是指查询一个一定不存在的数据,由于存储层查不到数据,因此不写入到缓存中,这将导致这个不存在的数据每次请求都要到 DB 去查询,可能导致 DB 挂掉。这种情况大概率是遭到了攻击。解决方案的话,一般来说有两种:第一种是缓存空对象;第二种是使用布隆过滤器来解决。布隆过滤器主要是用来检索一个元素是否在一个集合中。当时使用的是 Redisson 实现的布隆过滤器。它的底层原理是,先是初始化一个比较大的数组,里面存放的是二进制 0 或 1。

小扳手 8783

Redis核心技术深度解析:从单线程模型到分布式锁设计|2023面试必备+实战指南

本文系统剖析Redis核心工作机制与高频面试要点,涵盖:单线程高性能实现原理、渐进式ReHash黑科技、多线程IO演进路线、缓存穿透/雪崩/击穿终极解决方案、分布式锁Redisson看门狗机制、Cluster集群高可用方案等核心技术。通过源码级解析+大厂实战案例,深度讲解Redis在亿级流量场景下的缓存设计范式与性能调优策略,特别适合中高级开发者突破技术瓶颈。附赠:布隆过滤器实现原理、Pipeline性能优化技巧、热key探测方案等进阶内容,助你构建完整的Redis知识体系。

Zyw907155124的博客 2万+

面试篇:Redis

缓存穿透是指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到 DB 去查询,可能导致 DB 挂掉。这种情况大概率是遭到了攻击。解决方案的话,我们通常都会用布隆过滤器来解决它。布隆过滤器主要是用于检索一个元素是否在一个集合中。我们当时使用的是redisson实现的布隆过滤器。它的底层主要是先去初始化一个比较大数组,里面存放的二进制0或1。

JackMa的博客 9440

Redis面试篇

介绍了Redis面试相关内容,包括缓存、持久性、数据过期、内存淘汰、主从复制、主从同步、哨兵、分片集群等方面

weixin_49429082的博客 1351

一篇文章搞定java八股文面试题 (黑马笔记)Redis篇

前提概念重点:学习redis和mysql这些数据库场景之前,我们必须知道,redis是基于内存的非关系型数据库,每秒处理的数据可以达到10w-100w,而即使是优化很好的mysql,一秒钟也只能处理几千次到几万次的数据,关键在于redis没有IO操作,只是简单缓存数据,大部分时间不用考虑很复杂的事情,而mysql为了保证数据的一致性, 会加入锁和事务,让数据排队,然后还要读磁盘,所以较慢。(Remote Dictionary Server,远程字典服务)是一款。

zz143172的博客 1822

牛客面试系列之Redis

Redis常见面试题

m0_60264772的博客 3889

java面试八股文之------Redis夺命连环25问

redis面试题看这里-图文并茂带你起飞

初心不忘、始终方得 6573

一篇文章透彻Redis及面试高频题!

回答时结合具体场景(如“我用 Redis 的 ZSet 实现过排行榜”),展现实际经验。

2303_80799640的博客 1077
上一篇: 连夜整理了142页Spring知识点总离线文档(源码笔记+思维导图)
下一篇: Java 程序员如何使用 Shiro 框架
java架构那些事
博客等级 码龄6年 6粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值