Redis 6.0的新特性:多线程、客户端缓存与安全

news2025/1/17 19:53:02

2020年5月份,6.0版本。

面向网络处理的多IO线程可以提高网络请求处理的速度,而客户端缓存可以让应用直接在客户端本地读取数据,这两个特性可以提升Redis的性能。

细粒度权限控制让Redis可以按照命令粒度控制不同用户的访问权限,加强了Redis的安全保护。

RESP 3协议则增强客户端的功能,可以让应用更加方便地使用Redis的不同数据类型。

1 从单线程处理网络请求到多线程处理

Redis单线程架构,虽有些命令操作可用后台线程或子进程执行(如数据删除、快照生成、AOF重写),但从网络IO处理到实际的读写命令处理,都是由单线程完成。

随着网络硬件的性能提升,Redis性能瓶颈有时会出现在网络I/O处理,即单个主线程处理网络请求的速度跟不上底层网络硬件的速度。
一般有两种方法:

  • 用用户态网络协议栈(例如DPDK)取代内核网络协议栈,让网络请求的处理不用在内核里执行,直接在用户态完成处理就行。
    让Redis避免频繁让内核进行网络请求处理,可很好地提升请求处理效率。但这个方法要求在Redis的整体架构中,添加对用户态网络协议栈的支持,需修改Redis源码中和网络相关的部分(例如修改所有的网络收发请求函数),这会带来很多开发工作量。而且新增代码还可能引入新Bug,导致系统不稳定。
  • 采用多个IO线程来处理网络请求,提高网络请求处理的并行度。Redis 6.0采用
    Redis的多I/O线程只是用来处理网络请求,对于读写命令,Redis仍使用单线程处理。因为,Redis处理请求时,网络处理经常是瓶颈,通过多个I/O线程并行处理网络操作,可提升实例的整体处理性能。而继续使用单线程执行命令操作,无需为了保证Lua脚本、事务的原子性,额外开发多线程互斥机制了。这样Redis线程模型实现就简单了。

6.0中,主线程和IO线程具体是怎么协作完成请求处理的?

可将主线程和多I/O线程的协作分成如下阶段:

服务端和客户端建立Socket连接,并分配处理线程

主线程负责接收建立连接请求。当有客户端请求和实例建立Socket连接时,主线程会创建和客户端的连接,并把 Socket 放入全局等待队列中。
紧接着,主线程通过轮询方法把Socket连接分配给IO线程。

IO线程读取并解析请求

主线程一旦把Socket分配给IO线程,就会进入阻塞状态,等待IO线程完成客户端请求读取和解析。因为有多个IO线程在并行处理,所以,这个过程很快就可以完成。

主线程执行请求操作

等到IO线程解析完请求,主线程还是会以单线程的方式执行这些命令操作

IO线程回写Socket和主线程清空全局队列

当主线程执行完请求操作后,会把需要返回的结果写入缓冲区,然后,主线程会阻塞等待IO线程把这些结果回写到Socket中,并返回给客户端。

和IO线程读取和解析请求一样,IO线程回写Socket时,也是有多个线程在并发执行,所以回写Socket的速度也很快。等到IO线程回写Socket完毕,主线程会清空全局队列,等待客户端的后续请求。
该阶段主线程和IO线程的操作:

2 启用多线程

6.0多线程机制默认关闭,要启用,需在redis.conf中完成两个设置:

1.设置io-threads-do-reads=yes,表示启用多线程。

io-threads-do-reads yes

2.设置线程个数。线程个数一般小于Redis实例所在机器的CPU核数。如8核机器,Redis官方建议6个IO线程。

io-threads  6

若你在实际应用中,发现Redis实例CPU开销不大,吞吐量却没提升,可考虑使用Redis 6.0的多线程机制,加速网络处理,提升实例吞吐量。

3 实现服务端协助的客户端缓存

6.0实现了服务端协助的客户端缓存功能,也称跟踪(Tracking)功能。业务应用中的Redis客户端就能将读取的数据缓存在业务应用本地,应用就能直接在本地快速读取数据。

问题也来了,若数据被修改或失效,如何通知客户端对缓存的数据做失效处理?6.0实现的Tracking功能提供两种模式解决这问题。

3.1 普通模式

实例会在服务端记录客户端读取过的key,并监测key是否有修改。一旦key值变化,服务端会给客户端发送invalidate消息,通知客户端缓存失效

服务端对记录的key只会报告一次invalidate消息,也就是说,服务端在给客户端发送过一次invalidate消息后,如果key再被修改,此时,服务端就不会再次给客户端发送invalidate消息。

只有当客户端再次执行读命令时,服务端才会再次监测被读取的key,并在key修改时发送invalidate消息。这样设计的考虑是节省有限的内存空间。毕竟,如果客户端不再访问这个key了,而服务端仍然记录key的修改情况,就会浪费内存资源。

我们可以通过执行下面的命令,打开或关闭普通模式下的Tracking功能。

CLIENT TRACKING ON|OFF

3.2 广播模式

服务端会给客户端广播所有key的失效情况,但这样做后,若K被频繁修改,服务端会发送大量失效广播消息,消耗大量网络带宽资源。

实际应用时,会让客户端注册希望跟踪的key的前缀,当带有注册前缀的K被修改时,服务端会把失效消息广播给所有注册的客户端。和普通模式不同,在广播模式下,即使客户端还没读取过K,但只要它注册了要跟踪的K,服务端都会把K失效消息通知给这客户端。

案例 -客户端如何使用广播模式接收key失效消息

当我们在客户端执行下面的命令后,如果服务端更新了user🆔1003这个key,那么,客户端就会收到invalidate消息。

CLIENT TRACKING ON BCAST PREFIX user

这种监测带有前缀的key的广播模式,和我们对key的命名规范非常匹配。我们在实际应用时,会给同一业务下的key设置相同的业务名前缀,所以,我们就可以非常方便地使用广播模式。

普通模式和广播模式,需要客户端使用RESP 3协议,RESP 3协议是6.0新启用的通信协议。

对于使用RESP 2协议的客户端来说,就需要使用另一种模式:

重定向模式(redirect)

想获得失效消息通知的客户端,需执行订阅命令SUBSCRIBE,专门订阅用于发送失效消息的频道_redis_:invalidate。同时使用另外一个客户端,执行CLIENT TRACKING,设置服务端将失效消息转发给使用RESP 2协议的客户端。

案例

如何让使用RESP 2协议的客户端也能接受失效消息?

假设客户端B想获取失效消息,但客户端B只支持RESP 2协议,客户端A支持RESP 3协议。我们可以分别在客户端B和A上执行SUBSCRIBE和CLIENT TRACKING,如下所示:

//客户端B执行,客户端B的ID号是303
SUBSCRIBE _redis_:invalidate

//客户端A执行
CLIENT TRACKING ON BCAST REDIRECT 303

这样设置以后,如果有键值对被修改了,客户端B就可以通过_redis_:invalidate频道,获得失效消息了。

4 从简单的基于密码访问到细粒度的权限控制

实例的访问权限控制列表功能(Access Control List,ACL),这个特性可以有效地提升Redis的使用安全性。

在Redis 6.0 版本之前,要想实现实例的安全访问,只能通过设置密码来控制,例如,客户端连接实例前需要输入密码。

此外,对于一些高风险的命令(例如KEYS、FLUSHDB、FLUSHALL等),在Redis 6.0 之前,我们也只能通过rename-command来重新命名这些命令,避免客户端直接调用。

Redis 6.0 提供了更加细粒度的访问权限控制,这主要有两方面的体现。

首先,6.0版本支持创建不同用户来使用Redis。在6.0版本前,所有客户端可以使用同一个密码进行登录使用,但是没有用户的概念,而在6.0中,我们可以使用ACL SETUSER命令创建用户。例如,我们可以执行下面的命令,创建并启用一个用户normaluser,把它的密码设置为“abc”:

ACL SETUSER normaluser on > abc

另外,6.0版本还支持以用户为粒度设置命令操作的访问权限。我把具体操作列在了下表中,你可以看下,其中,加号(+)和减号(-)就分别表示给用户赋予或撤销命令的调用权限。

为了便于你理解,我给你举个例子。假设我们要设置用户normaluser只能调用Hash类型的命令操作,而不能调用String类型的命令操作,我们可以执行如下命令:

ACL SETUSER normaluser +@hash -@string

除了设置某个命令或某类命令的访问控制权限,6.0版本还支持以key为粒度设置访问权限。

具体的做法是使用波浪号“~”和key的前缀来表示控制访问的key。例如,我们执行下面命令,就可以设置用户normaluser只能对以“user:”为前缀的key进行命令操作:

ACL SETUSER normaluser ~user:* +@all

好了,到这里,你了解了,Redis 6.0可以设置不同用户来访问实例,而且可以基于用户和key的粒度,设置某个用户对某些key允许或禁止执行的命令操作。

这样一来,我们在有多用户的Redis应用场景下,就可以非常方便和灵活地为不同用户设置不同级别的命令操作权限了,这对于提供安全的Redis访问非常有帮助。

5 启用RESP 3协议

Redis 6.0实现了RESP 3通信协议,而之前都是使用的RESP 2。在RESP 2中,客户端和服务器端的通信内容都是以字节数组形式进行编码的,客户端需要根据操作的命令或是数据类型自行对传输的数据进行解码,增加了客户端开发复杂度。

而RESP 3直接支持多种数据类型的区分编码,包括空值、浮点数、布尔值、有序的字典集合、无序的集合等。

所谓区分编码,就是指直接通过不同的开头字符,区分不同的数据类型,这样一来,客户端就可以直接通过判断传递消息的开头字符,来实现数据转换操作了,提升了客户端的效率。除此之外,RESP 3协议还可以支持客户端以普通模式和广播模式实现客户端缓存。

6 总结


Redis 6.0是刚刚推出的,新的功能特性还需要在实际应用中进行部署和验证,所以,如果你想试用Redis 6.0,可以尝试先在非核心业务上使用Redis 6.0:

  • 可以验证新特性带来的性能或功能优势
  • 避免因为新特性不稳定而导致核心业务受到影响

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/829254.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

汽车智能化再掀新热潮!「中央计算架构」进入规模量产周期

中央计算区域控制的新一代整车电子架构,已经成为车企继电动化、智能化(功能上车)之后,新一轮竞争的焦点。 如果说智能化的1.0阶段,是智能驾驶智能座舱的争夺战;那么,即将进入的2.0阶段&#xff…

MacOS上配置docker国内镜像仓库地址

背景 docker官方镜像仓库网速较差,我们需要设置国内镜像服务 我的MacOS docker版本如下 设置docker国内镜像仓库地址 点击Settings点击Docker Engine修改配置文件,添加registry-mirrors {"builder": {"gc": {"defaultKeepS…

iOS——Block签名

首先来看block结构体对象Block_layout(等同于clang编译出来的__Block_byref_a_0) #define BLOCK_DESCRIPTOR_1 1 struct Block_descriptor_1 {uintptr_t reserved;uintptr_t size; };#define BLOCK_DESCRIPTOR_2 1 struct Block_descriptor_2 {// requi…

【ASP.NET MVC】生成页面(6)

本应该继续数据库访问的问题进行探讨,前文确实比较LOW。但本人认为:初学者需要解决的是快速了解知识路线的问题,所谓“生存问题”,所以,干脆把流程先走完。 一、页面生成 下面这张图在前面已经介绍过: 前…

AI时代数据库如何Ready?TiDB率先给出答案

当ChatGPT横空出世的那一刻,很多行业都为之一震,意识到变革时刻已经到来。 数据库是最早“觉醒”且付之行动的领域之一。业内普遍认为,大模型所呈现出的强大能力,让DataAI成为数据库领域的大势所趋。大模型与数据的同频共振&…

【POSIX信号量】

文章目录 1 :peach:POSIX信号量 :peach:2 :peach:信号量的接口介绍 :peach:2.1 :apple:初始化信号量:apple:2.2 :apple:销毁信号量:apple:2.3 :apple:等待信号量:apple:2.4 :apple:发布信号量:apple: 3 :peach:基于环形队列的生产者消费者模型 :peach:3.1 :apple:环形队列:appl…

插入排序讲解

插入排序(Insertion-Sort)一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表…

JDK8:Optional详解与源码分析,如何优雅的处理空指针

文章目录 一、Optional概述1、烦人的NullPointerException2、Optional简介 二、Optional使用1、创建Optional对象2、isPresent()与ifPresent()应用&源码解析3、get()应用&源码解析4、orElseThrow()应用&源码解析5、map()应用&源码解析6、flatMap()应用&源码…

string【2】模拟实现string类(超详解哦)

string模拟实现 引言(实现概述)string类方法实现默认成员函数构造函数拷贝构造赋值运算符重载析构函数 迭代器beginend 容量size、capacity、emptyreserveresize 访问元素operator[] 修改insert插入字符插入字符串 appendpush_backoperatoreraseclearswa…

BGP----边界网关路协议

目录 一,BGP相关的特点 二、BGP特点: 三、BGP数据包 四、BGP的工作过程 五、名词 六、BGP的路由黑洞问题 七、BGP的防环机制 –水平分割 八、BGP的基本配置: 1.直连的EBGP邻居关系建立 2.IBGP邻居关系建立 3.EBGP邻居间存在多条…

【NetCore】06-配置框架

文章目录 1.配置框架1.1 核心包1.2 配置框架核心类型1.3 配置框架扩展点 2.命令行配置提供程序2.1 支持的命令格式2.2 命令替换模式 3. 环境变量配置提供程序3.1 使用场景3.2 特性 4.文件配置提供程序4.1 文件配置提供程序4.2 特性 5.配置变更监听-配置热更新能力的核心5.1 场景…

客服如何通过微信接收消息通知-唯一客服文档中心

当我们在自己网站上嵌入对接了客服代码,我们想要通过微信接收访客的消息提醒通知,可以通过扫描客服后台的微信二维码,即时收消息通知提醒。 我们网站地址:gofly.v1kf.com 客服后台 后台主页面板,就展示了一个微信二维码…

PHP http请求封装使用(POST.GET,PUT,DELETE)

封装的 sendRequest() 函数是一个通用的发送请求函数&#xff0c;可以发送 POST、GET、PUT、DELETE 请求。下面对该函数的代码进行具体讲解&#xff1a; <?php function sendRequest($method, $url, $data null, $contentType multipart/form-data, $headers array(),…

无人驾驶实战-第一课(自动驾驶概述)

在七月算法上报了《无人驾驶实战》课程&#xff0c;老师讲的真好。好记性不如烂笔头&#xff0c;记录一下学习内容。 ————————————————————————————————————————— 无人驾驶汽车的定义&#xff1a; 无人驾驶汽车是可载人的移动智能机器…

【ASP.NET MVC】动态与静态网站(3)

一、区别 静态网页&#xff08;站&#xff09; 用户通过浏览器提交访问需求&#xff0c;需求可以是默认首页或者指定的网站中的某个页面&#xff0c;WEB服务器查找对应的网页&#xff0c;通过HTTP协议发送到客户端&#xff0c;完成访问。 特点&#xff1a;每次访问、不同角色…

视频监控综合管理平台EasyCVR修改参数提示database or disk is full是什么原因?

EasyDarwin开源流媒体视频EasyCVR安防监控平台可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等能力。视频监控综合管理平台EasyCVR具备视频汇聚融合能力&#xff0c;平台基于云边端一体化架构&#xff0c;具有强大…

【MCU学习】GD32F427VG开发

&#xff08;一&#xff09;学习文档和例程 兆易创新GD32 MCU参考资料下载 1.GD232F4xx的Keil芯片支持包 2.标准固件库和示例程序 3.GD32F4xx_固件库使用指南_Rev1.2 4.用户手册&#xff1a;GD32F4xx_User_Manual_Rev2.8_CN 5.数据手册&#xff1a;GD32F427xx_Datasheet_Rev…

通信笔记——最小移频键控MSK

由2FSK→MSK存在以下几点&#xff1a; 1、如何实现已调信号的码元正交&#xff1b;2、如何实现相位连续&#xff0c;不突变。 1、以2FSK一般表示法出发&#xff0c;推导得出两种频率的约束关系 正交条件&#xff1a; 积化和差公式有&#xff1a; 当载波频率比较高&#xff…

类欧几里得算法学习笔记

偶然发现了学长发给我的一个学长的学长也是我的学长的一个数论 p p t ppt ppt&#xff0c;先不着急复习莫反杜教筛&#xff0c;按这个顺序来吧 0.随便说说 前一阵子确实学习状态不是很好&#xff0c;我感觉我个人学习状态也是忽好忽坏的&#xff0c;不过只要在学习状态好的时…

大麦链接源码 大麦一键生成订单截图

8.4最新版源码 更新了大麦链接模版 更新了大麦订单截图一键生成 下载源码&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3