深入剖析Redis系列(五) - Redis数据结构之字符串

栏目: 数据库 · 发布时间: 5年前

内容简介:字符串类型是除了

字符串类型是 Redis 最基础的数据结构。 字符串类型 的值实际可以是 字符串简单复杂 的字符串,例如 JSONXML )、 数字 (整数、浮点数),甚至是 二进制 (图片、音频、视频),但是值最大不能超过 512MB

深入剖析 <a href='https://www.codercto.com/topics/18994.html'>Redis</a> 系列(五) - Redis数据结构之字符串

正文

1. 相关命令

1.1. 常见命令

1.1.1. 设置值

set key value [ex seconds] [px milliseconds] [nx|xx]

set 命令有几个选项:

  1. ex seconds :为 设置 秒级过期时间
  2. px milliseconds :为 设置 毫秒级过期时间
  3. nx :键必须 不存在 ,才可以设置成功,用于 添加
  4. xx :与 nx 相反,键必须 存在 ,才可以设置成功,用于 更新

除了 set 选项, Redis 还提供了 setexsetnx 两个命令:

setex key seconds value setnx key value
  • setex :设定键的值,并指定此键值对应的 有效时间
127.0.0.1:6379> setex key1 5 value1
OK
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> get key1
(nil)

复制代码
  • setnx :键必须 不存在 ,才可以设置成功。如果键已经存在,返回 0
127.0.0.1:6379> set key2 value1
OK
127.0.0.1:6379> setnx key2 value2
(integer) 1
127.0.0.1:6379> get key2
"value1"
复制代码

1.1.2. 获取值

get key

如果要获取的 键不存在 ,则返回 nil )。

127.0.0.1:6379> get not_exist_key
(nil)
复制代码

1.1.3. 批量设置值

mset key value [key value ...]

下面操作通过 mset 命令一次性设置 4键值对

127.0.0.1:6379> mset a 1 b 2 c 3 d 4
OK
复制代码

1.1.4. 批量获取值

mget key [key ...]

通过下面操作 批量获取abcd 的值:

127.0.0.1:6379> mget a b c d
1) "1"
2) "2"
3) "3"
4) "4"
复制代码

批量操作命令,可以有效提高 开发效率 ,假如没有 mget 这样的命令,要执行 nget 命令的过程和 耗时 如下:

n次get时间 = n次网络时间 + n次命令时间

深入剖析Redis系列(五) - Redis数据结构之字符串

使用 mget 命令后,执行 nget 命令的过程和 耗时 如下:

n次get时间 = 1次网络时间 + n次命令时间

深入剖析Redis系列(五) - Redis数据结构之字符串

Redis 可以支撑 每秒数万读写操作 ,但这指的是 Redis 服务端 的处理能力,对于 客户端 来说,一次命令除了 命令时间 还是有 网络时间

假设 网络时间1 毫秒 ,命令时间为 0.1 毫秒(按照每秒处理 1 万条命令算),那么执行 1000get 命令和 1mget 命令的区别如表所示:

操作 时间
1000次get操作 1000 * 1 + 1000 * 0.1 = 1100ms = 1.1s
1次mget操作 1 * 1 + 1000 * 0.1 = 101ms = 0.101s

1.1.5. 计数

incr key

incr 命令用于对值做 自增操作 ,返回结果分为三种情况:

  • 值不是 整数 ,返回 错误
  • 值是 整数 ,返回 自增 后的结果。
  • 键不存在,按照值为 0 自增 ,返回结果为 1
127.0.0.1:6379> exists key
(integer) 0
127.0.0.1:6379> incr key
(integer) 1
复制代码

除了 incr 命令, Redis 还提供了 decr自减 )、 incrby自增指定数字 )、 decrby自减指定数字 )、 incrbyfloat自增浮点数 )等命令操作:

decr key incrby key increment decrby key decrement incrbyfloat key increment

很多 存储系统编程语言 内部使用 CAS 机制实现 计数功能 ,会有一定的 CPU 开销。但在 Redis 中完全不存在这个问题,因为 Redis单线程架构 ,任何命令到了 Redis 服务端 都要 顺序执行

1.2. 不常用命令

1.2.1. 追加值

append key value

append 可以向 字符串尾部 追加值。

127.0.0.1:6379> get key
"redis"
127.0.0.1:6379> append key world
(integer) 10
127.0.0.1:6379> get key
"redisworld"
复制代码

1.2.2. 字符串长度

strlen key

比如说,当前值为 redisworld ,所以返回值为 10

127.0.0.1:6379> get key
"redisworld"
127.0.0.1:6379> strlen key
(integer) 10
复制代码

1.2.3. 设置并返回原值

getset key value

getsetset 一样会 设置值 ,但是不同的是,它同时会返回 键原来的值 ,例如:

127.0.0.1:6379> getset hello world
(nil)
127.0.0.1:6379> getset hello redis
"world"
复制代码

1.2.4. 设置指定位置的字符

setrange key offeset value

下面操作将值由 pest 变为了 best

127.0.0.1:6379> set redis pest
OK
127.0.0.1:6379> setrange redis 0 b
(integer) 4
127.0.0.1:6379> get redis
"best"
复制代码

1.2.5. 获取部分字符串

getrange key start end

startend 分别是 开始结束偏移量偏移量0 开始计算,例如获取值 best前两个字符 的命令如下:

127.0.0.1:6379> getrange redis 0 1
"be"
复制代码

最后给出 字符串 类型命令的 时间复杂度 说明:

深入剖析Redis系列(五) - Redis数据结构之字符串

2. 内部编码

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

  • int: 8 个字节的 长整型

  • embstr: 小于等于 39 个字节的字符串。

  • raw: 大于 39 个字节的字符串。

Redis 会根据当前值的 类型长度 决定使用哪种 内部编码实现

  • 整数类型
127.0.0.1:6379> set key 8653
OK
127.0.0.1:6379> object encoding key
"int"
复制代码
  • 短字符串
#小于等于39个字节的字符串:embstr
127.0.0.1:6379> set key "hello,world"
OK
127.0.0.1:6379> object encoding key
"embstr"
复制代码
  • 长字符串
#大于39个字节的字符串:raw
127.0.0.1:6379> set key "one string greater than 39 byte........."
OK
127.0.0.1:6379> object encoding key
"raw"
127.0.0.1:6379> strlen key
(integer) 40
复制代码

3. 典型使用场景

3.1. 缓存功能

下面是一种比较典型的 缓存 使用场景,其中 Redis 作为 缓存层MySQL 作为 存储层 ,绝大部分请求的数据都是从 Redis 中获取。由于 Redis 具有支撑 高并发 的特性,所以缓存通常能起到 加速读写降低后端压力 的作用。

深入剖析Redis系列(五) - Redis数据结构之字符串

整个功能的伪代码如下:

public UserInfo getUserInfo(long id) {
    String userRedisKey = "user:info:" + id;
    String value = redis.get(userRedisKey);
    UserInfo userInfo;    
    if (value != null) {
        userInfo = deserialize(value);     
    } else {        
        userInfo = mysql.get(id);   if (userInfo != null) { 
            redis.setex(userRedisKey, 3600, serialize(userInfo));
        }
        return userInfo;
    }
}
复制代码

3.2. 计数

许多应用都会使用 Redis 作为 计数 的基础工具,它可以实现 快速计数查询缓存 的功能,同时数据可以 异步落地 到其他 数据源 。一般来说,视频播放数系统,就是使用 Redis 作为 视频播放数计数 的基础组件,用户每播放一次视频,相应的视频播放数就会自增 1

public long incrVideoCounter (long id) {
    String key = "video:playCount:" + id;
    return redis.incr(key);
}
复制代码

实际上,一个真实的 计数系统 要考虑的问题会很多: 防作弊 、按照 不同维度 计数, 数据持久化底层数据源 等。

3.3. 共享Session

一个 分布式 Web 服务将用户的 Session 信息(例如 用户登录信息 )保存在 各自 的服务器中。这样会造成一个问题,出于 负载均衡 的考虑, 分布式服务 会将用户的访问 均衡 到不同服务器上,用户 刷新一次访问 可能会发现需要 重新登录 ,这个问题是用户无法容忍的。

深入剖析Redis系列(五) - Redis数据结构之字符串

为了解决这个问题,可以使用 Redis 将用户的 Session 进行 集中管理 。在这种模式下,只要保证 Redis高可用扩展性的 ,每次用户 更新 或者 查询 登录信息都直接从 Redis 中集中获取。

深入剖析Redis系列(五) - Redis数据结构之字符串

3.4. 限速

很多应用出于安全的考虑,会在每次进行登录时,让用户输入 手机验证码 ,从而确定是否是用户本人。但是为了 短信接口 不被 频繁访问 ,会 限制 用户每分钟获取 验证码 的频率。例如一分钟不能超过 5 次,如图所示:

此功能可以使用 Redis 来实现,伪代码如下:

String phoneNum = "138xxxxxxxx";
String key = "shortMsg:limit:" + phoneNum;
// SET key value EX 60 NX
boolean isExists = redis.set(key, 1, "EX 60", "NX");
if (isExists != null || redis.incr(key) <= 5) {
    // 通过
} else {
    // 限速
}
复制代码

上述就是利用 Redis 实现了 限速功能 ,例如 一些网站 限制一个 IP 地址不能在 一秒钟之内 访问超过 n 次也可以采用 类似 的思路。

小结

本文简单的介绍了 Redis字符串数据结构基本命令内部编码相关应用场景


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

代码之髓

代码之髓

[日] 西尾泰和 / 曾一鸣 / 人民邮电出版社 / 2014-8 / 45.00元

《代码之髓:编程语言核心概念》作者从编程语言设计的角度出发,围绕语言中共通或特有的核心概念,通过语言演变过程中的纵向比较和在多门语言中的横向比较,清晰地呈现了程序设计语言中函数、类型、作用域、类、继承等核心知识。本书旨在帮助读者更好地理解各种概念是因何而起,并在此基础上更好地判断为何使用、何时使用及怎样使用。同时,在阅读本书后,读者对今后不断出现的新概念的理解能力也将得到提升。 《代码之髓:......一起来看看 《代码之髓》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换