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

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:

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云服务器SVN仓库搭建(以阿里云为例)

远程连接阿里云服务器 安装svn(注意需要root权限使用命令sudo su) yum install subversion 安装成功后查看svn版本 svnserve --version 创建版本库的根目录 mkdir /var/svn 创建代码仓库 svnadmin create /var/svn/test 当前生成的目录结构 此处为svn的配置文件 创建用户名…

【Kubernetes】Kubernetes的部署

kubernetes 一、Kubernetes 的安装部署1. 常见的安装部署方式1.1 Minikube1.2 Kubeadm1.3 二进制安装部署2. K8S 部署 二进制与高可用的区别2.1 二进制部署2.2 kubeadm 部署二、Kubernetes 二进制部署过程1. 服务器相关设置以及架构2. 操作系统初始化配置3. 部署 etcd 集群4. 部…

数据结构【第3章】——线性表

线性表的定义 线性表:零个或多个数据元素的有限序列。 1)线性表是一个序列。即元素之间是有顺序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有一个前驱和后继。 2&a…

问道管理:两市股指冲高回落,沪指一度突破3300点,券商、保险板块领涨

8月4日,两市股指高开高走,沪指一度突破3300点。开盘后,沪指、深成指涨近1%,创业板指、上证50指数涨幅超1%。职业方面,券商、稳妥板块领涨,传媒、石油、半导体、银行、煤炭等板块均上扬,互联金融…

三、JVM-如何判断对象已死问题

内存模型以及如何判定对象已死问题 体验与验证 2.4.5.1 使用visualvm visualgc插件下载链接 :https://visualvm.github.io/pluginscenters.html 选择对应JDK版本链接—>Tools—>Visual GC 若上述链接找不到合适的,大家也可以自己在网上下载对应…

2023年电赛A题报告模板--可直接使用

任务 图1 任务内容 要求 图2 基本要求内容 图3 发挥部分内容 说明 图4 说明内容 评分标准 图5 评分内容 正文 (部分) 摘要 本实验旨在设计和制作一个由两个单相逆变器组成的并联系统,用于为电阻负载供电或并入220V电网。采用基于STM…

某银行软件测试笔试题

(时间90分钟,满分100分) 考试要求:计算机相关专业试题 一、填空题(每空1分,共10分) 1. ______验证___是保证软件正确实现特定功能的一系列活动和过程。 2. 按开发阶段分,软件测试可…

轻松学会WiFi模块(ESP8266)—基于STM32,学到就是赚到!

目录 前言 一、ESP8266介绍 二、如何实现WiFi传输?代码详解附上 三、结果实现流程与展示 四、总结 题外话: 前言 哎哎哎,发觉好久没有更新博客了,最近一直事情比较多,也没什么时间注意博客,不过接下…

C++stack_queue

stack_queue 容器适配器stack详解栈适配器栈模拟实现 队列详解队列适配器queue模拟实现 容器适配器 除了顺序容器外,标准库还定义了三个顺序容器适配器:stack(栈),queue(队列),priority_queue(优先队列)。适配器是标准库中的一个通用概念。容器,迭代器和…

Blazor第三方组件库推荐:BootstrapBlazor UI

文章目录 前言资源适合人群如何开始环境配置开始新项目Server和Wasm的区别.NET CORE 不支持 7.0运行结果 使用组件发布项目配置到IIS里面 样式问题 前言 Blazor是C#全栈追求极致开发速度的一个前后端不分离的框架,上限是在Winform,WPF,MAUI等宿主环境上面运行的全平…

uniapp 中过滤获得数组中某个对象里id:1的数据

// 假设studentData是包含多个学生信息的数组 const studentData [{id: 1, name: 小明, age: 18},{id: 2, name: 小红, age: 20},{id: 3, name: 小刚, age: 19},{id: 4, name: 小李, age: 22}, ]; // 过滤获取id为1的学生信息 const result studentData.filter(item > ite…

MySQL操作命令详解:增删改查

文章目录 一、CRUD1.1 数据库操作1.2 表操作1.2.1 五大约束1.2.2 创建表1.2.3 修改表1.2.3 删除表1.2.4 表数据的增删改查1.2.5 去重方式 二、高级查询2.1 基础查询2.2 条件查询2.3 范围查询2.4 判空查询2.5 模糊查询2.6 分页查询2.7 查询后排序2.8 聚合查询2.9 分组查询2.10 联…

SpringBoot搭建WebSocket初始化

1.java后端的maven添加websocket依赖 <!-- websocket依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>2.实例化ServerEndpointExport…

合合信息通过ISO/IEC国际标准双认证,为全球用户提供高合规标准AI服务

互联网、AI等技术的全球普及为人们提供便捷服务的同时&#xff0c;也带来了信息安全领域的诸多挑战。保护用户隐私及数据安全&#xff0c;是科技企业规范、健康发展的重心。近期&#xff0c;上海合合信息科技股份有限公司&#xff08;简称“合合信息”&#xff09;顺利通过国际…

测试|Junit相关内容

测试|Junit相关内容 文章目录 测试|Junit相关内容0.Junit说明1.Junit注解TestDisabledBeforeAll和AfterAllBeforeEach和AfterEach 2.Junit参数化单参数多参数&#xff08;多种/多组&#xff09;CSV获取参数&#xff08;支持多种&#xff09;CSV文件获取参数&#xff08;支持多种…

tomcat限制IP访问

tomcat可以通过增加配置&#xff0c;来对来源ip进行限制&#xff0c;即只允许某些ip访问或禁止某些来源ip访问。 配置路径&#xff1a;server.xml 文件下 标签下。与同级 <Valve className"org.apache.catalina.valves.RemoteAddrValve" allow"192.168.x.x&…

单片机中的通用LED驱动

前言 项目中需要用到很多的LED灯&#xff0c;存在不同的闪烁方式&#xff0c;比如单闪&#xff0c;双闪&#xff0c;快闪&#xff0c;慢闪等等&#xff0c;我需要一个有如下特性的LED驱动 方便的增加不同闪烁模式可以切换闪烁模式增加LED数目不会有太多的改动方便移植&#x…

Jmeter教程

目录 安装与配置 一&#xff1a;下载jdk——配置jdk环境变量 二&#xff1a;下载JMeter——配置环境变量 安装与配置 一&#xff1a;下载jdk——配置jdk环境变量 1.新建环境变量变量名:JAVA_HOME变量值&#xff1a;&#xff08;即JDK的安装路径&#xff09; 2.编辑Path%J…

Agents改变游戏规则,亚马逊云科技生成式AI让基础模型加速工作流

最近&#xff0c;Stability AI正式发布了下一代文生图模型——Stable Diffusion XL 1.0这次的1.0版本是Stability AI的旗舰版生图模型&#xff0c;也是最先进的开源生图模型。 在目前的开放式图像模型中&#xff0c;SDXL 1.0是参数数量最多的。官方表示&#xff0c;这次采用的…

指向字符串常量(字符串右值)的char指针,free的时候为什么会报错?

起因是如下代码 char *p "abc"; free(p);先说结果&#xff0c;这里会报错&#xff0c;会报一个错误如下 一开始还没反应过来&#xff0c;只知道 “test_content” 是一个右值&#xff0c;这是一个指向右值的指针。 但是free的时候为什么会报错呢&#xff1f; 首…