| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> Redis6.0新特性简述和验证分析——ACL权限控制、TLS加密管理、多线程IO -> 正文阅读 |
|
[大数据]Redis6.0新特性简述和验证分析——ACL权限控制、TLS加密管理、多线程IO |
目录 1. 简介Redis(Remote Dictionary Server),即远程字典服务,是一个使用 C编写的开源(BSD许可)、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,是现在最受欢迎的NoSQL数据库之一。依赖于Redis的高性能、多数据类型等特性,Redis应用场景十分广泛,可用于游戏缓存应用、互联网缓存应用、电商高并发应用及其他缓存加速访问应用,能有效承载巨大的读写压力,轻松实现高并发访问。 Redis最新版本为Redis6.X,其中有Redis6.0.X及Redis6.2.X两个分支。Redis6.0中已于2020年上半年发布,6.0版本最新已发布至6.0.15。Redis6.0带来了诸多新功能:
除此之外,Redis6.0还有RESP3协议、客户端缓存加速及redis-benchmark、redis-cli优化等新功能。 本文主要对Redis6.0的ACL权限管控、TLS加密管理及多线程IO进行了测试验证和解析。 2. 新功能测试验证2.1 新功能——ACL权限控制2.1.1 ACL简介Redis ACL 是Access Control List(访问控制列表)的缩写,该功能允许对访问 Redis 的连接做一些可执行命令和可访问 KEY 的限制。它的工作方式是,在连接之后,要求客户端进行身份验证,以提供用户名和有效密码,如果身份验证成功,该客户端连接与给定用户绑定,并具有该用户的访问权限。 Redis6.0版本之前,用户只有一个default用户,同一Redis实例所有读写操作都共享此用户,难免出现误操作删除数据或泄露数据情况。虽然可以使用rename命令禁用部分敏感操作,但也同时意味着需要进行敏感操作时,将有额外操作需要进行,权限管控复杂且不完善。在Redis6.0之后,通过ACL(权限管理)功能,可以设置不同的用户并对其授权命令或数据权限。这一功能,可以有效降低用户误操作导致数据丢失或数据泄露风险。其中,密码由SHA256进行加密。 Tips:linux下sha256加密方式:echo -n passowrd | sha256sum 2.1.2 ACL 参数解析本章节简要说明ACL常用命令,以及笔者使用时遇到的问题和需关注的地方。 常用的命令如下:
1)ACL CAT示例: ACL将所有命令分为21子类,ACL可以较细粒度地进行权限划分,但部分命令同时处于不同的权限子类中,设置多个子类权限时,需关注这些命令权限问题。 2)ACL LIST 示例: 通过ACL生成的用户以如下default、test账号为例,进行简要说明:
3)ACL SETUSER示例: ACL SETUSER时,可通过“>”符号分次设置多个密码且密码均为有效;可通过“<”符号使密码无效化,不建议同一账号设置过多密码。当密码无法找回时,可先删除账号再建立相同权限用户方式更新密码,以防有效密码过多导致密码泄露进而导致数据泄露。 对default用户的权限设置需谨慎。笔者进行测试时,设置了一个与default完全相同的admin用户并将default用户权限缩小,因操作原因出现了权限不可用情况,尽可能保留default权限不删减。 普通用户赋权后,可通过auth username password方式登录普通账号。此方式登录需使用6.0及以上版本redis-cli客户端,低版本客户端无法识别,多版本混用需注意。 笔者测试时,一个实例中生成7000+普通账号,redis运行正常权限管控正常。示例如下:
2.1.3 ACL 赋权配置及示例(1)ACL权限持久化方式通过上述的ACL SETUSER方式,对用户的账号进行了赋权后可进行持久化。Redis 实现ACL权限持久化的方式主要有两种: ① redis.conf方式:直接将账号密码持久化保存在redis.conf中; ② aclfile方式:将账号密码保存至users.acl文件中,并把users.acl 路径写入redis.conf。 两种方式中,更推荐aclfile方式。因为redis.conf方式加载配置需要重启Redis,而aclfile方式执行acl load即可。 此外,我们可以在客户端对账户密码进行操作,如果使用redis.conf方式,可通过config rewrite持久化;如果使用aclfile方式,可使用acl save进行持久化。
(2)ACL权限持久化配置示例两种持久化方式的示例如下: ① redis.conf方式 cat redis.conf | grep "~*"可得: ② aclfile方式
Tips:redis6.2.X与redis6.0.X在acl权限控制上,明显区别在于增加了 Pub/Sub channel (&*)管控。 2.1.4 ACL部分源码简析上面提到了ACL权限控制和持久化方式,下面对ACL初始化、权限加载、用户操作源码进行简要的解析。 (1)ACL初始化在server.c的main函数中,有ACLInit()函数,ACLInit()中,主要为初始化ACL的结构。同时,ACLInitDefaultUse初始化默认用户default。default用户初始化时,具有全部权限及默认不需要密码。
(2)ACL权限加载在ACLInit()完成后,main函数中通过ACLLoadUsersAtStartup()进行ACL权限加载,分别通过ACLLoadConfiguredUsers()及ACLLoadFromFile()函数判断用户信息及加载方式。ACLLoadConfiguredUsers()使用redis.conf进行权限加载,ACLLoadFromFile()使用acl文件进行权限加载。
(3)ACL用户操作在进行ACL操作命令时,实际调用了acl.c的aclCommad()命令。aclCommand中,对各类ACL操作分别进行了定义。如setuser,通过判断命令中是否含setuser关键字,再判断usename是否含有空格,user是否已存在,最后调用ACLSetUser(),ACLCreateUser()实现setuser操作。
在普通用户使用权限时,通过ACLCheckCommandPerm()及ACLGetUserCommandBit()函数判断用户是否具有操作权限,如无权限则报ACL_DENIED_CMD权限不足。 2.2 新功能——TLS加密管理2.2.1 TLS简介TLS(Transport Layer Security,安全传输层)是建立在传输层TCP协议之上的协议,服务于应用层,在实现上分为记录层和握手层两层,其中握手层又含四个子协议:握手协议、更改加密规范协议、应用数据协议和警告协议。实现了将应用层的报文进行加密后再交由TCP进行传输的功能,解决了保密、完整性、认证等网络安全问题。Redis从6.0版本开始支持TLS安全加密。 2.2.2 TLS 配置与示例Redis 内部使用 OpenSSL 开发库来实现TLS功能。因此,需要在 Redis 编译之前预先安装 OpenSSL 套件库。此外,TLS是可选功能,需要在编译时加上参数后才会加入TLS功能。 下面将对TLS编译使用进行示例,并简要说明过程中遇到的问题和需关注的地方。 (1)TLS 编译示例编译时,需添加 BUILD_TLS=yes以加入TLS功能。因为依赖主机OpenSSL版本,所以不同OpenSSL版本主机编译出的redis-server不通用。此外,需要注意gcc版本。下面以CentOS7.6、Ubuntu16.04为例进行说明及错误示例。 ① 以CentOS7.6为例 执行 “make BUILD_TLS=yes”时出现has no member named报错: 原因为gcc版本过低,升级gcc版本即可,升级方式:
升级完成后,执行gcc -v,出现gcc version 9.3.1 20200408 (Red Hat 9.3.1-2) (GCC)即为升级成功。再次编译执行“make distclean;make BUILD_TLS=yes”,即可编译成功。 ② 以Ubuntu16.04为例 执行“make BUILD_TLS=yes”,若出现“jemalloc/jemalloc.h: No such file or directory”或“Newer version of jemalloc required”报错: 方案一:README.md文件的官方解决方案 在README.md文件中,Redis官方给出了解决方案“To force compiling against libc malloc, use: % make MALLOC=libc”,再次执行“make distclean”。笔者将“make BUILD_TLS=yes”命令,改为“make BUILD_TLS=yes MALLOC=libc”,即可编译成功。 方案二:关注deps/jemalloc权限是否错误 通过wget获得对应Redis版本后,替换掉deps文件夹中内容,再次执行“make distclean;make BUILD_TLS=yes”。若通过这种方式可以编译成功,Redis采用tcmalloc时碎片率会更低最低。 使用redis:6.0.X替换容器版Redis6.0的镜像时,使用CentOS7.6编译镜像无法启动,使用Ubuntu16.04可成功启动。经分析,CentOS7.6与Ubuntu16.04的OpenSSL版本分别为OpenSSL 1.0.2k-fips、OpenSSL 1.1.1,因OpenSSL版本不同,所以编译出的redis-server不通用。验证时,使用Ubuntu16.04上编译的redis-server启动于CentOS7.6时,出现报错,可证明不通用。 (2)TLS 证书生成 在完成Redis TLS编译后,根据Redis官方文档TLS.md中说明,可通过如下命令生成根CA证书和服务器证书:
其中,生成DH(Diffie-Hellman)params文件耗时较长。 相关证书在配置时限制如下:
分析gen-test-certs.sh可知,所有证书均通过openssl生成。在实际使用中,除了使用shell脚本生成证书,还可以通过java、golang等代码方式调用ssl、tls、x509库生成。其中,证书有效期可以通过days动态生成,到期后可以对证书进行续期。 (3)TLS 参数解析 Redis启用TLS主要涉及如下参数:
2.2.3 Redis TLS使用示例为方便查看,启动参数直接置于启动命令行,以单机版redis-server启动为例:
redis server成功启动,使用redis-cli进行连接。连接时,同时需要加上证书信息:
在进行主备版测试时,redis-server及sentinel除新增上述参数外,需额外增加“--tls-auth-clients yes”和“--tls-replication yes”方可启动成功,否则将无法连接,解释见Redis TLS参数解析。 2.2.4 TLS部分源码简析(1)TLS初始化在server.c的main函数中,tlsInit()函数用于初始化SSL库,initServerConfig()、initConfigValues()用于初始化tls_port和tls_ctx_config等TLS相关参数(相关参数均在redis.conf中获得)。在InitServer()中,获得的TLS参数tls_ctx_config和tls_port被用于tls.c的tlsConfigure()中用于初始化TLS。
(2)TLS读写读写操作由connTLSRead()和connTLSWrite()组成。connTLSRead()是一个SSL_Read的封装,将从tls连接中读取的字节缓冲到buf中。connTLSWrite()是一个SSL_Write的封装,将字节写入data套接字。其中,tls_connection为建立起的tls连接。
2.2.5 TLS局限性Redis特性在于支持高并发且6.0开始支持多线程,然而开启了TLS功能后,出现了明显的局限性: ① 不再支持多线程功能(TLS.md:**Multi-threading I/O is not currently supported for TLS**); ② QPS显著下降,经测试只有未开启TLS的60%(详见下图); ③ 6.0.X版本的redis-benchmark不支持TLS功能,需使用6.2.X版本的redis-benchmark才能执行测试。 使用redis-benchmark在同一台主机上进行对SET、GET、LRANGE_600测试,结果如图所示。 可以看出,开启TLS后,QPS明显降低。 2.3新功能——多线程IO2.3.1 多线程IO简介Redis6.0 之前都是使用单线程异步IO处理数据的,单线程IO只能使用一个CPU核。当key的value比较大时容易拖垮Redis,而且QPS到达10W+后难以更进一步。从Redis6.0开始支持多线程IO,多线程IO不仅可以充分利用服务器CPU资源,还可以分摊IO读写负荷,大幅提升了Redis性能。 2.3.2 多线程IO实现及配置示例(1)多线程IO流程流程主要如下: ① 主线程负责接收建立连接请求,获取 socket 放入全局等待读处理队列; ② 主线程处理完读事件后,通过 RR(Round Robin) 将这些连接分配给这些 IO 线程; ③ 主线程阻塞等待 IO 线程读取 socket 完毕; ④ 主线程通过单线程的方式执行请求命令,请求数据读取并解析完成,但并不执行; ⑤ 主线程阻塞等待 IO 线程将数据回写 socket 完毕; ⑥ 解除绑定,清空等待队列。 (2)多线程IO参数解析在redis.conf中,可以对多线程进行配置(修改配置需重启redis实例)。多线程配涉及两个参数:
2.3.3多线程IO使用及性能对比添加多线程IO参数重启redis后,通过redis-cli config get *命令可查看当前io-threads及io-threads-do-reads配置现况。 多线程IO主要表现在提升了redis的并发能力上,故对不同版本的redis及同版本redis在不同机器上进行了比对测试,分析多线程IO提升能力。 (1)Redis版本间对比测试在同一台主机上,对Redis4.0和Redis6.0进行redis-benchmark性能测试。测试时,redis-benchmark使用了--threads参数进行多线程测试。测试结果详见下图: 可以看出,Redis6.0较Redis4.0同在单线程时,性能并没有得到提升;Redis6.0 二线程,较redis6.0单线程、Redis4.0并发量得到了明显提升。因此,可以得出结论,多线程IO可明显提高Redis的并发量。 (2)Redis CPU间性能对比测试多线程IO可明显提升Redis并发量,在不同类型的CPU主机上测试,也有不同的提升,具体如下: ① 多线程IO 并发上限不到单线程IO的三倍,io-threads到一定数之后(测试时值为6-10,因服务器CPU差别),并发增幅极为有限。在这种情况下,即使增加线程数,也不能明显增加Redis 并发量,只会导致服务器负载增加。 ② CPU频率越高,能达到的最大并发相对也越高。故选用CPU时,选择较高频率CPU可以提升Redis性能。使用时,打开高性能模式也可以提升Redis性能。 Redis6.0 SET Intel Xeon测试结果: 2.3.4 多线程IO部分源码简析多线程IO中,配置文件redis.conf主要涉及的参数是io_threads_do_reads、io-threads,源码中,除了这两个关键变量外,还会涉及io_threads_op、io_threads_pending等变量。 (1)多线程IO初始化在server.c的main函数InitServerLast()中,有初始化多线程函数initThreadedIO()。函数中调用了pthread_create 来创建线程,并且注册了线程回调函数IOThreadMain()。
(2)多线程IO任务处理以多线程读为例,使用了handleClientsWithPendingReadsUsingThreads 函数进行多线程读,步骤如下: ① 通过 io_threads_active 和io_threads_do_reads 两个标志判断是否开启了多线程IO,其中 io_threads_do_reads为redis.conf配置参数,io_threads_active通过调用startThreadedIO()进行置1操作; ② 主线程给工作线程分配client对象策略即轮询策略,io_threads_op指定读类型,通过给io_threads_pending[id]赋值启动工作线程,工作线程在处理完自己链表的 client 对象后会清空自己的链表并重置 io_threads_pending[id] 为0; ③ 主线程的利用while将自己链表中的 client 处理完毕; ④ 最后,线程的pending和为0,跳出循环完成读事件的处理。
3. 小结本次主要对Redis6.0的三个新功能ACL权限控制、TLS加密管理及多线程IO进行了功能性能测试及分析,测试时也兼带对redis-cli、redis-benchmark新功能进行了一定的测试验证:
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 14:52:03- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |