redis6刚退出不久,但依然有很多突破性的特性,及早了解新特性和变化,可以在分析业务场景需求时,多一个参考的选择维度
本文将着重从redis6的几个主要特性进行介绍
ps:redis6/redis-cluster-proxy因为使用了c标准库中的并发函数,需要gcc版本4.9以上才可以正常编译
先说结论
1.新增的acl可以有效的对redis集群进行 "分库","权限管理",实现不同业务的区隔
2.resp3使得请求和返回结果,尤其是返回结果,自带类型/size/值的字符长度,使得返回数据可以脱离redis系统的限制,提供更丰富精准的数据定义,实现比json更高效的解析
3.新推出的客户端缓存,有比较丰富的实现,对较复杂/数据量较大的 热读/冷写 有比较大的性能提升
4.官方推出的集群模块,可以有效地将底层redis集群抽象化,无需额外计算solt落点,批量操作透明化,并可以与acl相结合,实现不同proxy节点,不同默认用户 and 单独指定认证用户,使用专有链接等功能,缺点是,目前看来与resp3的结合不是很紧密,无法使用hello切换resp协议,且不支持客户端缓存
1.新增ACL的支持
因为redis的定位:内网高性能内存数据库
所以一直以来redis都只有最简单的auth和bind两种权限控制的方式,其他的安全都交给了网关和操作系统
但auth的权限控制粒度很粗糙,只能 给用户设置密码 or 不设置密码,网络连接更是明文交互
这次,redis6推出了两个强大的安全功能,ACL和SSL支持
SSL的支持,使得服务器间,服务器和客户端之间的网络,即使是不安全的,也能保证数据安全的传输,这里不做多的说明
ACL的出现,使得可以给每个用户设置单独的密码和操作权限,这些权限分为2类:
1.允许/禁止用户执行的命令(集)
2.用户有权限的key(正则匹配)
通过这两类的权限组合,可以将某个用户的操作权限,操作key控制在某个范围,再结合key的命令规范
1.比如某一业务key全部以 "XXXX:" 作为开头,通过将业务下账号的权限控制在 "XXXX:", 限定业务下账号可能影响的范围(即使最严重的后果,也就是丢失全部 "XXXX:" 的数据)
2.业务下不同账号,通过控制他们能执行的命令范围,区分出不同的账号权限(只有 get类命令的读账号,以及有 set类写权限的写账号)
3.通过禁止业务下账号执行flushall,flushdb等高危操作,避免了"业务需要用","用的多了,难免出问题"的死循环
4.可以通过从配置文件导入或者从指定的权限控制文件导入(两种方式等价,只能二选一)导入用户权限,可以快速批量的实现权限的群组控制
具体示例如下:
192.168.23.87:6519> acl setuser sre
#创建新的用户sre
OK
192.168.23.87:6519> acl list#查看用户列表
1) "user default on nopass ~* +@all"
2) "user sre off -@all"
192.168.23.87:6519> ACL SETUSER sre >sre_pass ~workflow:* +get
# 给sre用户收授权
# >sre_pass 表示设置sre的密码为sre_pass
# ~workflow:* 是授权给sre对"workflow:" 开头的key的操作权限
# +get 是给sre用户执行get操作的权限
OK
192.168.23.87:6519> ACL GETUSER sre#获取sre用户的权限详情
1# "flags" => 1~ "off"
2# "passwords" => 1) "a86284e57caea7be53718afbd4518db9da7676b83171575cc177d563b13a5549"
3# "commands" => "-@all +get"
4# "keys" => 1) "workflow:"
192.168.23.87:6519> acl list
1) "user default on nopass ~ +@all"
2) "user sre off #a86284e57caea7be53718afbd4518db9da7676b83171575cc177d563b13a5549 ~workflow:* -@all +get"
192.168.23.87:6519> ACL SETUSER sre +set# 给sre用户追加 set 操作的权限
OK
192.168.23.87:6519> ACL SETUSER sre ~cmdb:*给sre用户追加操作 cmdb: 开头key的权限
OK
192.168.23.87:6519> ACL GETUSER sre
1# "flags" => 1~ "off"
2# "passwords" => 1) "a86284e57caea7be53718afbd4518db9da7676b83171575cc177d563b13a5549"
3# "commands" => "-@all +set +get"
4# "keys" => 1) "workflow:"
2) "cmdb:"
192.168.23.87:6519> ACL SETUSER sre on#激活sre用户 (非激活不可登陆)
OK
192.168.23.87:6519> acl list
1) "user default on nopass ~* +@all"
2) "user sre on #a86284e57caea7be53718afbd4518db9da7676b83171575cc177d563b13a5549 ~workflow:* ~cmdb:* -@all +set +get"
192.168.23.87:6519> config get acl# 查看acl相关配置
1# "aclfile" => "/opt/gredis-6.0.6/conf/redis-master-6519.aclfile"# aclfile文件位置(没有单独aclfile则为空字符串)
2# "acllog-max-len" => "128"# acl 日志的最大长度
192.168.23.87:6519>
192.168.23.87:6519> auth sre sre_pass# 登陆sre用户
OK
192.168.23.87:6519> set cmdb:k1 cmdbv1
OK
192.168.23.87:6519> get cmdb:k1
"cmdbv1"
192.168.23.87:6519> hset cmdbnk1 ccc ddd# 提示没有hset操作的权限
(error) NOPERM this user has no permissions to run the 'hset' command or its subcommand
192.168.23.87:6519> set sre_workflow:k1 v1#提示没有操作 sre_workflow: 开头key的权限
(error) NOPERM this user has no permissions to access one of the keys used as arguments
192.168.23.87:6519> set sre:k1 v1#提示没有操作 sre: 开头key的权限
(error) NOPERM this user has no permissions to access one of the keys used as arguments
[root@host-192-168-23-87 ~]# cat /opt/gredis-6.0.6/conf/redis-master-6519.aclfile# 查看aclfile配置
user default on #37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f ~* +@all
user sre on #a86284e57caea7be53718afbd4518db9da7676b83171575cc177d563b13a5549 ~workflow:* ~cmdb:* -@all +set +get
192.168.23.87:6519> ACL SETUSER aclfile_user# 新增aclfile_user 用户
OK
[root@host-192-168-23-87 ~]# cat /opt/gredis-6.0.6/conf/redis-master-6519.aclfile# 查看aclfile配置
user aclfile_user off -@all
user default on #37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f ~* +@all
user sre on #a86284e57caea7be53718afbd4518db9da7676b83171575cc177d563b13a5549 ~workflow:* ~cmdb:* -@all +set +get
2.resp3通信协议
为了支持更多的新特性,以及将通信协议"语义化"的目的,对原有的resp协议进行了升级,主要新增特点:
1.新增了多种新的数据类型,支持更丰富的数据格式
2.新增的数据类型,以及原有的数据类型,每一种都有一个自己独有的"首字符",结合数据类型的"大小值",可以实现数据的层层嵌套,快速解析,而且使得数据脱离了具体的命令,即,只要拿到对应的"请求/返回"数据,就可以还原出具体的"请求/返回"的数据格式
3.新增了未知长度的"流"模式的数据类型
原有类型和新增类型之间关系
resp3与resp2等价的类型
Array: 一个有序集合,包含N个其它类型
Blob string: 二进制安全字符串
Simple string: 一个节省空间的非二进制安全字符串
Simple error: 一个节省空间的非二进制安全错误码和错误信息
Number: 有符号64位整数
resp3新增的类型
Null: 单一的空值,代替原先的 RESP v2 的*-1 和 $-1 空值。
Double: 浮点数
Boolean: 布尔类型 true / false
Blob error: 二进制安全的错误码和错误信息
Verbatim string: 一个二进制安全字符串,带文本格式, 如命令LATENCY DOCTOR的输出
Map: 一个有序的键值对
Set: 一个无序的不重复的集合
Attribute: 类似Map类型
Push: 带外数据,格式类似数组,但是客户端需要检查第一个数据,第一个数据指示了带外数据的类型。注意带外数据并不是一个reply,它是redis主动推送的数据,所以客户端收到带外数据,交给对应的处理方法去处理后,你还需要继续读取你的reply数据
Hello: hello命令的返回结果,类似Map类型,仅仅在客户端和服务器建立连接的时候发送
Big number: 大数字类型
还有一种新加的stream类型,可以用来传送不确定具体长度的数据。在数据的开头有固定的标识符,在数据传输完毕后在加上这个40字节的标识符,40字节的标志符基本上不会和传输的数据有重复
resp3协议中,有几类数据的"首字母"也做了更细粒度的区分,具体如下
数据类型 | resp2 | resp3 |
---|---|---|
Simple error | + | - |
Verbatim string | $ | = |
map | * | % |
set | * | ~ |
Attribute | * | | |
Push | * | > |
Streamed strings | $(字符长度)<CR><LF>(指定长度字符)<CR><LF> | $?<CR><LF>(任意发送次数,每次发送任意长度,每次发送遵循对应数据格式规范);0<CR><LF>(;0<CR><LF>作为固定的传输结束标识) |
Streamed aggregated data | *(items数量)<CR><LF>(只能有指定数量的items,items之间<CR><LF>分隔) | *?<CR><LF>[任意数量items].<CR><LF> |
可以看出resp2到reps3,支持了更灵活,更精确的类型语义,在数据传输,解析上,有更大的灵活性和效率
redis6可以通过hello 2(默认协议) , hello 3 切换resp协议的版本,会根据新的协议格式返回相关信息,具体如下
192.168.23.87:6519> hello 3
1# "server" => "redis"
2# "version" => "6.0.6"
3# "proto" => (integer) 3
4# "id" => (integer) 4
5# "mode" => "standalone"
6# "role" => "master"
7# "modules" => (empty array)
hello3抓包
hello 3
%7
$6
server
$5
redis
$7
version
$5
6.0.6
$5
proto
:3
$2
id
:5
$4
mode
$10
standalone
$4
role
$6
master
$7
modules
*0
192.168.23.87:6519> hello 2
1) "server"
2) "redis"
3) "version"
4) "6.0.6"
5) "proto"
6) (integer) 2
7) "id"
8) (integer) 4
9) "mode"
10) "standalone"
11) "role"
12) "master"
13) "modules"
14) (empty array)
hello2抓包
*14
$6
server
$5
redis
$7
version
$5
6.0.6
$5
proto
:2
$2
id
:5
$4
mode
$10
standalone
$4
role
$6
master
$7
modules
*0
通过hello2 和hello3 的抓包返回数据,可以发现,返回的第一列数据,已经从 *14 变为了 %7
即从 kv各占一行的list 变为了 size=7的map, 从语义的清晰和数据的容错上都有更好的表现
其他类似的类型"首字符"的转变就不再演示
3.redis客户端缓存
客户端缓存是redis6推出的一个比较重要的功能,正式发版前后,还有过比较大的调整修改
客户端缓存的目的是减少通过网络读取redis库的数量,将 tcp获取数据 -> 本地内存获取数据 ,以此获得数量级的提升
客户端缓存最适合的场景是 多读少写, 比如热帖,热评等,阅读量和回复/修改量有很大(数量级)差别,直接从内存读写的话,可以在不升级服务器配置的情况下,将相应请求响应支持数再提升一个数量级
ps:目前redis-cluster-proxy模块不支持客户端缓存设置
客户端缓存只有在resp3的协议下才能最好的实现(resp2只能曲线实现,这里就不多描述了)
客户端缓存有两种模式
默认模式:服务器记录客户端(id)访问了哪些key,当其中的key发生变更时给客户端发送失效信息,消耗服务器端内存
广播模式:客户端订阅访问过的key的前缀,当符合模式的key发生变更就会被通知(即使变更的key没有被客户端缓存),服务器端不记录客户端访问的key,因此不会消耗服务器端的内存;
两者适用于不同的场景
1.默认模式消耗的是服务的资源(记录key-客户端id的时效映射表),广播模式消耗的是网络带宽 + 客户端资源(即使没有缓存,只要是订阅的key前缀被修改,都会收到通知)
2.当订阅客户端较多,且和key前缀有强关联(业务相关)时,适合广播模式,因为服务器可以对每一个key前缀做一次加工,然后将加工后的数据按订阅客户端id重复群发,如果是默认模式的话,只能挨个发送
可以通过 client tracking on 或者 client tracking off 来开启关闭客户端缓存模式
开启的缓存模式有
CLIENT TRACKING on REDIRECT 8 BCAST {0,}[prefix 匹配前缀] //订阅匹配前缀的失效消息(不指定前缀则订阅全部key的失效消息)
CLIENT TRACKING on REDIRECT 8 [optin | optout]
CLIENT CACHING yes
当使用optin选项时,只有执行 CLIENT CACHING yes 后的第一个get才会被订阅/缓存
如果是事务/Lua脚本中执行 CLIENT CACHING yes , 则会订阅/缓存全部涉及的key
需要注意的是,两种模式的切换,需要通过 CLIENT TRACKING off 来切换
代码示例
192.168.23.87:6519> CLIENT TRACKING on REDIRECT 8
OK
192.168.23.87:6519> CLIENT TRACKING on REDIRECT 7
(error) ERR The client ID you want redirect to does not exist
192.168.23.87:6519> CLIENT TRACKING on bcast
(error) ERR You can't switch BCAST mode on/off before disabling tracking for this client, and then re-enabling it with a different mode.
192.168.23.87:6519> CLIENT TRACKING off
OK
192.168.23.87:6519> CLIENT TRACKING on REDIRECT 8 BCAST prefix k
OK
4.redis代理模块redis-cluster-proxy
为了更方便的管理redis集群,简化客户端的操作,redis6推出了官方的代理模块redis-cluster-proxy
redis-cluster-proxy的启动很简单
git clone https://github.com/artix75/redis-cluster-proxy
cd redis-cluster-proxy
make install
redis-cluster-proxy {1,}[ cluster-master:port] -p 7777(不设置的默认端口)
简单4个命令就启动了对一个集群的proxy
链接proxy的方式与client链接server一致,指定ip,port即可链接
redis-cli -h 192.168.23.87 -p 7777
如果需要个proxy设置一个默认用户(权限),可以在启动时时添加参数
redis-cluster-proxy --auth-user default --auth default 192.168.23.87:7777
除此之外,还可以设置连接池最大/最小/默认值,填充的间隔和时间等参数
ps:需要注意的是,链接proxy的客户端可以是redis6以前的版本,但之前的版本会使用resp2的协议,以proxy info命令执行的结果区别展示如下
proxy info命令展示的信息有:
多路复用的api:epoll
端口:7777
proxy已经运行的秒/时间
使用内存/系统内存
连接proxy的client数/共享连接池连接数/每个连接使用数
活跃连接cluster的ip:port列表
可以通过proxy help 查看帮助
proxy help
proxy info 可以查看cluster的master节点信息(ip,port,solt数量,分片数量,连接数),与proxy cluster info一致
proxy config get 配置key 可以查看proxy的相关配置的值
proxy config get 配置key 设置value 可以设置proxy的先关值
其中几个比较重要的参数
PROXY CONFIG SET enable-cross-slot 1 开启跨solt查询(默认关闭)
PROXY MULTIPLEXING STATUS | OFF 查询多路复用的状态,或者关闭多路复用(使用专有链接)
PROXY CONFIG SET log-level debug 设置日志级别为debug(debug,info,success,warning,error(默认为debug))
PROXY COMMAND [UNSUPPORTED|CROSSSLOTS-UNSUPPORTED] 查看[所有proxy | proxy跨solt查询]不支持的命令
以上是redis6主要特性以及使用场景的大致介绍,其他像"并发进行socket读写",消息队列模块,无磁盘数据同步,rdb文件加载速度优化等因为篇幅时间有限,就没有过多描述了
谢谢阅读!
网友评论