首页 > 其他分享 >追求性能极致:客户端缓存带来的革命

追求性能极致:客户端缓存带来的革命

时间:2022-10-12 16:32:22浏览次数:52  
标签:缓存 RESP Redis 模式 极致 key 客户端

背景

2020年5月份,Redis官方推出了令人瞩目的 Redis 6.0,提出很多新特性,包括了客户端缓存 (Client side caching)、ACL、Threaded I/O 和 Redis Cluster Proxy 等诸多新特性。如下:

追求性能极致:客户端缓存带来的革命_缓存

我们也专门对 Redis 6.0的 Threaded I/O(多线程网络I/O 模式)做了很详细的说明,有兴趣的翻到前面一篇。 这一篇咱们就来聊下这个Client side caching(客户端缓存),看看Redis为什么需要客户端缓存、是基于什么原理实现的,以及具体应该怎么使用。

1 为什么需要客户端缓存

1.1 缓存服务的目的

Redis的读写操作都是在内存中实现了,相对其他的持久化存储(如MySQL、File等,数据持久化在磁盘上),性能会高很多。因为我们在操作数据的时候,需要通过 IO 操作先将数据读取到内存里,增加工作成本。

追求性能极致:客户端缓存带来的革命_缓存_02

可以看看他的金字塔模型,越往上执行效率越高,价格也就越贵。下面给出每一层的执行耗时对比:

  • 寄存器:0.3 ns* L1高速缓存:0.9 ns* L2高速缓存:2.8 ns* L3高速缓存:12.9 ns* 主存:120 ns* 本地二级存储(SSD):50~150 us
  • 远程二级存储:30 ms
  • 我们举个L1和SSD的直观对比,如果L1耗时1s的话,SSD中差不多要15~45小时,所以内存层面的访问效率远远比磁盘层面的访问效率高很多。 总之,缓存的目的是基于对持久化在磁盘的数据(比如MySQL数据、文件数据等)的高效访问,为了提升效率而实现的。《Redis in Action》中也提到, Redis 能够提升普通关系型数据库的 10 ~ 100 倍的性能。 数据访问过程如下图,Redis 存储了热点数据,当天我们请求一个数据时,先去访问缓存层,如果不存在再去访问数据库,这样可以解决大部分高效读取数据的业务场景,性能是缓存最重要的价值之一。
  • 追求性能极致:客户端缓存带来的革命_缓存_03

1.2 存在的问题

虽然我们使用Redis提升了数据的访问效率,但是依然存在一些问题。基于分布式访问的缓存服务是一个独立的服务存在,一般情况下访问它需要经过这几个步骤:

  • 连接缓存服务(一般不会跟计算服务在一个实例上)
  • 查找并读取数据(I/O操作)
  • 网络传输
  • 数据序列化反序列化
  • 这些操作一样的是对性能有影响的,随着互联网的发展,流量不断的膨胀,很容易达到 Redis 的性能上限。 所以,我们经常会使用进程缓存(本地缓存),来辅助处理,将一些高频读低频写的数据暂存在本地,读取数据的时候,先检查本地缓存是否存在,不存在再访问远端缓存服务的数据,进一步提高访问效率。 如果Redis也不存在,就只能去 数据库 中查询,查到的数据再设置到 Redis 和 本地缓存中,这样后续的请求就不用再走到数据库中了。
  • 追求性能极致:客户端缓存带来的革命_缓存_04

  • 一般我们会使用Memcachced、Guava Cache 等来做第一级别缓存(本地缓存),使用Redis作为第二级缓存(缓存服务),本地内存避免了 连接、查询、网络传输、序列化等操作,性能比缓存服务快很多,这种模式大大减少数据延迟。

2 客户端缓存实现原理

Redis自己实现了一个客户端缓存,用以协助服务端Redis的操作,叫做​​tracking​​。 我们可以通过命令来配置它:

CLIENT TRACKING ON|OFF [REDIRECT client-id] [PREFIX prefix] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]

客户端缓存最核心的问题就是当Redis中的缓存变更或者失效了之后,如果能够及时有效的通知到客户端缓存,来保证数据的一致性。 Redis 6.0 实现 Tracking 功能,这个功能提供了两种方案来实现数据的一致性保证:

  • RESP2 协议版本的转发模式
  • RESP3 协议版本的普通模式和广播模式
  • 追求性能极致:客户端缓存带来的革命_缓存_05

  • 接下来我们一个个来分析。

2.1 普通模式

Redis使用 TrackingTable 来存储普通模式的客户端数据,它的数据类型是基数树 ( radix tree)。

radix tree是针对稀疏的长整型数据查找的多叉搜索树,能快速且节省空间的完映射

追求性能极致:客户端缓存带来的革命_redis_06

如图中,客户端ID列表与Redis存储键的指针具有映射关系。而Redis键对象的指针对应的就是内存地址,数据结构是Long。 当开启了track 功能之后,操作具有以下特性:

  • 当Redis获取一个键值信息时,radix tree 会调用 enableTracking 方法记录 key 和 clientId 的映射关系,记录到 TrackingTable 中。
  • 当Redis删除或者修改一个键值信息时
  • radix tree 根据key调用 trackingInvalidateKey 方法查找对应的 Clinet ID
  • 调用 sendTrackingMessage 方法把失效的键值信息(invalidate 消息) 发送给这些 Clinet ID。
  • 发送完成之后从TrackingTable中删除映射关系。
  • Client关闭 track 功能后,遇到大量删除操的时候,一般是懒删除,只将 CLIENT_TRACKING 标志位删除。
  • 默认 track 模式是不开启,需要通过命令开启,参考如下:
CLIENT TRACKING ON|OFF
+OK
GET test
$7
archite

2.2 广播模式(BCAST)

追求性能极致:客户端缓存带来的革命_客户端_07

广播模式与普通模式类似,也是采用映射关系来对照,但实现过程还是有区别的:

  • 存储的内容不一样:如图,采用Prefix Table 来存储客户端数据,存储的是前缀字符串指针 和 客户端数据(客户端ID列表 + 需通知的key值列表)的映射关系。
  • 删除键值的时机不一样:
  • radix tree 根据key调用 trackingInvalidateKey 方法查找PrefixTable。
  • 判断是否为空,不为空则 调用 trackingRememberKeyToBroadcast 对键列表进行进行遍历,找到符合前缀匹配规则的,并记录位置。
  • 在事件处理周期函数 beforeSleep 中 调用 trackingBroadcastInvalidationMessages 函数来发送消息。
  • 发送完成之后从 PrefixTable 中删除映射关系。

2.3 转发模式

RESP 3 协议 是 Redis 6.0 新启用的协议,使用普通模式或者广播模式需要依赖这种协议,这样对于RESP 2 协议的客户端来说就会有问题。所以衍生除了另一种模式:重定向(redirect)。

  • RESP 2 无法直接 PUSH 失效消息,所以不能直接获取到失效数据(Redis Client 2)。
  • 支持 RESP 3 协议的客户端(Redis Clinet 1) 告诉 Server 将失效消息通过 Pus/Sub 通知给 RESP 2 客户端。
  • 而Redis Client 2 (RESP 2 )是通过订阅命令 SUBSCRIBE,专门订阅用于发送失效消息的频道redis:invalidate。
  • 追求性能极致:客户端缓存带来的革命_缓存_08

如下所示:

# Redis Client 2 (支持RESP 2)执行订阅 
client id : 888
subscribe _redis_:invalidate

# Redis Client 1(支持RESP 3),转发给 2
client tracking on bcast redirect 888

3 总结

3.1 默认模式(普通模式)

  • 服务端记录客户端操作过的 key,key 对应的值发生变化时,会发送 Invalidation Messages 给Redis 客户端。
  • 服务端记录key信息会消耗一些内存,但是发送失效消息的范围,限制在存储的key范围内,计算和网络传输变的轻量。
  • 优点是节省 CPU 以及流量带宽,但是会占用一些内存。

3.2 广播模式

  • 服务端不记录 key,而是订阅 key 的特定前缀,当匹配前缀的 key 的值改变时,发送 Invalidation Messages 给 Redis客户端。
  • 优点是服务端的内存消耗少,但是会损耗更多的 CPU 去做前缀匹配的计算。

3.3 转发模式

  • 为了兼容 resp2 协议的一种过渡模式
  • 优点是占用内存少,CPU占用多

客户端的缓存

客户端缓存,需要业务侧自己实现,Redis 服务端只负责通知你key 的变动(删除、新增)。

标签:缓存,RESP,Redis,模式,极致,key,客户端
From: https://blog.51cto.com/u_15773567/5749107

相关文章

  • 有关Idea的Invalidate Caches/Restart (Idea本地缓存异常,导致Idea无法识别Maven依赖)
    分析原因:有时我们自己在编写项目后,再次打开会发现自己封装的类,导入后还是爆红。这是因为Idea本地缓存异常,导致Idea无法识别Maven依赖,从而无法找到某些类。解决方式:通过Idea......
  • Java新浪微博客户端开发第四、五步
    0、Main:主函数入口;1、MainDialog:主界面;2、WeiboPanel:StatusPanel及CommentPanel的父类;3、StatusPanel:所有有关“微博”的父类......AD: 这一步是对之前进行较大的改动。......
  • 秒验 客户端SDK返回码
    返回码返回码描述6119000不支持的运营商6119001手机号不合法6119002无sim卡6119003缺少必要的权限6119004未打开蜂窝网络6119005未接受Mob隐私协议6119095缺少必要的参数611......
  • ShuffleNetV1:极致轻量化卷积神经网络(分组卷积+通道重排)
    参考论文:ShuffleNet:AnExtremelyEfficientConvolutionalNeuralNetworkforMobileDevices作者:XiangyuZhang,XinyuZhou,MengxiaoLin,JianSun  1、论文摘要 ......
  • 缓存概念介绍
     一、缓存是什么?    缓存其实是内存中一个以key-value(键值对)的形式存储数据的一个空间。当然,缓存也可以持久化。常用的缓存技术:Memcached、Ehcache、OsCache、R......
  • 什么是缓存雪崩?服务器雪崩的场景与解决方案
    什么是应用服务雪崩雪崩问题分布式系统都存在这样一个问题,由于网络的不稳定性,决定了任何一个服务的可用性都不是100%的。当网络不稳定的时候,作为服务的提供者,自身可能会被......
  • 【CPU】缓存一致性、CPU基础
    PU的位宽、寻址总线、数据总线CPU的位宽和寄存器一次能够存储的大小相关,比如一个大于4字节的数据,我们用32位的CPU显然是无法存储它的,自然就无法一次性处理它而总线位宽和......
  • PHP正确获取客户端IP地址
    获取代理IP$_SERVER['REMOTE_ADDR']; 获取真实IPfunctionget_client_ip(){$ip=null;if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){$ip=explo......
  • vue3中tab详情页多开keepalive根据key去动态缓存与清除缓存
    一.场景由于存在tab栏,当从查询页面点击列表进入详情时,需求是详情页都会新开一个tab,并缓存,tab中的切换不会重新加载详情页数据,但是关闭一个详情tab,再次从查询页点击这条详......
  • 一文带您了解 Client-Go 的四种客户端
    Client-Go简介Client-Go是负责与KubernetesAPIServer服务进行交互的客户端库,利用Client-Go与KubernetesAPIServer进行的交互访问,来对Kubernetes中的各类资源对象......