老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数

2020-07-19  本文已影响0人  1bb5cb194ba3
image

引言

今天周末,我在家坐着掐指一算,马上又要到一年一度的金九银十招聘季了,国内今年上半年受到 YQ 冲击,金三银四泡汤了,这就直接导致很多今年毕业的同学会和明年毕业的同学一起参加今年下半年的秋招,这个竞争就比较激烈了。

最近后台有一些朋友给我留言,希望我能写写招聘相关的内容,毕竟虽然说是金九银十,但是很多大公司的校招从 7 、 8 月份就开始了。

本来是想写点面试技巧和简历技巧的,但我转念一想,大家都是搞技术的,问题的核心还是技术能力要过关,面试技巧这东西最多只能用作锦上添花,而技术能力过不去,机会送到手里都抓不住。

再说简历这件事儿,说实话,这个不是短时间内能进行弥补的,之前我也有文章分享过我是怎么挑简历的,无外乎先看学校,再参考下实习公司,项目经验这一栏就看心情了。

尤其是校招,学校放在第一位,在金矿里淘金子肯定要比在沙堆上淘金子效率高得多,当然,如有能有大厂的实习经验,也会成为简历上的一个亮点,能去大厂实习,不管最后什么原因没有留下,本身已经可以说明很多问题了。

MD ,老说实话,实话这么讲下去得罪的人有点多啊。

当然哈,如果这两样都没有出彩的地方,就只能在项目经验上下点功夫了,在 Github 上多找找能拿来练手的项目,多动动手,动起来总比整天怨天尤人要来的强。

第一份工作可以找的不好,至少先混口饭吃,在工作中再接着学习,夯实自己的基础,做个两三年工作还是可以换的嘛。

Redis 安装

扯远了,强行扯回来,我思来想去还是用 Redis 开头,就是因为这玩意使用频率以及使用场景太多了,不管什么语言,做什么方向,最终都能和 Redis 扯上关系(emmm,扯不上的我也能强行扯上)。

先简单介绍下我认为的本地最简安装方案,这个方案顺便还实现了跨平台(一开始我并没有想到这个,直到我写到这才忽然想起来)。

Docker + Redis ,Docker 在各个平台都有自己的安装包,请各位同学去官网自行下载安装,我就不多介绍了, Windows 环境下官网提供了现成的 exe 程序,直接双击一路 next 到底就完。

Docker 安装成功后,不管在哪个平台都是打开命令行模式,或者找个输入命令的地方,Windows 平台下可以使用 CMDPowerShell 或者 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 ?

现在基本上只要问到缓存,第一个问题基本上都是哪里用了缓存?为啥要用?不用行不行?用了以后会不会有什么风险?

就是单纯的看你背后对缓存有没有思考,还是说只是单纯的傻乎乎的用。如果没办法给一个还可以的回答,那这个映像分一下就降下来了。

首先哈,我们在项目中使用 Redis 肯定是为了更高的性能和更好的并发。因为传统的关系型数据库已经无法满足现在所有的使用场景了,最常见的秒杀场景,或者查询时的流量洪峰等等,都很容易把传统的 MySQL 或者是 Oracle 打崩,所以引入了缓存中间件 Redis 。

高性能:

假设一个场景,一个请求过来,开始查询数据库,乱七八糟一顿 SQL 操作,查了个结果,结果耗时可能有个 500ms 左右,就比如商城的首页,各种类目的商品信息,各种推荐信息,如果走数据库查询,并且查完了可能接下来好几个小时都没什么变化,那每次请求都走到数据库里,就有点不大合适了。

这时,我们把查到的结果放到扔到缓存里面,下次再来查询,不走数据库,直接走缓存查询,算上网络消耗可能 10ms 左右就能响应结果了,性能瞬间提升 50 倍。

这就是说,对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就好了。

高并发:

MySQL 或者 Oracle 这种关系型数据库压根就不是用来玩并发的,虽然也可以支撑一定的并发,单机 8C16G 的 MySQL 优化基本上极限能撑到 900 左右的 TPS , QPS 极限能撑到 9000 左右。别看这个数字不小,请注意是极限情况,这个情况下 CPU 全都已经爆表,整个服务已经处于不健康的状态。

这时业务场景如果 1s 有 1w 的请求过来,使用一个 MySQL 单机肯定直接崩掉,但是如果使用 Redis 缓存,把大量的热点数据放在缓存,因为是走内存的操作,单机轻松支撑几万甚至于几十万的访问。单机的并发承载量是 MySQL 的几十倍。

除了 Redis 还有考虑过其他缓存么?

这个问题实际上是在问知识广度,因为现在市面上比较常见的缓存有两个,一个是 Redis 还有一个是 Memcached ,而大家现在基本上都在用 Redis 而逐渐的抛弃掉了 Memcached ,这么做肯定是由原因的,说明 Memcached 是存在明显的短板的。

  1. Redis 相比较 Memcached 而言,它支持更复杂的数据结构,能支持更丰富的数据操作。
  2. Redis 在 3.x 版本以后,原生支持了集群模式,而 Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据。
  3. Redis 拥有更加丰富的附加功能,如:pub/sub 功能, Lua 脚本支持, 序列化支持等等。
  4. Redis 支持数据持久化, RDB 和 AOF。

Redis 的线程模型是什么?为什么 Redis 单线程却能支撑高并发?

这两个问题我放在一起,实际上是一个递进的关系。

首先明确第一点, Redis 是单线程的模型。

而单线程却能拥有很好的性能以及支撑高并发则得益于它自身的另一套机制「 I/O 多路复用机制」。

Redis 内部使用文件事件处理器( file event handler ) 是单线程的,所以 Redis 才叫做单线程的模型。

它采用 IO 多路复用机制同时监听多个 socket ,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。

image

尽管多个文件事件操作可能会并发的出现,但 I/O 多路复用系统总是会将所有产生的套接字( Socket ) 放到一个队列里面,然后通过这个队列,以有序、同步、每次一个套接字的方式向文件分派器传送套接字。只有当上一个套接字产生的事件被处理完毕之后, I/O 多路复用系统才会继续向文件分派器传送下一个套接字。

同时,单线程的模型反而带来了另一个好处是无需频繁的切换上下文,预防了多线程可能产生的竞争问题。

注意: Redis 6.0 之后的版本抛弃了单线程模型这一设计,原本使用单线程运行的 Redis 也开始选择性地使用多线程模型。

前面还在强调 Redis 单线程模型的高效性,现在为什么又要引入多线程?这其实说明 Redis 在有些方面,单线程已经不具有优势了。因为读写网络的 Read/Write 系统调用在 Redis 执行期间占用了大部分 CPU 时间,如果把网络读写做成多线程的方式对性能会有很大提升。

Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。 之所以这么设计是不想 Redis 因为多线程而变得复杂,需要去控制 key、lua、事务、LPUSH/LPOP 等等的并发问题。

Redis 的数据结构有哪些呀?

首先最基础的五种数据结构必须烂熟于心: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 的持久化有哪几种方式?

Redis 数据持久化有两种方式: RDB 和 AOF 。

通过 RDB 或者 AOF ,都可以将 Redis 内存中的数据持久化到硬盘上面,如果有需要,还可以将硬盘上的数据备份到其他地方去。

如果 Redis 挂了,这时止不仅 Redis 服务挂掉,内存数据丢失,同时产生硬件损坏,硬盘上的数据也丢失或者复发恢复,我们还可以从其他地方将数据拷贝回来进行数据恢复。

不同的持久化机制都有什么优缺点?

RDB 的优缺点:

AOF 的优缺点:

两种持久化方式选择:

参考

https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-persistence.md

上一篇下一篇

猜你喜欢

热点阅读