热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis数据结构之string应用场景解析

本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。


英国弗兰明曾说过一句话:“不要等待运气降临,应该去努力掌握知识。”


1 前言


大家好,我是阿沐!对于redis大家是最熟悉不过了,作为缓存界的使用率一直遥遥领先。基本上整个互联网无论大小公司使用redis占绝大部分,那么很多人使用它,那就是只是使用它,对于它的使用场景并没有去理会太多(能用就行),这篇文章来讲讲redis的基础数据结构string。


Redis有五种基础数据结构如下: string(字符串)hash(哈希又叫字典)set(集合又可叫无序集合)zset(有序集合)list(列表) 。这五种数据结构涵盖了整个redis的知识点,它是redis最重要却也是最 基础的知识点 。当然,你也会在面试中经常遇到redis这些基础知识,三连问:它的使用场景?它的坑在哪里?如何解决?那么下面阿沐将会使用面试官与面试者的角色一一的进行问答讲解!


2 面试开场心里状态


面试官:一个带着眼镜的年轻面试官(26,27岁)缓慢从原来走过来,手里拿着我的简历,边走边看,然后时不时抬头望向我这边。


面试者:“哎呦,,,别再看我了,我就是一个一年经验的小菜鸟,看的我心发慌,腿直抖。他会问我啥呢,我该怎么流畅的回答呢?心里嘀嘀咕咕, 真的我还是只是一个孩子啊 ,面试官放过我吧,简单点来。”


面试官:“来到面试会议室坐在我对面”。简单的介绍下自己吧?


面试者:你好面试官,我叫阿沐,河南人,毕业于郑州大学。目前工作半年,上家公司是广州xxx公司,担任后端开发工程师,主要负责搜素,购物车,产品模块等。业余时间喜欢xxxx(省略200字)......


面试官:嗯呢,看了你的简历,那么我们简单聊聊redis,看你上面写的项目大部分都是跟redis相关连。就说一说redis的string类型的一些常用的基础指令吧!


3 面试开始直进主题了


这不是小菜一碟嘛,难不住我,easy:



  1. 相关描述:string是数据结构中比较简单的一种,通常是以key和value的形式存储,它内部存储是一个字符数组形式。Redis字符串的最大长度是512M,并且的存储是动态的(意味着可以随时修改它本身的值),每次分配内存时会高出实际字符串的length,这样采用 预分配冗余空间方式来减少内存的频繁分配


  2. 常使用命令:



set - 设置key的值;若key存在,覆盖旧值无视类型,成功返回OK(注意大写OK,很多框架封装返回的值改变了,不要被误导了)
get - 获取指key值;若key不存在,返回nil(不是null,不要搞错)
mset - 同set一致,批量设置键值对,减少网络开销
mget - 同get一致,批量获取键值对,减少网络开销
incr - key值+1,不存在则先set后incr,返回integer切记值必须能标识为数字
incrby - 同incr一致,多出一个指定数字增量值
decr - 同incr原理一致,操作方式变为了减法
decrby - 同incrby原理一致,操作方式变为了减法
strlen - 获取长度len,若不存在返回0,类型为integer
setnx - 设置key值,若key不存在,则返回1,否则返回0。(若场景需要设置过期时间,不推荐使用这个命令,网络波动情况下,有可能setnx成功,expire却失败了,不是原子操作)
setex - 设置key值及过期时间,若key已存在,则替换旧值覆盖。(若需要set值且需设置过期时间且要求较高必须要有过期时间,推荐使用这个命令,设置key值+过期时间是原子操作,要么成功要么失败)
append - 对key值进行末尾追加数据,返回值是字符串长度

面试官:微微点点头,心里说道:“哎呦,功课做得挺足的哦,对使用和注意点了解的这么清楚,来自面试官的肯定,加分”。


4 string的使用场景


面试者:就知道你会问我使用场景,还好我准备的比较充足,是时候表现真正的技术啦!面带表情开始一本经常的介绍到: 计数缓存基础数据限制请求次数分布式下共享session签到 等等,那么我按照这些场景介绍下用法。


4.1 缓存基础数据


例如缓存登录用户的基本的缓存数据(建议hash存储,这里只是举例),用户登录成功之后,可以将用户基础数据组装json字符串设置到缓存,用户请求查询缓存层来加速读写性能降低mysql查询的压力。若用户更新则对应的刷新同步缓存,如果用户表数据字段较多,可以分成冷热数据分别存储,降低key的大小,减少网络额外开销。


// 实例化redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
//echo "Server is running: " . $redis->ping();
$member_info = [
'member_id' => 1001,
'member_nickname' => '我是阿沐',
'member_email' => 'lw1772363381@163.com',
'member_phone' => '12345678998',
'member_qq' => '2511221051@qq.com',
'member_level' => 120,
];
$key = sprintf('member:info:id:%u', $member_info['member_id']);
$expire = 60;
// 设置缓存并且60s过期
$result = $redis->set($key, json_encode($member_info), $expire);
//$redis->set($key, json_encode($member_info), ['nx', 'ex' => 60]);
if (!$result) {
exit( "额,设置失败了");
}
echo "哇喔,设置成功了";
-- 终端 get
127.0.0.1:6379> get member:info:id:1001
"{\"member_id\":1001,\"member_nickname\":\"\\u6211\\u662f\\u963f\\u6c90\",\"member_email\":\"lw1772363381@163.com\",\"member_phone\":\"12345678998\",\"member_qq\":\"2511221051@qq.com\",\"member_level\":120}"
127.0.0.1:6379> get member:info:id:1001
(nil) -- 记住无数据返回nil

4.2 计数器


计数功能常用于统计某一个页面的访问数据量,例如:我之前是在电商公司工作,产品会经常让我们做活动 页面的浏览量 以及活动内的产品详情打开量,通过 pv数据分析 活动中哪些产品受众。当然也会统计产品详情页 视频的点击量 ,以及开放api的每天调用总次数等等场景。迅速在纸上手写代码:


// 实例化redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
//echo "Server is running: " . $redis->ping();
$key = sprintf('product:detail:pid:%u', 12345);
$result = $redis->incr($key);
// $result php中返回的是布尔类型 true or false
//redis终端
127.0.0.1:6379> incr product:detail:pid:12345
(integer) 2
127.0.0.1:6379> get product:detail:pid:12345
"2"

4.3 限制请求次数


限制访问次数,这个一般用来控制某一图谋不轨的人利用非正常手动 刷接口 或者 恶意破坏我们的系统服务 ,对于一些比较敏感,比较重要的接口做上限流措施。例如:网站使用手机号注册,一般公司短信发送是使用第三方,是要给钱的,心疼啊!点一次就是1毛钱。心在滴血。尽管客户端做了校验限制,但是避免不了抓包模拟请求,这个时候我们需求对这些用户或者IP地址进行限流请求,使用incr+expire结合处理。手撕伪代码如下:


// 实例化redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
//echo "Server is running: " . $redis->ping();
$key = sprintf('member:login:phone:count:%u', 12345678998);
$maxCount = 10;
// 获取当前key是否有生存时间 -2未设置key -1 key 存在未设置过期时间
$ttl = $redis->ttl($key);
if ($ttl > 0) {
$times = $redis->get($key);
if ($times >= $maxCount) return true;
$result = $redis->incr($key);
if ($result) return true;
} else {
$result = $redis->set($key, 1, 60);
if ($result) return true;
}
return false;

4.4 分布式共享session


面试者:“心里暗暗庆幸着,还好我在上家公司有实习了解过,不然真的要死翘翘了“。开始吹牛皮了:系统最开始时由于用户量小一般都是 单机器支撑 ,用户登录之后存储在 session (服务器文件存储)中,那么当随着我们的业务越来越大,用户量激增到上百万,这个时候我们有单机变成了集群,使用了 ngxin做负载均衡 ,将各个用户的请求都会被负载到各个服务器上,用来分摊机器压力,保证服务稳定。


这个时候会发现用户登录时请求随机到了某一台机器,这个时候生成了session文件,但是在用户访问其他页面又被随机到其他服务器这个时候拿不到session,就会被拦截用户登录请求,就导致用户可能要登录很多次。那这样肯定不行呀,非常不友好的用户体验会被的狗血淋头。


那么这个时候分布式缓存就可以解决这个问题啦。用Redis将用户的Session信息进行集中的管理,每次用户登录信息都从Redis中集中获取,这样完美的解决了这一问题。我们可以设置php.ini:


session.save_handler = redis -- 保存方式
session.save_path ="tcp://127.0.0.1:6379" -- 保存路径


面试官:”这家伙准备的这么充分,头头是道的,条理清晰。看来我得给他加点调料了,戳戳锐气“。面试官说道:请问负载均衡集群中的session解决方案除了使用redis管理session,还有哪些方案可以使用呢?


面试者:”心里暗香:吆喝,这是跟我杠上了,问的差不多不就行了,还非要深入去问;我这一年多经验的人,就对我这么狠,求求你饶过小弟吧!不过我初生不怕牛犊,我就是刚“。恩,既然您问到这一块了,那我也就对号入座了,说下我自己了解到的吧:


其实除了session使用redis存储这一方案,我们还可以考虑权衡一下方案:



  1. session会话保持- 意思是保证用户每次请求都在同一台机器上


  2. session会话复制- 意思是把每个应用服务器中的session信息复制同步到其它服务器节点



4.4-1 session会话保持


-1、一般使用nginx负载均衡中的upstream中的一种分配方式ip_hash或者url_hash(需要额外install) 原理就是:将用户的每一个请求ip地址hash结果集进行分配到固定一台服务器请求,这样就可以保证用户一直处于登录状态。例如下面配置:


upstream bakend { -- bakend是upstream的名称,也是proxy_pass反向代理的地址
ip_hash;
server 192.168.0.1:80;
server 192.168.0.2:80;
server 192.168.0.3:80;
}

2、使用haproxy做负载均衡的Session保持,有三种方式:



  • ① 类似nginx的ip_hash识别算法


  • ② COOKIE 识别,haproxy在用户第一次访问的后在浏览器插入一个COOKIE,用户下一次访问的时候浏览器就会带上这个COOKIE给Haproxy,进行识别分析


  • ③ haproxy将后端服务器产生的session和后端服务器标识存在haproxy中的一张表里,请求时先查询这张表进行识别(感兴趣的可以自行谷歌查阅haproxy)



会话保持的缺点:


1、负载均衡无用武之地:本身面对 大流量、高并发、我们使用nginx做负载均衡,降低服务压力 ;那么会话保持显然摒弃了这一点优势,每个用户规定请求某台机器,可能会出现多台机器资源空缺浪费,而部分机器压力负载过大,倾向于单机时代。


2、无法根据解决session问题:若某台服务器突然宕机或者超时链接不上,那么nginx的高可用则会踢出这台机器,请求会被重新分配到其他机器,导致用户要重新登录,这体验度简直不要不要的,差评。


4.4-1 session会话复制


会话复制是一种服务机制,用于复制存储在不同实例的会话中的数据。主要是指在集群环境下, 多台服务器之间同步session文件数据 ,保持所有机器上的session一致,对外透明。如果用户登录之后,请求被随机分配到任何一台机器都能通过session会话拿到登录信息,或者某台机器服务故障宕机, nginx负载均衡调度器会遍历可以使用的节点 ,分发其他机器请求。但是session已完成同步,不会影响用户再次登录。


不推荐使用原因:session的会话复制会带来额外的性能损失,一旦session中存在比较大的对象,会导致同步缓存,性能消耗上升。


最后总结


面试者:面试官你好,上面说的这些就是我在项目中经常使用的字符串类型,并且还有它的使用场景以及场景分析和出现的问题以及解决方案。


面试官:嗯嗯,可以看出来redis的基础知识还是很扎实的,常使用命令的一些分析的很好,也很仔细。看出来你在日常工作中善于积累," 来自面试官的一个肯定的眼神 "。那么我们来继续下一个问题(等待下一章节)...


从上面的面试情况来分析,基本上常使用的一些指令都涵盖到以及使用的场景介绍;并非一定是这样使用,只是我们在实际使用string类型指令要考量我们的场景,根据用户量或者其他方面来决定使用的类型,考量设置的数据量,太大影响性能消耗;那么我们下一章节继续。


宫崎骏曾说过一句话:“遇见的都是天意,拥有的都是幸运,不完美又何妨,万物皆有裂痕,那是光照进来的地方”;我们学习亦是如此,唯有面试官虐我千百遍,我才能待面试官如初恋;不完美才有提升的机会。


好了,我是阿沐,一个不想30岁就被淘汰的打工人 :fuelpump:️ :fuelpump:️ :fuelpump:️ 。




推荐阅读
  • LVS实现负载均衡的原理LVS负载均衡负载均衡集群是LoadBalance集群。是一种将网络上的访问流量分布于各个节点,以降低服务器压力,更好的向客户端 ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 本文主要复习了数据库的一些知识点,包括环境变量设置、表之间的引用关系等。同时介绍了一些常用的数据库命令及其使用方法,如创建数据库、查看已存在的数据库、切换数据库、创建表等操作。通过本文的学习,可以加深对数据库的理解和应用能力。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • PHP组合工具以及开发所需的工具
    本文介绍了PHP开发中常用的组合工具和开发所需的工具。对于数据分析软件,包括Excel、hihidata、SPSS、SAS、MARLAB、Eview以及各种BI与报表工具等。同时还介绍了PHP开发所需的PHP MySQL Apache集成环境,包括推荐的AppServ等版本。 ... [详细]
  • Redis的默认端口、数据库使用和多端口配置
    本文介绍了Redis的默认端口、数据库使用和多端口配置的方法。通过选择不同的数据库和使用flushdb命令可以实现对不同数据库的访问和清除数据。同时,本文还介绍了在同一台机器上启用多个Redis实例的方法,并讨论了配置认证密码的步骤和注意事项。 ... [详细]
author-avatar
落了个小妞农_602
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有