【Redis】redis的数据类型、单线程模型和String的使用


在这里插入图片描述

1. 数据结构和内部编码

type 命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、list(列表)、hash(哈希)、set(集合)、zset(有序集合),但这些只是Redis对外显示的数据结构

redis的5种数据类型:
在这里插入图片描述
但是redis在底层实现这些数据结构的时候会有变数,也就是内部数据结构的编码方式

这样Redis会在合适的场景选择合适的内部编码,来进行优化。
在这里插入图片描述

可以使用 object encoding key查看实际编码的方式

在这里插入图片描述

2. redis的单线程模型

我们知道,redis是使用单线程处理所有的命令请求的,但不是说一个redis服务器进程内部真的就只有一个线程,其实有多个线程,多线程是在处理网络IO。

Redis内部只有⼀个服务窗口,多个客⼾端按照它们达到的先后顺序被排队在窗口口前,依次接受Redis的服务,不会发⽣并发问题,这个就是Redis的单线程执⾏模型。

为什么单线程还能这么快呢?(面试题)

  • 快、慢都是和其它关系型数据比的
  • redis的操作是访问内存,比访问硬盘快
  • redis的核心功能,比数据库的业务更简单
  • redis是单线程的,避免了多线程的开销
    • redis的每个操作,都是短平快的,就收简单操作一下内存,不是什么耗CPU的操作,即使使用多线程,提升也不大
  • redis使用epoll处理网络IO

3. String类型

字符串类型是Redis最基础的数据类型,关于字符串需要特别注意:

  • 首先Redis中所有的键的类型都是字符串类型,而且其他几种数据结构也都是在字符串类似基础上构建的
  • 字符串类型的值实际可以是字符串,数字,甚⾄是二进制流数据(最大值不能超过512MB)

在这里插入图片描述

3.1 常用命令

  1. set

将string 类型的value设置到key中。如果key之前存在,则覆盖,无论原来的数据类型是什么,之前关于此key的TTL也全部失效。

set key value [expiration EX seconds | PX milliseconds] [NX|XX]
  • EX seconds:使用秒作为单位设置key的过期时间。
  • PX milliseconds:使用毫秒作为单位设置key的过期时间。
  • NX:只在key不存在时才进⾏设置,即如果key之前已经存在,设置不执行。(添加)
  • XX:只在key存在时才进⾏设置,即如果key之前不存在,设置不执行。(修改)

在这里插入图片描述

由于带选项的SET命令可以被SETNXSETEXPSETEX 等命令代替,所以之后的版本中,Redis可能进行合并

介绍一个命令:FLUSHALL可以把redis上的所有键值对都删除(工作中慎用

  1. get

获取key对应的value。如果key不存在,返回nil。如果value的数据类型不是string,会报错。

get key

在这里插入图片描述

  1. mget、mset

mget:⼀次性获取多个key的值。如果对应的key不存在或者对应的数据类型不是string,返回nil。

mget key [key ...]

mset:⼀次性设置多个key的值。

mset key value [key value ...]

在这里插入图片描述

使用 mget、mset由于可以有效地减少了⽹络时间,所以性能相较更高
在这里插入图片描述

所以,学会使用批量操作,可以有效提高业务处理效率,但是要注意,每次批量操作所发送的键的数量也不是无节制的,否则可能造成单⼀命令执行时间过长,导致Redis阻塞。

  1. 计数命令
  • incr:将key对应的string表⽰的数字加⼀。
    • 如果key不存在,则视为key对应的value是0。
    • 如果key对应的string不是⼀个整型或者范围超过了64位有符号整型,则报错。
  • incrby:将key对应的string表⽰的数字加上对应的值。
  • decr:将key对应的string表⽰的数字减⼀。
    • 如果key不存在,则视为key对应的value是0。
    • 如果key对应的string不是⼀个整型或者范围超过了64位有符号整型,则报错。
  • decrby:将key对应的string表⽰的数字减上对应的值。
  • incrbyfloat:将key对应的string表示的浮点数加上对应的值。
    • 如果对应的值是负数,则视为减去对应的值。
    • 如果key 不存在,则视为key对应的value是0。
    • 如果key对应的不是string,或者不是⼀个浮点数,则报错。允许采⽤科学计数法表⽰浮点数。

在这里插入图片描述

  1. 其它命令
  • APPEND:如果key已经存在并且是⼀个string,命令会将value追加到原有string的后边。如果key不存在,则效果等同于SET命令。
APPEND KEY VALUE

在这里插入图片描述

  • getrange:返回key对应的string的⼦串,由start和end确定(左闭右闭)。
    • 可以使⽤负数表⽰倒数。-1代表倒数第⼀个字符,-2代表倒数第⼆个,其他的与此类似。
    • 超过范围的偏移量会根据string的⻓度调整成正确的值。
GETRANGE key start end

在这里插入图片描述

  • setrange:覆盖字符串的⼀部分,从指定的偏移开始
SETRANGE key offset value

offset大于键处字符串的当前长度时,Redis 会通过填充零字节(即 \x00)来使偏移量合适;填充的零字节是不可见字符,不会影响字符串的显示内容,但会影响字符串的实际长度和二进制表示

在这里插入图片描述

  • strlen:获取key对应的string的⻓度。当key存放的类似不是string时,报错。

在这里插入图片描述

下图对上方命令的总结(命令的效果、时间复杂度)
在这里插入图片描述

3.2 内部编码

字符串类型的内部编码有3种:

  • int:8个字节的⻓整型
  • embstr:小于等于39个字节的字符串
  • raw:大于39个字节的字符串

Redis 会根据当前值的类型和⻓度动态决定使⽤哪种内部编码实现。

在这里插入图片描述

3.3 应用场景

  1. 缓存功能

缓存功能是比较典型的缓存使用场景,其中Redis作为缓冲层,MySQL作为存储层,绝⼤部分请求的数据都是从Redis中获取。由于Redis具有⽀撑⾼并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。
在这里插入图片描述

  • 与MySQL等关系型数据库不同的是,Redis没有表、字段这种命名空间,而且也没有对键名有强制要求(除了不能使⽤⼀些特殊字符)。
  • 但设计合理的键名,有利于防⽌键冲突和项⽬的可维护性,比较推荐的方式是使用"业务名:对象名:唯⼀标识:属性"作为键名。
  • 例如MySQL的数据库名为vs,⽤⼾表名为user_info,那么对应的键可以使用"vs:user_info:6379"、“vs:user_info:6379:name” 来表示,
  1. 计数功能

许多应用都会使用Redis作为计数的基础⼯具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源。
当然,这个操作也可以使用数据库来完成,但是当访问量大时,数据库的服务器的压力是比较大的

如图所示,例如视频网站的视频播放次数可以使用redis来完成:用户每播放⼀次视频,相应的视频播放数就会自增1。

视频ID作为key,播放次数作为value
在这里插入图片描述

  1. 共享会话

⼀个分布式Web服务将用户的Session信息(例如⽤⼾登录信息)保存在各⾃的服务器中(如左图所示),但这样会造成⼀个问题:出于负载均衡的考虑,分布式服务会将用户的访问请求均衡到不同的服务器上,并且通常⽆法保证⽤⼾每次请求都会被均衡到同⼀台服务器上,这样当用户刷新⼀次访问是可能会发现需要重新登录,这个问题是用户无法容忍的。
在这里插入图片描述

为了解决这个问题,可以使⽤Redis将用户的Session信息进⾏集中管理,如右图所⽰,在这种模式下,只要保证Redis是⾼可⽤和可扩展性的,⽆论⽤⼾被均衡到哪台Web服务器上,都集中从Redis 中查询、更新Session信息。

  1. 手机验证码

很多应用出于安全考虑,会在每次进⾏登录时,让⽤⼾输⼊⼿机号并且配合给⼿机发送验证码,然后让用户再次输⼊收到的验证码并进⾏验证,从⽽确定是否是⽤⼾本⼈。
为了短信接⼝不会频繁访问,会限制用户每分钟获取验证码的频率,例如⼀分钟内只能获取一次

String 发送验证码(phoneNumber) {
    key = "shortMsg:limit:" + phoneNumber;
    // 设置过期时间为 1 分钟(60)    
    // 使⽤ NX,只在不存在 key 时才能设置成功    
    bool r = Redis 执⾏命令:set key 1 ex 60 nx
    if (r == false) {
        // 说明1分钟内设置过该⼿机的验证码了        
        return null;
    }
     
    // 说明之前没有设置过⼿机的验证码
	String validationCode = ⽣成随机的 6 位数的验证码(); 
    validationKey = "validation:" + phoneNumber;
    // 验证码 5 分钟(300 秒)内有效     
    Redis 执⾏命令:set validationKey validationCode  ex 300;
    // 返回验证码,随后通过⼿机短信发送给⽤⼾     
    return validationCode ;
 }
 
 // 验证⽤⼾输⼊的验证码是否正确
bool 验证验证码(phoneNumber, validationCode) {
    validationKey = "validation:" + phoneNumber;
    
    String value = Redis 执⾏命令:get validationKey;
    if (value == null) {
        // 说明没有这个⼿机的验证码记录,验证失败        
        return false;
    }
    if (value == validationCode) {
        return true;
    } else {
        return false;
    }
 }

以上介绍了使⽤Redis的字符串数据类型可以使⽤的几个场景,但其适⽤场景远不⽌于此,开发⼈员可以结合字符串类型的特点以及提供的命令,充分发挥自己的想象⼒,在自己的业务中去找到合适的场景去使⽤Redis的字符串类型。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值