今天周末,我在家坐着掐指一算,立刻又要到一年一度的金九银十招聘季了,国内今年上半年受到 YQ 冲击,金三银四泡汤了,这就直接致使不少今年毕业的同窗会和明年毕业的同窗一块儿参加今年下半年的秋招,这个竞争就比较激烈了。java
最近后台有一些朋友给我留言,但愿我能写写招聘相关的内容,毕竟虽说是金九银十,可是不少大公司的校招从 7 、 8 月份就开始了。git
原本是想写点面试技巧和简历技巧的,但我转念一想,你们都是搞技术的,问题的核心仍是技术能力要过关,面试技巧这东西最多只能用做锦上添花,而技术能力过不去,机会送到手里都抓不住。github
再说简历这件事儿,说实话,这个不是短期内能进行弥补的,以前我也有文章分享过我是怎么挑简历的,无外乎先看学校,再参考下实习公司,项目经验这一栏就看心情了。面试
尤为是校招,学校放在第一位,在金矿里淘金子确定要比在沙堆上淘金子效率高得多,固然,若有能有大厂的实习经验,也会成为简历上的一个亮点,能去大厂实习,无论最后什么缘由没有留下,自己已经能够说明不少问题了。redis
MD ,老说实话,实话这么讲下去得罪的人有点多啊。docker
固然哈,若是这两样都没有出彩的地方,就只能在项目经验上下点功夫了,在 Github 上多找找能拿来练手的项目,多动动手,动起来总比成天怨天尤人要来的强。shell
第一份工做能够找的很差,至少先混口饭吃,在工做中再接着学习,夯实本身的基础,作个两三年工做仍是能够换的嘛。数据库
扯远了,强行扯回来,我思来想去仍是用 Redis 开头,就是由于这玩意使用频率以及使用场景太多了,无论什么语言,作什么方向,最终都能和 Redis 扯上关系(emmm,扯不上的我也能强行扯上)。缓存
先简单介绍下我认为的本地最简安装方案,这个方案顺便还实现了跨平台(一开始我并无想到这个,直到我写到这才突然想起来)。安全
Docker + Redis
,Docker 在各个平台都有本身的安装包,请各位同窗去官网自行下载安装,我就很少介绍了, Windows 环境下官网提供了现成的 exe
程序,直接双击一路 next
到底就完。
Docker
安装成功后,无论在哪一个平台都是打开命令行模式,或者找个输入命令的地方,Windows 平台下可使用 CMD
、 PowerShell
或者 Windows Terminal
等工具,其余常见平台包括 MacOS 、 CentOS 或者 Ubuntu ,就不用我多说了吧,若是本身找不到的话,我估摸着我也找不到。
而后用下面三个命令安装 Redis :
# 下载最新版本 Redis 镜像
docker pull redis
# 查看当前镜像
docker images
# 启动命令
docker run --name redis -p 6380:6379 -d redis:latest --requirepass "02wKdSs7NvWT5TdlRyN4dxkXvIDnI1uroh5t"
# 查看运行容器
docker ps
# 进入容器
docker exec -it 013a252b24d6 redis-cli
复制代码
稍微解释下容器的启动命令 --name
是对这个启动的容器进行命名, -p
是指定映射的端口, -d
是指后台运行容器,并返回容器的 ID , --requirepass
是指定了当前启动的 Redis 的访问密码。
而后一个 Redis 就启动好了,咱们进入容器执行几条命令看下是否正常:
# 使用刚才设置的密码登陆
127.0.0.1:6379> auth 02wKdSs7NvWT5TdlRyN4dxkXvIDnI1uroh5t
OK
# 写入一个 key-value
127.0.0.1:6379> set name geekdigging
OK
# 查询 key
127.0.0.1:6379> get name
"geekdigging"
# 查询全部 key
127.0.0.1:6379> keys *
1) "name"
# 删除 key
127.0.0.1:6379> del name
(integer) 1
# 查询全部 key
127.0.0.1:6379> keys *
(empty array)
# 退出
127.0.0.1:6379> quit
复制代码
Redis 入门结束,看完这一段,在简历上写个 Redis 达到了解级别我以为木有任何问题。
既然是从面试出发,那么接下来的内容将会以面试题为导向进行解答,面试题来源于网络或者我本身的杜撰。
如今基本上只要问到缓存,第一个问题基本上都是哪里用了缓存?为啥要用?不用行不行?用了之后会不会有什么风险?
就是单纯的看你背后对缓存有没有思考,仍是说只是单纯的傻乎乎的用。若是没办法给一个还能够的回答,那这个映像分一下就降下来了。
首先哈,咱们在项目中使用 Redis 确定是为了更高的性能和更好的并发。由于传统的关系型数据库已经没法知足如今全部的使用场景了,最多见的秒杀场景,或者查询时的流量洪峰等等,都很容易把传统的 MySQL 或者是 Oracle 打崩,因此引入了缓存中间件 Redis 。
高性能:
假设一个场景,一个请求过来,开始查询数据库,乱七八糟一顿 SQL 操做,查了个结果,结果耗时可能有个 500ms 左右,就好比商城的首页,各类类目的商品信息,各类推荐信息,若是走数据库查询,而且查完了可能接下来好几个小时都没什么变化,那每次请求都走到数据库里,就有点不大合适了。
这时,咱们把查到的结果放到扔到缓存里面,下次再来查询,不走数据库,直接走缓存查询,算上网络消耗可能 10ms 左右就能响应结果了,性能瞬间提高 50 倍。
这就是说,对于一些须要复杂操做耗时查出来的结果,且肯定后面不怎么变化,可是有不少读请求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就行了。
高并发:
MySQL 或者 Oracle 这种关系型数据库压根就不是用来玩并发的,虽然也能够支撑必定的并发,单机 8C16G 的 MySQL 优化基本上极限能撑到 900 左右的 TPS , QPS 极限能撑到 9000 左右。别看这个数字不小,请注意是极限状况,这个状况下 CPU 全都已经爆表,整个服务已经处于不健康的状态。
这时业务场景若是 1s 有 1w 的请求过来,使用一个 MySQL 单机确定直接崩掉,可是若是使用 Redis 缓存,把大量的热点数据放在缓存,由于是走内存的操做,单机轻松支撑几万甚至于几十万的访问。单机的并发承载量是 MySQL 的几十倍。
这个问题其实是在问知识广度,由于如今市面上比较常见的缓存有两个,一个是 Redis 还有一个是 Memcached ,而你们如今基本上都在用 Redis 而逐渐的抛弃掉了 Memcached ,这么作确定是由缘由的,说明 Memcached 是存在明显的短板的。
这两个问题我放在一块儿,其实是一个递进的关系。
首先明确第一点, Redis 是单线程的模型。
而单线程却能拥有很好的性能以及支撑高并发则得益于它自身的另外一套机制「 I/O 多路复用机制」。
Redis 内部使用文件事件处理器( file event handler
) 是单线程的,因此 Redis 才叫作单线程的模型。
它采用 IO 多路复用机制同时监听多个 socket ,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。
尽管多个文件事件操做可能会并发的出现,但 I/O 多路复用系统老是会将全部产生的套接字( Socket ) 放到一个队列里面,而后经过这个队列,以有序、同步、每次一个套接字的方式向文件分派器传送套接字。只有当上一个套接字产生的事件被处理完毕以后, I/O 多路复用系统才会继续向文件分派器传送下一个套接字。
同时,单线程的模型反而带来了另外一个好处是无需频繁的切换上下文,预防了多线程可能产生的竞争问题。
注意: Redis 6.0 以后的版本抛弃了单线程模型这一设计,本来使用单线程运行的 Redis 也开始选择性地使用多线程模型。
前面还在强调 Redis 单线程模型的高效性,如今为何又要引入多线程?这其实说明 Redis 在有些方面,单线程已经不具备优点了。由于读写网络的 Read/Write 系统调用在 Redis 执行期间占用了大部分 CPU 时间,若是把网络读写作成多线程的方式对性能会有很大提高。
Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。 之因此这么设计是不想 Redis 由于多线程而变得复杂,须要去控制 key、lua、事务、LPUSH/LPOP 等等的并发问题。
首先最基础的五种数据结构必须烂熟于心:String 、 Hash 、 List 、 Set 、 SortedSet 。
若是连这五种基础数据结构都记不住的话那就真的须要本身多补补课了。
那么,是否是只有这五种基础数据结构,答案并非,好比在 2.8.9 版本添加的 HyperLogLog ,或者在 3.2 版本提供的 GEO ,又或者在 2.2 版本后新增的 Bitmap 以及在比较近的 5.0 版本新增的 Stream 。
上面这几种种数据结构都不复杂,你们百度下看看文章就能和面试官吹牛皮了。
能答出来后面这几种数据类型,基本上面试官都会对你刮目相看,若是还能接着说出来使用场景以及具体应用,那么这道题基本上你的发挥已经超出了面试官的预期。
这时你还能够接着聊下去,好比你还用过一些 Redis 的第三方模块,这个是 Redis 在 4.0 版本之后提供了插件功能,好比很是经常使用的一个插件布隆过滤器「 BloomFilter 」。
布隆过滤器主要是用来去重使用的,在空间上能够节省 90% 以上,可是稍微有点不精确,有必定的误判几率。能够简单的把布隆过滤器理解成一个不怎么精确的 set 结构,当使用它的 contains 方案判断某个对象是否存在时,它可能会误判。可是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度也能够控制的相对足够精确,只会有小小的误判几率。
除了 「BloomFilter」 ,还有一些比较经常使用的,如: 「RedisSearch」 和 「rediSQL」 。
「RedisSearch」 是一个强大全文检索插件而 「rediSQL」 则是一个使得 Redis 能使用 SQL 作查询的插件。
Redis 数据持久化有两种方式: RDB 和 AOF 。
append-only
的模式写入一个日志文件中,在 Redis 重启的时候,能够经过回放 AOF 日志中的写入指令来从新构建整个数据集。经过 RDB 或者 AOF ,均可以将 Redis 内存中的数据持久化到硬盘上面,若是有须要,还能够将硬盘上的数据备份到其余地方去。
若是 Redis 挂了,这时止不只 Redis 服务挂掉,内存数据丢失,同时产生硬件损坏,硬盘上的数据也丢失或者复发恢复,咱们还能够从其余地方将数据拷贝回来进行数据恢复。
RDB 的优缺点:
save
,另外一个是 bgsave
。 save
命令会阻塞当前的 Redis 进程,直到 RDB 文件建立完毕,在这期间,服务器不能处理任何命令请求。而 bgsave
则会派生出一个子进程,而后由子进程生成 RDB 文件,服务进程不受干扰,继续处理命令请求。AOF 的优缺点:
append-only
模式写入,因此没有任何磁盘寻址的开销,写入性能很是高,并且文件不容易破损,即便文件尾部破损,也很容易修复。rewrite log
的时候,会对其中的指令进行压缩,建立出一份须要恢复数据的最小日志出来。在建立新日志文件的时候,老的日志文件仍是照常写入。当新的 merge
后的日志文件 ready
的时候,再交换新老日志文件便可。两种持久化方式选择: