bitfield命令
redis3.2后新增了一个bitfield命令,可以一次对多个位进行操作.这个指令有三个子指令,get,set,incrby,都可以对指定位片段进行读写,但最多只能处理64个连续的位,如超过64位,则要使用多个子指令,bitfield可以一次执行多个子指令。
Redis位字段允许您设置、递增和获取任意位长度的整数值。例如,您可以操作无符号1位整数到有符号63位整数的任何整数。
这些值是使用二进制编码的Redis字符串存储的。位字段支持原子读、写和增量操作,是管理计数器和类似数值的好选择。
127.0.0.1:6379> set w hello
OK
以上代码存储的位数据为:
字母 | 数值 | 二进制(高位<-低位) |
h | 104 | 0110 1000 |
e | 101 | 0110 0101 |
l | 108 | 0110 1100 |
l | 108 | 0110 1100 |
o | 111 | 0110 1111 |
127.0.0.1:6379> bitfield w get u4 0 #从w的第一个位开始取4个位(0110),结果为无符号数(u)
1) (integer) 6
127.0.0.1:6379> bitfield w get u3 2 #从w的第三个位开始取3个位(101),结果为无符号数(u)
1) (integer) 5
127.0.0.1:6379> bitfield w get i4 0 #从w的第一个位开始取4个位(0110),结果为有符号数(i)
1) (integer) 6
127.0.0.1:6379> bitfield w get i3 2 #从w的第三个位开始取3个位(101),结果为有符号数(i)
1) (integer) -3
从上可知,有符号数最多可以取64位,无符号数只能取63位.( redis 协议中的integer是有符号数,最大64位).
也可以一次执行多个子指令:
127.0.0.1:6379> bitfield w get u4 0 get u3 2 get i4 0 get i3 2
1) (integer) 6
2) (integer) 5
3) (integer) 6
4) (integer) -3
也可以用set修改字符:
127.0.0.1:6379> bitfield w set u8 8 97 #从第9个位开始,将接下来8个位用无符号数97 ( 字母a) 替换
1) (integer) 101
127.0.0.1:6379> get w
"hallo"
incrby对指定范围的位进行自增操作,如操作后有数据溢出,redis的处理是折返,即将益处的符号位丢掉,比如:8位的无符号数255,加1后变为0,而8位的有符号数127,加1后成-128.
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w incrby u4 2 1 #从第3个位开始,对接下来的4位无符号数+1
1) (integer) 11
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 14
127.0.0.1:6379> bitfield w incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w incrby u4 2 1 #溢出折返了
1) (integer) 0
也可以选择溢出行为,还可以选择 失败(fail,报错不执行), 折返( wrap ), 饱和截断(sat, 超过了范围就停留在最大或最小值).
127.0.0.1:6379> set w hello
OK
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 11
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 14
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield w overflow sat incrby u4 2 1 #保持了最大值
bitfield类型使用
1、bitfield key [get type offset]
127.0.0.1:6379> get k1
"hello"
127.0.0.1:6379> bitfield k1 get i8 0
1) (integer) 104
127.0.0.1:6379> bitfield k1 get i8 8
1) (integer) 101
127.0.0.1:6379> bitfield k1 get i8 16
1) (integer) 108
2、bitfield key [set type offset value]
127.0.0.1:6379> get k1
"hello"
127.0.0.1:6379> bitfield k1 set i8 8 120
1) (integer) 101
127.0.0.1:6379> get k1
"hxllo"
3、bitfield key [incrby type offset increment]
127.0.0.1:6379> bitfield k1 incrby u4 2 1
1) (integer) 11
127.0.0.1:6379> bitfield k1 incrby u4 2 1
1) (integer) 12
127.0.0.1:6379> bitfield k1 incrby u4 2 1
1) (integer) 13
127.0.0.1:6379> bitfield k1 incrby u4 2 1
1) (integer) 14
127.0.0.1:6379> bitfield k1 incrby u4 2 1
1) (integer) 15
127.0.0.1:6379> bitfield k1 incrby u4 2 1
1) (integer) 0
这里默认incrby使用wrap参数
4、overflow[wrap][sat][fall]
wrap:使用回绕(wrap around)方法处理有符号整数和无符号整数的溢出情况。
sat:使用饱和计算(saturation arithmetic)方法处理溢出,下溢计算结果为最小的整数值,而上溢计算的结果为最大的整数值。
127.0.0.1:6379> bitfield k1 overflow sat set i8 0 145
1) (integer) -122
127.0.0.1:6379> bitfield k1 get i8 0
1) (integer) 127
fail:命令将拒绝执行那些会导致上溢或下溢情况出现的计算,并向用户返回空值表示计算未被执行。
127.0.0.1:6379> bitfield k1 overflow fail set i8 0 230
1) (nil)
例子
假设你正在跟踪一个网络游戏中的活动。你需要为每个玩家保留两个关键的指标:黄金总量和被杀死的怪物数量。因为你的游戏很容易上瘾,所以这些计数器应该至少有32位宽。
您可以为每个玩家用一个位字段来表示这些计数器。
1、新玩家以1000黄金开始(计数器偏移量为0)
> BITFIELD player:1:stats SET u32 #0 1000
1) (integer) 0
2、杀死俘虏王子的妖精后,加上赚取的50黄金,并增加“被杀”计数器(偏移1)
> BITFIELD player:1:stats INCRBY u32 #0 50 INCRBY u32 #1 1
1) (integer) 1050
2) (integer) 1
3、付给铁匠999黄金,买一把传说中的锈迹斑斑的匕首
> BITFIELD player:1:stats INCRBY u32 #0 -999
1) (integer) 51
4、获取玩家的统计数据
> BITFIELD player:1:stats GET u32 #0 GET u32 #1
1) (integer) 51
2) (integer) 1
基本命令
BITFIELD以原子方式设置、递增和读取一个或多个值。
BITFIELD_RO是BITFIELD的只读变体。
性能
BITFIELD复杂度是O(n),其中n是访问的计数器数。