项目中缓存是如何使用的?

95 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情 项目中缓存是如何使用的?

这个,需要结合自己项目的业务来。

为什么要用缓存?

用缓存,主要有两个用途:高性能、高并发。

高性能

假设这么个场景,你有个操作,一个请求过来,吭哧吭哧你各种乱七八糟操作 mysql,半天查

出来一个结果,耗时 600ms。但是这个结果可能接下来几个小时都不会变了,或者变了也可以

不用立即反馈给用户。那么此时咋办?

缓存啊,折腾 600ms 查出来的结果,扔缓存里,一个 key 对应一个 value,下次再有人查,别

走 mysql 折腾 600ms 了,直接从缓存里,通过一个 key 查出来一个 value,2ms 搞定。性能提

升 300 倍。

就是说对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请

求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就好。

高并发

mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持

不好。mysql 单机支撑到 2000QPS 也开始容易报警了。

所以要是你有个系统,高峰期一秒钟过来的请求有 1万,那一个 mysql 单机绝对会死掉。你这

个时候就只能上缓存,把很多数据放缓存,别放 mysql。缓存功能简单,说白了就是 key-

value 式操作,单机支撑的并发量轻松一秒几万十几万,支撑高并发 so easy。单机承载并发

量是 mysql 单机的几十倍。

缓存是走内存的,内存天然就支撑高并发。用了缓存之后会有什么不良后果?

常见的缓存问题有以下几个:

缓存与数据库双写不一致

缓存雪崩、缓存穿透、缓存击穿

缓存并发竞争

Redis 和 Memcached 有啥区别?

Redis 支持复杂的数据结构

Redis 相比 Memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓

存能够支持更复杂的结构和操作, Redis 会是不错的选择。

Redis 原生支持集群模式

在 Redis3.x 版本中,便能支持 cluster 模式,而 Memcached 没有原生的集群模式,需要依靠客

户端来实现往集群中分片写入数据。性能对比

由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数

据时比 Memcached 性能更高。而在 100k 以上的数据中,Memcached 性能要高于 Redis。虽然

Redis 最近也在存储大数据的性能上进行优化,但是比起 Memcached,还是稍有逊色。

Redis 的线程模型

Redis 内部使用文件事件处理器 file event handler ,这个文件事件处理器是单线程的,所

以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket,将产生事件的

socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处

理。

文件事件处理器的结构包含 4 个部分:

多个 socket

IO 多路复用程序

文件事件分派器

事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程

序会监听多个 socket,会将产生事件的 socket 放入队列中排队,事件分派器每次从队列中取出

一个 socket,根据 socket 的事件类型交给对应的事件处理器进行处理。

来看客户端与 Redis 的一次通信过程: Redis 和 Memcached 有啥区别?

Redis 支持复杂的数据结构

Redis 相比 Memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓

存能够支持更复杂的结构和操作, Redis 会是不错的选择。

Redis 原生支持集群模式

在 Redis3.x 版本中,便能支持 cluster 模式,而 Memcached 没有原生的集群模式,需要依靠客

户端来实现往集群中分片写入数据。性能对比

由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数

据时比 Memcached 性能更高。而在 100k 以上的数据中,Memcached 性能要高于 Redis。虽然

Redis 最近也在存储大数据的性能上进行优化,但是比起 Memcached,还是稍有逊色。

Redis 的线程模型

Redis 内部使用文件事件处理器 file event handler ,这个文件事件处理器是单线程的,所

以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 socket,将产生事件的

socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处

理。

文件事件处理器的结构包含 4 个部分:

多个 socket

IO 多路复用程序

文件事件分派器

事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程

序会监听多个 socket,会将产生事件的 socket 放入队列中排队,事件分派器每次从队列中取出

一个 socket,根据 socket 的事件类型交给对应的事件处理器进行处理。

来看客户端与 Redis 的一次通信过程:

image.png 要明白,通信是通过 socket 来完成的,不懂的同学可以先去看一看 socket 网络编程。首先,Redis 服务端进程初始化的时候,会将 server socket 的 AE_READABLE 事件与连接应答

处理器关联。

客户端 socket01 向 Redis 进程的 server socket 请求建立连接,此时 server socket 会产生一个

AE_READABLE 事件,IO 多路复用程序监听到 server socket 产生的事件后,将该 socket 压入队

列中。文件事件分派器从队列中获取 socket,交给连接应答处理器。连接应答处理器会创建一

个能与客户端通信的 socket01,并将该 socket01 的 AE_READABLE 事件与命令请求处理器关

联。

假设此时客户端发送了一个 set key value 请求,此时 Redis 中的 socket01 会产生

AE_READABLE 事件,IO 多路复用程序将 socket01 压入队列,此时事件分派器从队列中获取到

socket01 产生的 AE_READABLE 事件,由于前面 socket01 的 AE_READABLE 事件已经与命令请

求处理器关联,因此事件分派器将事件交给命令请求处理器来处理。命令请求处理器读取

socket01 的 key value 并在自己内存中完成 key value 的设置。操作完成后,它会将

socket01 的 AE_WRITABLE 事件与命令回复处理器关联。

如果此时客户端准备好接收返回结果了,那么 Redis 中的 socket01 会产生一个 AE_WRITABLE

事件,同样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对

socket01 输入本次操作的一个结果,比如 ok ,之后解除 socket01 的 AE_WRITABLE 事件与

命令回复处理器的关联。