Redis的指令组(一)

写在前面

简介

上篇文章介绍了Redis的安装,官网上是这样介绍的,Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)
这段话高度概括了Redis的功能,它支持多种数据结构,提供多种可持久化方案,并且提供分布式和集群的部署方案,保证高可用性。
单看上面的介绍,咱们可能还感觉不到redis的强大之处。下面将同是作为内存存储的开源的memcache与Redis做一个对比。

与Memcached的对比

数据来源于 https://db-engines.com/
下列图中第二列为Memcached第三列为Redis。
排名情况

  • 在缓存数据库排名中Redis排名第一,Memcached排名第四
    在这里插入图片描述
  • 上图中Typing类型对比,Memcached那一栏为no(其实是只支持string类型),而Redis支持多种类型。
    在这里插入图片描述
  • Redis支持二级索引,Memcached不支持。他们同为NoSql。Redis比Memcached支持的语言多得多,当面临多语言开发团队的时候Redis会有更好的支持性。
    在这里插入图片描述
  • Redis 服务器支持Lua脚本执行。Redis 使用单个 Lua 解释器去运行所有脚本,并且, Redis 也保证脚本会以原子性(atomic)的方式执行:当某个脚本正在运行的时候,不会有其他脚本或 Redis 命令被执行。这和使用 MULTI / EXEC 包围的事务很类似。在其他别的客户端看来,脚本的效果(effect)要么是不可见的(not visible),要么就是已完成的(already completed)。而Memcached不支持任何语言脚本。
  • Redis提供分布式和高可用的集群部署方案,而Memcached不支持。
  • Redis提供一些原子性操作,而Memcached不支持。
  • Redis支持持久化,而Memcached不支持。

redis的命令组

命令组介绍

redis的命令十分丰富,其分为14个命令组,如下:

  • cluster :跟集群操作有关的命令组,比如:cluster info等
  • connection:跟链接有关的命令组,比如:auth,quit,select 等
  • geo:跟地理位置有关的命令组,比如:geoadd,geohash等
  • hashes:操作数据类型为map的命令组,比如:hset,hmset,hget等
  • HyperLogLog:获取基数的命令组(一般用于大数据统计等),比如:pfadd等
  • keys:操作key的命令组,比如:del,object,expire等
  • lists:操作数据类型为列表的命令组,比如lset,lget,lpush,lpop等
  • pub/sub:发布订阅操作指令组,比如pubsub,publish等
  • scripting:执行lua脚本的操作指令组,比如eval,evalsha等
  • server:操作服务端数据的指令组,比如:bgrewriteaof,bgsave等
  • sets:操作数据类型为集合的指令组,比如 sadd,scard,sdiff等
  • sorted sets:操作数为有序集合的指令组,比如zadd,zcard等
  • streams:流操作指令组,比如:xack,xadd等
  • strings:操作数据类型为字符的指令组,比如:set,get,mset,setnx等
  • transcations:事务的指令组,比如:exec,watch等

strings命令组

对字符串的操作指令

在客户端通过 help @string 可以查看所有string的操作指令

在这里插入图片描述

  • set指令可以给一个key设置一个值,后面可以跟 [ex seconds(有效期单位为秒) | px milliseconds(有效期单位为毫秒)] | [nx(没有key是设置成功) | xx(有key是设置成功)]
    下面是在客户端的运行事例即结果。

在这里插入图片描述
set key value nx , set key value ex seconds, set key value px millisenconds value的设置方式也可以通过 setnx key valuesetex key seconds value, psetex key milliseconds value实现。
setnx指令保证只能有一个线程可以将key设置成功,所以该指令经常用于分布式锁,为了避免死锁,可以设置超时时间。

不过没有setxx
在这里插入图片描述
对于过期的key,Redis并不会马上主动清除key,其实Redis的清楚策略有三种:

  1. 被动删除:当客户端操作一个过期的key时,才会主动删除key,比如:get,set,del, incr等
  2. 主动删除:服务端会定期检查整理自身的资源,这个过程中会删除一批过期的key
  3. 超过maxmemory时,会主动删除过期的key
  • setrange 指令可以根据给定的下标替换key的值。如果key为空并且不是从第0个位置开始替换的则用0补充。

在这里插入图片描述

  • get指令可以获取通过set指令设置的key的值。
  • getset指令除了设置key的值还返回老的值。
  • getrange指令可以截取指定位置的字符串。redis中除了正向索引(1,2,3…) 还有反向索引(…-3,-2,-1),两者可以结合使用。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • append指令可以在给定个key后面追加内容

在这里插入图片描述
在这里插入图片描述
除了设置单个key的,redis还支持设置多个值的指令。

  • mget指令可以一次获取多个key的值
  • mset指令可以一次设置多个key的值

在这里插入图片描述
在这里插入图片描述

  • msetnx指令可以一次性设置多个值,仅在设置的key都不存在时成功。如果有多余一个key存在时那么所有的key都设置不成功。

在这里插入图片描述
在这里插入图片描述

  • strlen 指令返回指定key的字节个数

在这里插入图片描述
通过上面的运行结果,对于k1的长度是10没有问题,但是k2返回的长度是6 。因为我的客户端是UTF8编码方式,UTF8会将一个汉字用三个字节表示,这里两个汉字所以返回的长度是6 。说明strlen获取的长度是字节的个数。通过get指令获取的k2的值返回的是字节编码。
Redis是一个二进制安全的存储系统,即客户端以什么样的编码格式发给服务端,服务端会不做任何处理的存入系统,当获取时会原封不动的返回给客户端。所以对于同一个key存储获取获取的多个客户端需要保持编码一直,否则可能会出现解码后乱码的情况。
比如对于汉字“中国”UTF8编码的客户端与GBK编码的客户端有不同的编码,所以服务端存储的也会不一样,通过strlen获取的长度也不一样前者长度为 6 后者长度 为 4.下面看一下运行结果:

客户端为UTF8编码的运行结果:
在这里插入图片描述
客户端为GBK编码的运行结果:
在这里插入图片描述
通过redis-cli --raw链接服务端,get指令会按客户端的编码进行格式化:
在这里插入图片描述
可以发现k2的值是乱码,因为设置k2的客户端的编码为UTF8,而get k2的客户端的编码为GBK。
这就是Redis的二进制安全。

对数值类型操作指令

Rredis对数值类型的操作也是放到strings指令组里的。

  • decr指令对key进行减一操作
  • decrby指令对key减去指定的值
  • incr指令对key进行加一操作
  • incrby指令对key加上指定的值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在并发的情况下redis保证对key的加减操作具有原子性,不会出现多个线程同时对同一个值进行加减操作。
如果指定的key不存在,那么在执行这些操作之前,会先将它的值设定为0。
如果指定的key中存储的值不是字符串类型(fix:)或者存储的字符串类型不能表示为一个整数,那么执行这个命令时服务器会返回一个错误(eq:(error) ERR value is not an integer or out of range)。
这些操作仅限于64位的有符号整型数据。
通过incr可以实现网站限流的操作:

UNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current > 10 THEN
    ERROR "too many requests per second"
ELSE
    value = INCR(ip)
    IF value == 1 THEN
        EXPIRE(value,1)
    END
    PERFORM_API_CALL()
END

上述方法的思路是,从第一个请求开始设置过期时间为1秒。如果1秒内请求数超过了10个,那么会抛异常。否则,计数器会清零。
上述代码中,可能会进入竞态条件,比如客户端在执行INCR之后,没有成功设置EXPIRE时间。这个ip的key 会造成内存泄漏,直到下次有同一个ip发送相同的请求过来。
把上述INCR和EXPIRE命令写在lua脚本并执行EVAL命令可以避免上述问题(只有redis版本>=2.6才可以使用)。
Redis并没有一个明确的类型来表示整型数据,所以这些操作是一个字符串操作。
在java中数值类型的长度都有固定的字节个数。比如整型为固定的4个字节。但是在redis中并不是这样,9999 与 10000 所占的字节个数不一样(对于浮点数也是一样):

在这里插入图片描述

执行这些操作的时候,key对应存储的字符串被解析为10进制的64位有符号整型数据
事实上,Redis 内部采用整数形式(Integer representation)来存储对应的整数值,所以对该类字符串值实际上是用整数保存,也就不存在存储整数的字符串表示(String representation)所带来的额外消耗。

  • incrbyfloat指令对key加上指定的浮点值
    没有 decrbyfloat。

在这里插入图片描述
在这里插入图片描述

bitmap(位图)操作指令

在strings的指令组里面还有一类以bit开头的指令,这些指令是按位来设置一个key的。我们都知道,一个字节是8个bit位,每个bit位都可以用0或者1来表示。
比如 ‘A’的ASCII码值为 0 1000001 在redis中可以这样设置:

在这里插入图片描述

  • setbit指令可以设置key的value在offset出的bit值。其中偏移量offset的取值范围为 0 < offset < 232 - 1

在这里插入图片描述

  • getbit指令获取key对应的value在offest处的bit值。当offest超出value的长度的时候总是返回0.

在这里插入图片描述
在这里插入图片描述
通过上面strlen的返回结果可知,即使通过setbit设置的key,redis还是按字节数统计的,并且是按字节返回的。当通过getbit获取超出value的长度的时候,并不会开辟空间。

  • bitcount指令统计value被设置为1的bit数。

在这里插入图片描述
在这里插入图片描述
bitcount 可以指定start end,但是这个start,end是按字节并不是按位。

  • bitfield key get 指令可以获取一个value从指定偏移位置开始截取指定长度的bit位并转为10进制的有符号(或者无符号)的值。
    这个指令是区别于 get 和getbit指令的。
    比如对于一个key的value是0 1000001 也就是 ‘A’ 。
    • get key 只能按字节获取,也就是只能返回 ‘A’。
    • getbit key offest 只能获取某一位的bit值。
    • bitfield key get指令 可以获取任意bit位置的任意长度的bit位,这里定义为

对于0 1000001 也就是 ‘A’,想要获取前四位的bit值 0 100
可以这样操作:
在这里插入图片描述
bitfield k1 get u4 0 的意思是从key为k1的value中从第0个位置开始截取4(4)位按无符号(u)整数返回
bitfield k1 get i4 0 的意思是从key为k1的value中从第0个位置开始截取4(4)位按有符号(i)整数返回
bitfield 可以将get连续使用。
在这里插入图片描述

  • bitfield key set 指令可以设置一个value的指定域的值,并返回他的原值。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
简单说一下redis是如何将二进制转换为有符号十进制数字的。
对于k1 1 0001000

  • 当获取无符号整数时比较简单,就直接按权展开求和即1 * 27 + 0 * 2 6 + 0 * 2 5 + 0 * 2 4 + 1 * 2 3 + 0 * 2 2 + 0 * 2 1 + 0 * 2 0 = 136
  • 当获取有符号整数时,若第0位为1,
    • 从第1位开始取数 0001000
    • 将取到的数字求返 1110111
    • 将求返的数字 + 1后 与第0位结合 11111000 ,第0位为符号位 后七位按权展开求和 则为 -120
  • 当取有符号整数时,若第0位为0,则直接按权展开求和

当set的值超过指定域的最大值时,则默认从低位开始截取指定的长度存入库。

在这里插入图片描述
bitfield key incrby 可以对value的指定域进行自增或自减(若给定的值为负数)。

在这里插入图片描述
当自增(自减)的结果超出域的最大范围的时候redis给了三种处理方式 并且用 overflow 表示

  • overflow wrap : 回环算法,适用于有符号和无符号整型两种类型。对于无符号整型,回环计数将对整型最大值进行取模操作(C语言的标准行为)。对于有符号整型,上溢从最负的负数开始取数,下溢则从最大的正数开始取数,例如,如果i8整型的值设为127,自加1后的值变为-128。
  • overflow sat : 饱和算法,下溢之后设为最小的整型值,上溢之后设为最大的整数值。例如,i8整型的值从120开始加10后,结果是127,继续增加,结果还是保持为127。下溢也是同理,但量结果值将会保持在最负的负数值。
  • overflow fail :失败算法,这种模式下,在检测到上溢或下溢时,不做任何操作。相应的返回值会设为NULL,并返回给调用者。
    注意每种溢出(OVERFLOW)控制方法,仅影响紧跟在INCRBY命令后的子命令,直到重新指定溢出(OVERFLOW)控制方法。
    如果没有指定溢出控制方法,默认情况下,将使用WRAP算法

在这里插入图片描述

  • bitop指令可以对一个或多个key进行按位 与(and)、或(or)、非(not)、异或(xor)操作。除了非(not)只能接受一个key,剩下的三个都可以接收多个key。

在这里插入图片描述

  • bitpos命令返回value值内第一个为0或者1的bit的位置。

在这里插入图片描述
在这里插入图片描述

如果我们在空字符串或者0字节的字符串里面查找bit为1的内容,那么结果将返回-1。
如果我们在字符串里面查找bit为0而且字符串只包含1的值时,将返回字符串最右边的第一个空位。如果有一个字符串是三个字节的值为0xff的字符串,那么命令BITPOS key 0将会返回24,因为0-23位都是1。
基本上,我们可以把字符串看成右边有无数个0。
然而,如果你用指定start和end范围进行查找指定值时,如果该范围内没有对应值,结果将返回-1。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值