最近写了一篇自己搭建 redis 集群并在自己项目中使用的文章, 今天早上看别人写的面经发现 redis 在面试中还是比较常问的(我是 python 方向). 所以查阅官方文档以及他人造好的轮子, 总结了一些 redis 面试和学习中你必须掌握的问题. 事无巨细, 不可能囊括到所有内容, 尽量把比较常见的写出来
什么是 Redis?
安装 Redis Redis 的代码遵循 ANSI-C 编写, 可以在所有 POSIX 系统 (如 Linux, *BSD, Mac OS X, Solaris 等) 上安装运行. 而且 Redis 并不依赖任何非标准库, 也没有编译参数必需添加. redis 的安装出奇的简单, 这可能也是他风靡的一个原因, 让人很容易上手. Redis 是一个使用 C 语言写成的, 开源的 key-value 数据库.. 和 Memcached 类似, 它支持存储的 value 类型相对更多, 包括 string(字符串),list(链表),set(集合),zset(sorted set -- 有序集合)和 hash(哈希类型). 这些数据类型都支持 push/pop,add/remove 及取交集并集和差集及更丰富的操作, 而且这些操作都是原子性的. 在此基础上, redis 支持各种不同方式的排序. 与 memcached 一样, 为了保证效率, 数据都是缓存在内存中. 区别的是 redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件, 并且在此基础上实现了 master-slave(主从)同步. 目前, Vmware 在资助着 redis 项目的开发和维护.
Redis 与 Memcached 的区别与比较
1 ,Redis 不仅仅支持简单的 k/v 类型的数据, 同时还提供 list,set,zset,hash 等数据结构的存储. memcache 支持简单的数据类型, String.
2 ,Redis 支持数据的备份, 即 master-slave 模式的数据备份.
3 ,Redis 支持数据的持久化, 可以将内存中的数据保持在磁盘中, 重启的时候可以再次加载进行使用, 而 Memecache 把数据全部存在内存之中
4, redis 的速度比 memcached 快很多
5,Memcached 是多线程, 非阻塞 IO 复用的网络模型; Redis 使用单线程的 IO 复用模型.
如果想要更详细了解的话, 可以查看慕课网上的这篇手记(非常推荐) :脚踏两只船的困惑 - Memcached 与 Redis:www.imooc.com/article/235...
Redis 与 Memcached 的选择
终极策略: 使用 Redis 的 String 类型做的事, 都可以用 Memcached 替换, 以此换取更好的性能提升; 除此以外, 优先考虑 Redis;
使用 redis 有哪些好处?
(1) 速度快, 因为数据存在内存中, 类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O(1)
(2)支持丰富数据类型, 支持 string,list,set,sorted set,hash
(3) 支持事务, 操作都是原子性, 所谓的原子性就是对数据的更改要么全部执行, 要么全部不执行
(4) 丰富的特性: 可用于缓存, 消息, 按 key 设置过期时间, 过期后将会自动删除
Redis 常见数据结构使用场景
1. String
常用命令: set,get,decr,incr,mget 等.
String 数据结构是简单的 key-value 类型, value 其实不仅可以是 String, 也可以是数字. 常规 key-value 缓存应用; 常规计数: 微博数, 粉丝数等.
2.Hash
常用命令: hget,hset,hgetall 等.
Hash 是一个 string 类型的 field 和 value 的映射表, hash 特别适合用于存储对象. 比如我们可以 Hash 数据结构来存储用户信息, 商品信息等等.
举个例子: 最近做的一个电商网站项目的首页就使用了 redis 的 hash 数据结构进行缓存, 因为一个网站的首页访问量是最大的, 所以通常网站的首页可以通过 redis 缓存来提高性能和并发量. 我用 jedis 客户端来连接和操作我搭建的 redis 集群或者单机 redis, 利用 jedis 可以很容易的对 redis 进行相关操作, 总的来说从搭一个简单的集群到实现 redis 作为缓存的整个步骤不难. 感兴趣的可以看我昨天写的这篇文章:
一文轻松搞懂 redis 集群原理及搭建与使用: juejin.im/post/5ad54d...
3.List
常用命令: lpush,rpush,lpop,rpop,lrange 等
list 就是链表, Redis list 的应用场景非常多, 也是 Redis 最重要的数据结构之一, 比如微博的关注列表, 粉丝列表, 最新消息排行等功能都可以用 Redis 的 list 结构来实现.
Redis list 的实现为一个双向链表, 即可以支持反向查找和遍历, 更方便操作, 不过带来了部分额外的内存开销.
4.Set
常用命令: sadd,spop,smembers,sunion 等
set 对外提供的功能与 list 类似是一个列表的功能, 特殊之处在于 set 是可以自动排重的. 当你需要存储一个列表数据, 又不希望出现重复数据时, set 是一个很好的选择, 并且 set 提供了判断某个成员是否在一个 set 集合内的重要接口, 这个也是 list 所不能提供的.
在微博应用中, 可以将一个用户所有的关注人存在一个集合中, 将其所有粉丝存在一个集合. Redis 可以非常方便的实现如共同关注, 共同喜好, 二度好友等功能.
5.Sorted Set
常用命令: zadd,zrange,zrem,zcard 等
和 set 相比, sorted set 增加了一个权重参数 score, 使得集合中的元素能够按 score 进行有序排列.
举例: 在直播系统中, 实时排行信息包含直播间在线用户列表, 各种礼物排行榜, 弹幕消息 (可以理解为按消息维度的消息排行榜) 等信息, 适合使用 Redis 中的 SortedSet 结构进行存储.
MySQL 里有 2000w 数据, Redis 中只存 20w 的数据, 如何保证 Redis 中的数据都是热点数据(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(驱逐): 禁止驱逐数据
Redis 的并发竞争问题如何解决?
Redis 为单进程单线程模式, 采用队列模式将并发访问变为串行访问. Redis 本身没有锁的概念, Redis 对于多个客户端连接并不存在竞争, 但是在 Jedis 客户端对 Redis 进行并发访问时会发生连接超时, 数据转换错误, 阻塞, 客户端关闭连接等问题, 这些问题均是由于客户端连接混乱造成. 对此有 2 种解决方法:
1. 客户端角度, 为保证每个客户端间正常有序与 Redis 进行通信, 对连接进行池化, 同时对客户端读写 Redis 操作采用内部锁 synchronized.
2. 服务器角度, 利用 setnx 实现锁.
注: 对于第一种, 需要应用程序自己处理资源的同步, 可以使用的方法比较通俗, 可以使用 synchronized 也可以使用 lock; 第二种需要用到 Redis 的 setnx 命令, 但是需要注意一些问题.
Redis 数据结构
redis 的作者 antirez 曾称其为一个数据结构服务器(data structures server), 这是一个非常准确的表述, redis 的所有功能就是将数据以其固有的几种结构保存, 并提供给用户操作这几种结构的接口. 我们可以想象我们在各种语言中的那些固有数据类型及其操作.
redis 目前提供四种数据类型: string,list,set 及 zset(sorted set)和 Hash.
string 是最简单的类型, 你可以理解成与 Memcached 一模一个的类型, 一个 key 对应一个 value, 其上支持的操作与 Memcached 的操作类似. 但它的功能更丰富.
list 是一个链表结构, 主要功能是 push,pop, 获取一个范围的所有值等等. 操作中 key 理解为链表的名字.
set 是集合, 和我们数学中的集合概念相似, 对集合的操作有添加删除元素, 有对多个集合求交并差等操作. 操作中 key 理解为集合的名字.
zset 是 set 的一个升级版本, 他在 set 的基础上增加了一个顺序属性, 这一属性在添加修改元素的时候可以指定, 每次指定后, zset 会自动重新按新的值调整顺序. 可以理解了有两列的 mysql 表, 一列存 value, 一列存顺序. 操作中 key 理解为 zset 的名字.
Hash 数据类型允许用户用 Redis 存储对象类型, Hash 数据类型的一个重要优点是, 当你存储的数据对象只有很少几个 key 值时, 数据存储的内存消耗会很小. 更多关于 Hash 数据类型的说明请见: http://code.google.com/p/redis/wiki/Hashes
Redis 数据存储
redis 的存储分为内存存储, 磁盘存储和 log 文件三部分, 配置文件中有三个参数对其进行配置.
save seconds updates,save 配置, 指出在多长时间内, 有多少次更新操作, 就将数据同步到数据文件. 这个可以多个条件配合, 比如默认配置文件中的设置, 就设置了三个条件.
appendonly yes/no ,appendonly 配置, 指出是否在每次更新操作后进行日志记录, 如果不开启, 可能会在断电时导致一段时间内的数据丢失. 因为 redis 本身同步数据文件是按上面的 save 条件来同步的, 所以有的数据会在一段时间内只存在于内存中.
appendfsync no/always/everysec ,appendfsync 配置, no 表示等操作系统进行数据缓存同步到磁盘, always 表示每次更新操作后手动调用 fsync()将数据写到磁盘, everysec 表示每秒同步一次.
来源: http://database.51cto.com/art/201804/571225.htm