Redis数据结构-String字符串
1.String字符串
字符串类型是Redis中最基础的数据结构,关于数据结构与要特别注意的是:首先Redis中所有的键的类型都是字符串类型,而且其他集中数据结构也都是在字符串类似基础上进行构建,例如列表和集合的元素类型是字符串类型,所有字符串类型能为其他4中数据结构的学习奠定基础。其次字符串类型的值可以是字符串,包含一般格式的字符串和JSON,XML格式的字符串;数字,也可以是整数或者浮点数;甚至是二进制流数据,例如图片,音频,视频等。不过一个字符串的最大值不能超过512MB
2.常见命令
2.1 SET
将String类型的value设置到key中。如果之前key存在,则覆盖,无论原来的数据类型是什么。之前关于此key的TTL也会全部失效。
语法:SET key value [expiration EX seconds | PX milliseconds] [NX |XX]
时间复杂度:O(1)
选项:
EX seconds ——使用秒作为单位设置key的过期时间
PX milliseconds——使用毫秒作为单位设置key的过期时间
NX——只要key不存在时才进行设置,即如果key之前已经存在,设置不执行
XX——只在key存在时才进行设置,即如果key之前已经存在,设置不执行
返回值:
如果设置成功,返回OK。
如果由于SET指定NX或者XX但条件不满足,SET不会执行,并返回(nil)
示例:
2.2 MGET
一次性获取多个key的值。如果对应的key不存在或者对应的数据类型不是string,返回nil
语法:MGET key [key ...]
时间复杂度:O(1)(或O(N),N是key的数量)
返回值:对应value的列表
示例:
2.3 MSET
一次设置多个key的值
语法:MSET key value [key value...]
时间复杂度:O(1)(或O(N),N是key的数量)
返回值:永远是OK
示例:
多次 get vs单次mget
Redis是一个客户端-服务器结构的程序,客户端和服务器之间通信是通过网络实现的,多次get产生了多次请求,进行多次网络通信。单次mget只进行一次网络通信,mget减少了网络事件,所以性能较高
2.4 SETNX
设置key-value但只允许在key之前不存在的情况下
语法:SETNX key value
时间复杂度:O(1)
返回值:1表示设置成功,0表示没有设置成功
示例:
2.5 INCR
将key对应的value(String类型)表示的数字+1。如果key不存在,则视为key对应的value是0。如果key对应的string不是一个整数或者范围超过了64位有符号整数,则报错
语法:INCR key
时间复杂度:O(1)
返回值:integer类型的加完后的数值
示例:
2.6 INCRBY
将key对应的string表示的数字加上对应的值。如果key不存在,则视为key对应的value是0.如果key对应的string不是一个整数或者范围超过了64位有符号整数,则报错
语法:INCRBY key decrement
时间复杂度:O(1)
返回值:integer类型的加完后的数值
示例:
2.7 DECR
将key对应的string表示的数字减一。如果key对应的value是0.如果key对应的string不是一个整数或者范围超过了64位有符号整数,则报数
语法:DECR key
时间复杂度:O(1)
返回值:integer类型的减完后的数值
示例:
2.8 INCRBYFLOAT
将key对应的string表示的浮点数加上对应的值。如果对应的值是负数,则视为减去对应的值。如果key不存在,则视为key对应的value是0.如果key对应的不是string,或者不是一个浮点数,则报错。允许采用科学计数法表示浮点数
语法:INCRBYFLOAT
时间复杂度:O(1)
返回值:加/减完后的数值
示例:
2.9 APPEND
如果key已经存在并且是一个string,命令会将value追加到原有的string的后面。如果key不存在,则效果等同于SET命令
语法:APPEND KEY VALUE
时间复杂度:O(1)
返回值:追加完成之后string的长度
示例:
2.10 GETRANGE
返回key对应的string的子串,有start和end确定(左闭右闭)。可以使用负数表示倒数。-1表示倒数第一个字符,其他的于此类似。超过范围的偏移量会根据string的长度调整成正确的值
语法:GETRANGE key start end
时间复杂度:O(N),N为[start,end]区间的长度。由于string通常比较短,可以视为是O(1)
返回值:string类型的子串
示例:
2.11 SETRANGE
覆盖字符串的一部分,从指定的偏移开始
语法:SETRANGE key offset value
时间复杂度:O(N),N为value的长度,由于一般的value比较短,通常视为O(1)
返回值:替换后的string
示例:
2.11 STRLEN
获取key对应的string的长度。当key存放的类型不是string时,报错
语法:STRLEN key
时间复杂度:O(1)
返回值:string的长度,或者当key不存在时,返回0
示例:
3.String的内部编码
字符串类型的内部编码有3种:
int:8个字节的长整型
embstr:小于等于39个字节的字符串
raw:大于39个字节的字符串
Redis会根据当前值的类型和长度动态决定使用那种内部编码实现
redis存储小数,本质上还是当字符串来存储的,这意味着每次进行算数运算时,都需要将字符串转为小数,再将运算结果转为字符串,计算过程中的转换都是开销
4.String的典型场景
4.1缓存功能
缓存功能是String比较典型的运用场景,其中Redis作为缓冲层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用
MySQL+Redis组成的缓存存储框架结构
业务层 也可以看做是应用服务器,缓存层是Redis服务器(用于存放热点数据),存储层是MySQL服务器
假设业务是根据用户uid获取用户信息:
首先从Redis获取用户信息,如果没有从Redis中得到用户信息,及缓存miss,则进一步从MySQL中获取对应的信息,随后写入缓存并返回。如果从Redis中获取到用户的信息,则直接返回。通过增加缓存的功能,可以极大地提高查询的效率,也降低了对MySQL的访问次数
4.2计数功能
许多应用都会使用Redis作为技术的基础工具,他可以实现快速的技术,查询缓存的功能,同时数据可以一步处理或者落地到其他的数据源
实际的开发一个成熟,稳定的真实技术系统,要面临的挑战远不止如此简单:防作弊,按照不同的维度技术,避免单点问题(单个redis挂了,数据丢失),数据持久化到底层数据源等
4.3共享会话
一个分布式Web服务将用户的Session信息保存在各自的服务器中,但这样会造成一个问题:处于负载均衡的考虑,分布式服务会将用户的访问请求均衡到不同的服务器上,并且通常无法保证用户每次请求都会被均衡到同一台服务器上,这样当用户刷新一次访问是可能会发现需要重新登陆的,这个问题对于用户来说是非常不适的
Session分散存储
为了解决这个问题,可以使用Redis将用户的Session信息进行集中管理。
Redis集中管理Session
这种模式下,无论用户被均衡到哪台服务器上,都会集中从Redis中查询,更新Session信息
4.4短信验证码
很多应用处于安全考虑,会在每次登陆时,让用户输入手机号并且配合给手机发送验证码,然后让用户输入收到的验证码进行验证,从而确定是否是用户本人。为了短信接口不会频繁访问,会限制用户每分钟获取验证码的频率,例如一分钟不能超过五次等
解决思路:
通过Redis命令对制定的key设置有效时间,在有效时间内访问Redis即可成功,如果超出有效时间就登录失败
当然实际中并不会像我描述的这么简单,还需要根据业务的场景进行具体的编写