总是写严肃的东西,也写点轻松愉快的,谈谈Redis,总结下自己面试以及网上的一些Redis面试经验。
笔者博客:https://charpty.com
一进门便是游戏开始了
我总感觉面试和狼人杀游戏差不多,一拿到牌游戏就开了,一样的,当面试官踏进门游戏便开始了。
咱们假设只是问Redis
相关的哈。
不知道许多面试官有没有中招,第一题总是Redis有几种数据类型,D:–
Redis有几种数据类型呢
第一个问题往往是最重要的,因为它决定了后面要问你什么样的问题,就和你冲排位似的,前几把是定级赛,定级时给你个青铜段位,想要爬上去可就难了
是我的话,肯定要答全啊(装X脸)。都知道的有String
、List
、Set
、Sorted Set
、Hash
。
不过这么回答的话,看样子只能拿30分了,接下来就是问问你会不会几个命令之类的了。
在我看来分为两类结构,一个是Redis
自带的数据结构.
- 二进制安全的String:有点扯,但是面试官肯定在想你指的啥了.
- 双向链表、跳表、压缩表简称列表:这时面试官觉得有点意思了.
- 有序集合:这下好了这家伙使用上面的结构实现的
- 哈希表:和JDK1.7的实现类似
- 集合:利用哈希表实现
答了这5个,面试官的心窝子暖了,总算来了个稍微懂点的兄弟了,可是吧还不够,还不够完美,这5个是Redis
基础的数据结构,还有更加高级的。
- 位图bitmap或者bit arrays:把本地的位图功能搬到了分布式环境中
- HyperLogLog:超级计数器,用来做大量元素计数统计的
- Geo地理位置:这可是PostgreSQL、mongo等db的拿手好戏,redis也做了支持
- 发布订阅:和楼上这位一样,是不是属于数据结构各有看法,更有说Pipeline也是
没了吧,真没了,Redis
内部的数据结构真的就是这些了,这时候面试官流着口水看着你,当然他不是要吃掉你,他是希望你继续说下去。
在Redis
官网右边倒数第二个选项卡Modules
,Redis
本身各命令时也就是通过模块注入的方式实现的,所以它可以灵活的支持其他人编写模块嵌入到Redis
中。
既然是自己编写模块,那这数据结构就说不清楚了,随你自己造,当然不需要你全部列出来,说几个出名的就行,Redis
也把写的好的模块放到了官网上(写的好的都是他们自己人。。。)。
- neural-redis:这个厉害了,
Redis
作者自己实现的神经网络,当作是Redis
的一种数据类型 - ReJSON:A JSON data type for Redis你懂就行
- rebloom:布隆过滤器
- Redis Graph:这老哥就不是整个数据结构那么简单了,他整了一个数据库,一大堆数据结构
因为Redis
扩展的模块实在很多,就不一一列举,自己玩过写过module
会有体会。
好了回答到这里,第一个问题就算是回答清楚了,厉害的面试官应该挺开心的,对你说:你小子值得再问100个问题!。。。。差点想打他,忍住嘛毕竟咱是来找工作的
说一说Redis的单线程模型
得,有了上面的回答,一般的set、get问题也懒得问了,Redis
最著名的莫如这个单线程模型,不问才是见了鬼了。
那Redis
的单线程模型怎么来的呢,其实是这样的,作者antirez
学艺不精,Linux
的pthread
编程模型对他来说太困难了,算了,咱就搞个单线程的算了,别和说什么多核并发、同步运行、异步非阻塞,老夫敲代码就是一把梭。
当然这不是真的,Redis
单线程模型就是为了快,为了简单,是的没错,简单了就会很快,就好比为什么用越多的框架性能就越低,因为复杂了,为了扩展性、使用便利不得不作出很多性能牺牲。
单线程模型最大的好处就是防止了线程上下文切换带来的消耗,Redis
使用的非阻塞IO、数据结构都量身定制,在实际环境中Redis
最高可以支持百万级的QPS(这牛皮吹大了),Redis
作为一个内存数据库,主要在于对内存的操作,CPU绝不会成为瓶颈。
你要实在是可惜你的CPU浪费了,你可以在一台机器上装Redis
啊,。。。。我竟无言以对
前面回答完了,面试官只能是点点头,没有露出诡异的微笑,那还有什么要说的呢。。其实还很多,任何架构总是配合具体的业务来设计的,既然选择了单线程一定要有各种配合,首先思考几个问题。
1、这么多客户端连接Redis
服务器,随时每个连接都有请求,一个线程面对这么多连接怎么应付的过来呢
2、在Redis
中备份数据非常耗时的操作怎么做的呢
3、大键删除、过期数据扫描、Rehash、大量连接检查保活是怎么做的呢
4、单线程下多个客户端的事物型请求怎么处理
对啊,你倒是单线程了,你倒是简单了,编程也简单,速度也快了,看代码也爽了。那这些问题怎么解决呢,单线程模型咱说了,牛皮也吹了,关键在于在于在单线程模型下巧妙的解决了这些问题,这才是Redis
单线程模型的真正精髓,不然解决不了问题早就改了。
多线程提供了除了利用多核以外很多的好处:防止阻塞、更好的编程模型,要在单线程模型下结合业务也拥有这些特性则需要巧妙的设计(我想Redis
有些设计真的不是用巧妙形容的,简直是粗暴),场景非常多,挑上述几个典型的说说。
网络问题则是利用Linux
提供的多路复用IO,Unix
种种好处,也是没有开发```Windows````版本原因之一
粗暴的来了,数据备份操作则是通过fork子进程来完成
大键删除、过期数据扫描、Rehash等操作,Redis
则都是将其逻辑切分,每次只完成一部分,每次只占用一小段时间的CPU,分多次完成。这里涉及到一个很重要的东西,就是Redis
对CPU时间片的分配,这个分配模型贯穿了众多耗时操作,也是eventLoop非常重要的一环。
事务啊,更粗暴,不支持,Redis
事务并不是完整的ACID,当然可以顺便把几种实现一次类原子的执行命令的场景,multi、pipeline、lua script、面试官应该满意了。
当然最后还要得瑟一下,咳咳、Redis
的单线程模型也要看怎么理解了哈,虽然存在并发、并行行为,但是它表现的像串行执行一般即可呀。 Redis
4.0开始也逐渐增加了许多并发编程,总的目的都是提高各种各样场景下的运行性能(实际场景总是复杂的,实验室的QPS不能作数)。
Redis安全
很多同学对Redis各方面都很了解了,但是这个问题绝不仅仅关于Redis
,即使很多工作多年的同学都容易忽略安全这个问题,安全无小事!
一般会问你们一般都做了哪些工作来保证Redis安全,这个问题比较难回答,涉及到了宏观的架构安全,但是可以先从小事入手。
- 高强度密码:Redis服务器绝不裸奔
- 危险命令重命名:对于刷库、config、save等命令进行重命名,防止误操作和恶意攻击
- 指定网卡bind:不要在所有网卡监听,也最好不要用默认端口,在不确定的网络环境中造成巨大隐患
- 防火墙与IP白名单:和数据库一样严格
- 定期数据备份:安全当然包括数据不丢失
- 非root启动:之前的Redis save获得root权限的场景还历历在目
- 定期审计:定期检查client list和慢日志,查看是否有monitor等
- 手动清理不合规数据:大键、大lua脚本、永留存数据,要有监控大盘
- 代码安全:要有统一的公共组件代码来访问Redis,避免程序员误操作
回答了这些,我想至少面试官会认为你有安全意识了,这个问题在他心中你已经通过了。但是想让他眼前一亮,你还得知道Redis的安全模型。
安全模型涉及的内容不少,简单的有Protected mode
,这个在早前版本就有,一启动只能localhost访问,是不是很郁闷。
数据加密,Redis不支持数据传输加密,但是可以借助其他工具实现安全传输如spiped。
特殊算法碰撞,Redis的数据结构不多,比如Hash类型,如果把所有的元算都放到一个桶里,那岂不是整个Redis都卡了,关键Redis大量使用哈希表存储各种系统运行、时间、方法引用等信息。Redis为了防止这种情况使用了per-execution pseudo-random
种子,使得元素存储带有一定的随机性,避免了相同数据落桶密集的问题。
Lua脚本评估,eval()这个东西在任何时候都是个麻烦,里面的参数就是代码,可以想见一不留神就危险了,虽然Redis没有对String做escape,但是通信协议有规定prefixed-length strings
来保障安全,再说说RESP
通信协议,面试官会刮目相看。
说到这里,面试官已经对你称赞不绝了,就差一步就可以录取你了。
Redis集群概述
好吧,最后一题,这时对面试官而言,问完这个问题怎么给你定级别才是问题。
一般会问,说一说Redis集群的通信方式、Redis如何做数据路由等等。
其实前面的问题都不是那么关键,这个才是真正展现你水平的时候,Redis集群是生产环境常用的场景。
这里面涉及的东西就太多了,分布式理论,一致性协议、数据分区与路由、集群通信协议、故障转移等等数不尽数,我想绝大多数人都只能尽力而为,但是知道几个大块和回答方向,谈起来也会从容许多。
分布式理论像CAP、BASE等一大堆东西是个大学问只能自己慢慢看和体会,一致性协议像Paxos、Raft、ZAB等等倒是可以自己跟着推导推导,手写尝试实现。这两点看着讲吧,别不懂装懂就行,面试官都不是吃素的,很容易拆穿你。
Redis的数据分区与路由以及集群通信机制则是必须要掌握的
Redis采用slot槽进行分区,各个数据通过一致性哈希分配到每个节点,当然他问你一致性哈希你也可以和他讲讲,一共映射有16384个槽,为什么呢2^14次方,因为考虑到最多节点数和集群节点map大小问题。
分区了当然也会限制很多的操作不能进行,可以讲一讲
Redis集群的路由也简单,计算槽 -> 槽节点查找,首先是通过hash函数计算位置,crc16() & 16383得到槽的位置,为什么还要再找槽呢,因为是集群就涉及到节点下线、数据迁移等问题,前一秒master1还在线,下一秒slave1就要接替站岗了,集群node map都还来不及更新。
Redis找槽主要逻辑就是先按map找,找到了发现不是,咱就随机换一个节点接着找呗,直到找到为止,这种方法虽然耗资源,但是简单!这和单线程模型如出一辙,都是作者偷懒的表现,哈哈。。。。
另外还要注意讲清楚ASK响应,如何实现智能客户端等等
接下来就是说说节点之间的通信了,通信协议采用的Gossip
协议,单个节点与节点之间不断的交换消息,最终信息扩展到整个集群,整个通信是在另外单独的端口上进行的,有ping、meet、fail等多种消息。
既然是一对一,那么选择谁进行通信则是关键,否则老是和同一个节点说话,那么消息就很难传播到整个集群,Redis大量的工作就在此处了,通过记录与节点的通信时间,随机选择,槽信息更新频率等情况对通信节点进行选择。
最后这一个问题是展现本事的时候,不大可能是单纯的回答,中间多少穿插着就细节展开问题,这时就靠兵来将挡水来土淹了,当然回答这些问题不是关键,重要的是真的理解它的原理。
好了,面试要差不多,面试官问你大概期待的薪资待遇等等了,突然,你露出诡异的笑容,你知道自己过了,轻轻的说一句:我是来锻炼下水平的,再见!D#–