Redis:08---字符串对象

一、字符串对象概述

  • 字符串类型是Redis最基础的数据结构。首先键都是字符串类型,而且其他几种数据结构都是在字符串类型基础上构建的,所以字符串类型能为其他四种数据结构的学习奠定基础

  • 字符串就是一个由字节组成的序列

  • 如下图所示,字符串类型的值实际可以是:

    • 字符串(简单的字符串、复杂的字符串(例如JSON、XML))

    • 数字 (整数、浮点数)

    • 二进制(图片、音频、视频),但是值最大不能超过512MB

二、命令

设置值(SET、SETEX、SETNX)

  • set:设置值。参数如下:

    • ex seconds:为键设置秒级过期时间

    • px milliseconds:为键设置毫秒级过期时间

    • nx:键必须不存在,才可以设置成功,用于添加

    • xx:与nx相反,键必须存在,才可以设置成功,用于更新

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

  • setex、setnx:它们的作用和set命令的ex和nx选项是一样的

    • setex:设置键的时候同时设置过期时间

    • setnx:键必须不存在,才可以设置成功,否则出错

setex key seconds value
setnx key value

  • setnx和setxx在实际使用中有什么应用场景吗?

    • 以setnx命令为例子,由于 Redis的单线程命令处理机制,如果有多个客户端同时执行setnx key value, 根据setnx的特性只有一个客户端能设置成功,setnx可以作为分布式锁的一种实现方案,Redis官方给出了使用setnx实现分布式锁的方法:http://redis.io/topics/distlock

获取值(GET)

get key
  • 如果要获取的键不存在,则返回nil(空)

批量设置值(MSET)

mset key value [key value ...]
  • 例如下面依次设置4个键值对:

批量获取值(MGET)

  • 如果有些键不存在,那么它的值为nil(空)

mget key [key ...]
  • 例如下面获取键为a、b、c、d、e的值,其中e键不存在

批量操作的好处

  • 批量操作命令可以有效提高开发效率,假如没有mget这样的命令,要执行n次get命令需要耗时如下:

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

  • 使用mget命令后,要执行n次get命令操作只需要耗时:

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

  • Redis可以支撑每秒数万的读写操作,但是这指的是Redis服务端的处理能力,对于客户端来说,一次命令除了命令时间还是有网络时间,假设网络时间为1毫秒,命令时间为0.1毫秒(按照每秒处理1万条命令算),那么执行1000次get命令和1次mget命令的区别如下图所示,因为Redis的处理能力已经足够高,对于开发人员来说,网络可能会成为性能的瓶颈

  • 学会使用批量操作,有助于提高业务处理效率,但是要注意的是每次批 量操作所发送的命令数不是无节制的,如果数量过多可能造成Redis阻塞或 者网络拥塞。

字符串的自增命令和自减命令:

命令用例和描述
INCRINCR key-name 将键存储的值加上l
DECRDECR key-name 将键存储的值减去Ⅰ
INCRBYINCRBY key-name amount 将键存储的值加上整数amount
DECRBYDECRBY key-name amount 将键存储的值减去整数amount
INCRBYELOAT工NCRBYFLOAT key-name amount 将键存储的值加上浮点数amount,这个命令在Redis 2.6或以上的版本可用

概念:

    • 用户可以通过给定一个任意的数值,对存储着整数或者浮点数的字符串执行自增(increment)、自减操作(decrement)

    • 在需要的时候,Redis还会将整数转换为浮点数

    • 整数的取值范围和系统的长整数(long integer)的取值范围相同(32位系统中就是32位有符号整数;64位系统中就是64位有符号整数)

    • 而浮点数的取值范围和精度则与IEEE 754标准的双精度浮点数(double)相同

  • 返回值:

    • INCR:返回增加后键的值。返回值分为三种:

    • DECR:返回删除后键的值

    • INCRBY:返回增加后键的值

    • DECRBY:返回删除后键的值

    • INCRBYFLOAT:返回增加后键的值

  • 注意事项:

    • 如果对一个不存在的键或者一个保存了空串的键执行自增或者自减操作,那么Redis在执行操作时会将这个键的值作为0来处理

    • 如果所操作的字符串不是一个能被解释为整数或者浮点数的字符串,那么这些命令的操作将返回一个错误

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

  • 演示案例如下:

     STRLEN:获取字符串长度(备注:中文占3个字节)

strlen key

 

  • GETSET:设置并返回原值。

  • getset和set一样会设置值,但是不同的是,它同时会返回键原来的值

getset key value

  • 下面给出了其他一些演示案例:

  • 注意SETRANGE的用法:

  • 下图是字符串类型命令的时间复杂度:

  • 命令

    时间复杂度

    set key value

    o(l)

    get key

    o(1)

    del key [key ...]

    o(k),k是键的个数

    mset key value [ key value ...]

    O(k),t是键的个致

    mget key [key ...]

    o(),I是键的个致

    incr key

    o1)

    decr key

    o(1)

    incrby key increment

    o(1)

    decrby key decrement

    o(1)

    incrbyfloat key increment

    o(1)

    append key value

    o(1)

    strlen key

    o(1)

    setrange key offset value

    o(1)

    getrange key start end

    oo),n是宁符串长度,由于获取字符串非常快,所以

    如果字符非不是很长,可以视阿为O(1)

三、内部编码

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

    • int:8个字节的长整型

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

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

演示说明

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

  • 整数类型示例如下:

  • 短字符串示例如下:

  • 长字符串示例如下:

四、典型使用场景

①缓存功能

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

  • 下面伪代码模拟了上图的访问过程:

//1.该函数用于获取用户的基础信息UserInfo getUserInfo(long id){...}//2.首先从Redis获取用户信息:// 定义键userRedisKey = "user:info:" + id;// 从Redis获取值value = redis.get(userRedisKey);if (value != null) {// 将值进行反序列化为UserInfo并返回结果userInfo = deserialize(value);return userInfo;}//3.如果没有从Redis获取到用户信息,需要从MySQL中进行获取,并将结果回写到Redis,添加1小时(3600秒)过期时间://从MySQL获取用户信息userInfo = mysql.get(id);// 将userInfo序列化,并存入Redisredis.setex(userRedisKey, 3600, serialize(userInfo));// 返回结果return userInfo
  • 整个功能的伪代码如下:

UserInfo getUserInfo(long id){userRedisKey = "user:info:" + idvalue = 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;}
  • 应用场景1:缓存热门图片

set redis-log.jpg redis-log-data
  • 应用场景2:存储文章。当用户想在博客中撰写一篇新文章的时候,程序就需要把文章的标题、内容、作者、发表时间等多 项信息存储起来,并在用户阅读文章的时候取出来这些信息。可以使用 mset mget msetnx 命令来进行

  • 开发提示:

    • 与MySQL等关系型数据库不同的是,Redis没有命令空间,而且也没有对键名有强制要求(除了不能使用一些特殊字符)

    • 但设计合理的键名,有利于防止键冲突和项目的可维护性,比较推荐的方式是使用“业务名:对象 名:id:[属性]”作为键名(也可以不是分号)

    • 例如MySQL的数据库名为 vs,用户表名为user,那么对应的键可以用"vs:user:1","vs:user:1:name"来表示,如果当前Redis只被一个业务使用,甚至可以去掉“vs:”。如 果键名比较长,例如“user:{uid}:friends:messages:{mid}”,可以在能描 述键含义的前提下适当减少键的长度,例如变为“u:{uid}:fr:m:{mid}”,从而减少由于键过长的内存浪费

②计数

  • 许多应用都会使用Redis作为计数的基础工具,它可以实现快速计数、 查询缓存的功能,同时数据可以异步落地到其他数据源

  • 应用场景1:文章长度计数功能、文章摘要、文章计数

    • 文章长度:STRLEN article:10086:content

    • 文章摘要:GETRANGE article:10086:content 0 5

    • 文章阅读计数:INCRBY article:10086:count

  • 应用场景2:例如笔者所在团队的视频播放数系统就是使用Redis作为视频播放数计数的基础组件,用户每播放一次视频,相应的视频播放数就会自增1。代码如下所示

long incrVideoCounter(long id) {
key = "video:playCount:" + id;
return redis.incr(key);
}
  • 开发提示:实际上一个真实的计数系统要考虑的问题会很多:防作弊、按照不同维度计数,数据持久化到底层数据源等

③共享Session

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

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

④限速器

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

  • 此功能可以使用Redis来实现,下面的伪代码给出了基本实现思路:

phoneNum = "138xxxxxxxx";key = "shortMsg:limit:" + phoneNum;//SET key value EX 60 NXisExists = redis.set(key,1,"EX 60","NX");if(isExists != null || redis.incr(key) <=5){// 通过}else{// 限速}
  • 应用场景2:防止用户的账号遭到暴力破解,如果同个账号连续好几次输入错误的密码,则限制账号的登录,只 能等 30 分钟后再次登录,比如设置 3 次

    • 1)SET max:execute:times 3

    • 2)密码出错时 DECR max:execute:times

    • 3)当 max:execute:times 的值小于 0 时则禁止登录,并可以设置 SETEX login:error:darren 1800 "Incorrect password",然后使用 TTL login:error:darren 1800 检测对应剩余的时间

  • 应用场景3:例如一些网站为了防止网页内容被网络爬虫疯狂抓取,限制一个IP地址在固定的时间段内能够访问的页面数量.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444480.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode252. 会议室

给定一个会议时间安排的数组&#xff0c;每个会议时间都会包括开始和结束的时间 [[s1,e1],[s2,e2],...] (si < ei)&#xff0c;请你判断一个人是否能够参加这里面的全部会议。 示例 1: 输入: [[0,30],[5,10],[15,20]] 输出: false 示例 2: 输入: [[7,10],[2,4]] 输出: tr…

(十八)深入浅出TCPIP之epoll的一些思考

Epoll基本介绍在linux的网络编程中&#xff0c;很长的时间都在使用select来做事件触发。在linux新的内核中&#xff0c;有了一种替换它的机制&#xff0c;就是epoll。相比于 select&#xff0c;epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select…

leetcode292. Nim 游戏

你和你的朋友&#xff0c;两个人一起玩 Nim 游戏&#xff1a;桌子上有一堆石头&#xff0c;每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。 你们是聪明人&#xff0c;每一步都是最优解。 编写一个函数&#xff0c;来判断你是否可以在给定石头…

C++:16---强制类型转换和类型转换

旧式的强制类型转换 在早期C/C++中,显式地进行强制类型的转换有以下两种形式:type (expr) ; //函数形式的强制类型转换(type) expr; //C语言风格的强制类型转换比如: char c = 12; int b = (int)c; float f = float(b); C++的新式强制类型转换…

Nginx不停机优雅升级

最近线上运行的游戏越来越多,云服务商也给我推送提示系统升级,漏洞补丁升级,也有nginx更新的。 有一些比较关键性的系统补丁需要立即更新处理,有一些可以换一换不用升级,但此nginx升级的需求比较迫切,但更新可能需要重启nginx。 这将会影响到我们这样的一个登录业务逻辑…

leetcode186. 翻转字符串里的单词 II

给定一个字符串&#xff0c;逐个翻转字符串中的每个单词。 示例&#xff1a; 输入: ["t","h","e"," ","s","k","y"," ","i","s"," ","b","l…

Nginx大规模并发原理

Nginx在主流硬件上的并发数为十万,网络处理方面的领先地位,归功于突破性的事件驱动架构。 Nginx在每颗内核上创建一个工作进程,有效利用硬件资源。 在单个工作进程中交替处理多个连接,应对突如其来的网络流量。 Nginx资源管理 Nginx使用状态机管理流量。 非阻塞事件…

使用 CXF 做 webservice 简单例子

转&#xff1a;http://www.cnblogs.com/frankliiu-java/articles/1641949.html Apache CXF 是一个开放源代码框架&#xff0c;提供了用于方便地构建和开发 Web 服务的可靠基础架构。它允许创建高性能和可扩展的服务&#xff0c;您可以将这样的服务部署在 Tomcat 和基于 Spring …

老司机整理对Nginx性能优化

Nginx性能优化应遵循一个原则:一次只调整一项,调整不理想,将修改还原。 Linux参数 Nginx很多功能直接使用操作系统实现,操作系统决定nginx上限。 现代linux内核(2.6+)涵盖了大多应用场景,查看linux内核日志,找出参数过低的提示消息,根据建议调整。 连接队列 若传入…

leetcode189. 旋转数组

给定一个数组&#xff0c;将数组中的元素向右移动 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: [1,2,3,4,5,6,7] 和 k 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋转 1 步: [7,1,2,3,4,5,6] 向右旋转 2 步: [6,7,1,2,3,4,5] 向右旋转 3 步: [5,6,7,1,2,3,4] 示例 2: 输…

Nginx 配置UDP负载均衡

Nginx 1.9.13开始支持UDP负载匀衡&#xff0c;现代应用通常使用多种协议&#xff0c;很多核心Internet协议都早于HTTP&#xff0c;支持UDP势在必行。 UDP常用于非事务性的轻量级协议&#xff0c;如&#xff1a;DNS、syslog、RADIUS。 这些协议对可靠性没有严格要求&#xff0…

leetcode191. 位1的个数

编写一个函数&#xff0c;输入是一个无符号整数&#xff0c;返回其二进制表达式中数字位数为 ‘1’ 的个数&#xff08;也被称为汉明重量&#xff09;。 示例 1&#xff1a; 输入&#xff1a;00000000000000000000000000001011 输出&#xff1a;3 解释&#xff1a;输入的二进制…

Nginx location执行顺序和匹配规则

nginx location执行顺序和匹配原则根据location的特点分为普通和正则两种,执行顺序和匹配规则的差异也在于此。 执行顺序 nginx会优先执行普通location,不管普通location是否匹配,都会再次转向执行正则location,一旦第一个正则location被满足,则停止向后执行。 匹配原则…

Nginx 配置TCP负载均衡

Nginx从1.9.0版本开始,新增加了一个stream模块,用来实现四层协议的转发、代理或者负载均衡等鉴于Nginx在负载均衡和web service上的成功,和Nginx良好的框架,stream模块前景一片光明。 Nginx的stream模块默认不会自带安装,需要编译安装的时候手动添加上这个模块,不过我的系…

leetcode162. 寻找峰值 变种二分见过吗

峰值元素是指其值大于左右相邻值的元素。 给定一个输入数组 nums&#xff0c;其中 nums[i] ≠ nums[i1]&#xff0c;找到峰值元素并返回其索引。 数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回任何一个峰值所在位置即可。 你可以假设 nums[-1] nums[n] -…

(十九)TCPIP面试宝典-进入大厂必备总结(上)

TCP 作为传输层的协议,是一个IT工程师素养的体现,也是面试中经常被问到的知识点。在此,我将 TCP 核心的一些问题梳理了一下,希望能帮到各位。 实际上这篇文章相当于是复习之前的网络基础部分。只不过这篇文章的提问方式更灵活,也是让读者们懂得变通,更熟悉TCP。 TCP 和 U…

leetcode348. 判定井字棋胜负 好麻烦的代码

请在 n n 的棋盘上&#xff0c;实现一个判定井字棋&#xff08;Tic-Tac-Toe&#xff09;胜负的神器&#xff0c;判断每一次玩家落子后&#xff0c;是否有胜出的玩家。 在这个井字棋游戏中&#xff0c;会有 2 名玩家&#xff0c;他们将轮流在棋盘上放置自己的棋子。 在实现这…

C++:17---sizeof运算符

功能:以字节位单位,返回一个表达式或一个数据类型所占的字节数返回值类型:是size_t类型sizeof有无括号:sizeof不加括号,后面不可以直接跟数据类型sizeof加括号,后面既可以跟表达式也可以跟数据类型注意事项对引用类型执行sizeof运算得到被引用对象所占空间的大小对指针执…

leetcode345. 反转字符串中的元音字母

编写一个函数&#xff0c;以字符串作为输入&#xff0c;反转该字符串中的元音字母。 示例 1: 输入: "hello" 输出: "holle" 示例 2: 输入: "leetcode" 输出: "leotcede" 说明: 元音字母不包含字母"y"。 思路&#xff1a…

Redis:10---List对象

一、列表对象概述列表类型是用来存储多个有序的字符串&#xff0c;一个列表最多可以存储多个元素。列表是一种比较灵活的数据结构&#xff0c;它可以充当栈和队列的角色&#xff0c;在实际开发上有很多应用场景特点&#xff1a;一个列表可以存储多个字符串&#xff0c;相同元素…