【精通Redis】Redis入门介绍

news2024/12/24 8:37:45

引言

本文作为笔者研究学习Redis的开篇之作,主要是对redis做一个简单系统的介绍,日常开发中都只是集成使用其缓存的功能,没有更深入的学习了解它的特性。笔者作为一个有五年Java开发经验的程序员,把大量时间都花在了编码上,各种框架组件的集成使用上,没有花时间去研究这些设计精妙的组件,从原理上理解吃透。说来惭愧,这也是自己还没有迈向架构那一步的主要原因。

Redis相信从事开发工作的朋友没有没听说过的,是一个非常强大的内存数据库,性能非常强劲,支持的数据类型也很丰富,有着很广泛的使用场景,学习掌握它的关键技术,了解它的设计思想对我们开发会有很大的帮助。废话不多说了,直接进入主题。

一、Redis的来历

先来一张"Redis之父"的照片压压惊,保佑我学习顺利。

"Redis之父"本名为 Salvatore Sanfilippo,网名Antirez,一位来自意大利西西里岛(Sicily)的70后程序员。这让我想起了年少时看过的一部启蒙电影《西西里的美丽传说》,我看了很多遍(懂得都懂)。

在这里插入图片描述

Redis是怎么诞生的

Redis诞生于2009年3月,据"Redis之父"自己的描述,他当时是遇到了这样一个需求场景:多个网站会通过一个小型的JavaScript追踪器(tracker)不断的向他的服务器发送页面访问记录,他的服务器需要为每个网站保存一定数量的最新页面访问记录,并通过网页把这些记录实时地展示给用户观看。

最大负载达到每秒几千条页面记录的情况下,常规的关系数据库都无法在一个受限的小虚拟机上处理如此大的负载。Salvatore Sanfilippo决定开发一个内存数据库,使用列表作为基本数据类型,并且能够对列表两端执行常数时间复杂度的弹出(pop)和推入(push),这个初始版本帮助他解决了问题。后来他又用C语言重写了最初的内存数据库原型,加上了基于子进程实现的持久化特性,Redis诞生了。

Redis始于实用主义——它是一个程序员因为找不到合适的工具来解决手头上的问题而发明的。说到这一点笔者感概良多,很多伟大的软件系统都是这么诞生的,不过在国内很难有环境支持国内程序员去创新。一个程序员的一生能有一个这么世界级的作品留下,可以说是无上的荣耀,我等只能膜拜大佬。

程序员想要提升到更高层次必须意识到的一个方面,不要过多花时间关注在编码上,而应该是花时间在思考需求和问题、找到好的设计这些事情上

Redis默认端口为什么是6379

这个端口号不是随便取得,是由手机键盘字母"MERZ"的位置决定的,如下图所示
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/bcc29a783dc4487f881be08
“MERZ"这个在"Redis之父"的朋友圈的意思是"愚蠢”,据说是意大利广告女明星"Alessia Merz"在电视节目上说了一堆愚蠢的话让人熟知,Redis之父使用6379作为默认端口估计也有点嘲讽的意思吧。

二、Redis数据库介绍

笔者在windows环境安装了redis,这个请读者朋友们自行网上搜索安装,比较简单,这里不再叙述。使用navicat工具连接redis数据库:
在这里插入图片描述
可以看到redis默认有16个数据库,索引范围从0-15,这个是可以修改的,windows下安装的redis,在配置文件redis.windows.conf文件中修改,其他系统如linux系统,可能在redis.linux.conf中或者redis.conf等类似的配置文件中修改。

默认情况下,使用的是索引为0数据库
在这里插入图片描述

修改成其他数值的数据库后,重启redis即可。

三、Redis基本数据结构

String

Redis 的 String 类型虽然是以“字符串”命名,但实际上它可以存储任意的二进制数据,而不仅仅是文本字符串。这意味着你可以在 Redis 的 String 键中存储任何形式的字节序列,包括文本、图片、音频文件、视频文件、序列化的对象等,只要总的大小不超过单个键值对的最大限制(目前 Redis 支持的最大值大小为 512 MB,但在某些版本中这个限制可能会更高,例如 1GB)。

String类型是Redis中最简单数据结构,常用来缓存用户信息。Redis中所有的数据结构都以唯一的key字符串作为名称,然后通过唯一的key获取对应的value数据。

不同类型数据结构的差异主要在于value结构不一样

redis提供了很多命令来操作字符串,这里只简单介绍三个最常用的:

命令行为
GET获取存储在给定键中的值
SET设置存储在给定键中的值
DEL删除存储在给定键中的值(这个命令可以用于所有数据类型)

设置一个简单的键值对,key为hello,value为word

set hello word

查询key为hello的value值

get hello

删除键为key的

del hello

可以使用redis客户端工具,执行试下,语句结尾注意不要加分号";",不然会作为value的一部分,保存到redis中。

List

Redis的列表相当于java中的LinkedList,注意是链表而不是数组,而且是双向链表。双向链表这种数据结构插入和删除速度很快,时间复杂度为O(1)。

Redis的列表常用来做异步队列使用。把需要延后处理的任务结构体序列化为字符串,塞入Redis的列表,另一个线程从这个列表中轮询数据进行处理。

下面是关于List列表的常见命令:

命令行为
RPUSH将给定值推入列表右端
LRANGE获取列表在给定范围上的所有值
LINDEX获取列表在给定位置上的单个元素
LPOP从列表的左端弹出一个值,并返回被弹出的值

以下操作命令,读者朋友可以自行试下:

rpush list-key item 从左边推入元素item1

rpush list-key item2 从左边推入元素item2

rpush list-key item3 从左边推入元素item3

LRANGE list-key 0 -1  查询所有元素,起始位置为0,结束位置索引为-1,可以取出列表包含的所有元素

lindex list-key 2 查询索引位置2的元素

lpop list-key  从左边弹出元素,并返回弹出的元素

关于List列表,再深入底层一点,我们会发现它不是一个简单的LinkedList,而是一个称之为"快速链表"(quicklist)的结构。

拓展

Quicklist这种数据结构是由ziplist(压缩列表)和双向链表两种结构组合而成。

从大的范围看快速列表本质还是一个双向链表,只是每个节点又是另外一种数据结构ziplist

ziplist不是单一的元素,它的内部是几个在物理内存上连续的,紧挨在一起的元素。即ziplist这种数据结构占有一块连续的内存区域,里面的元素紧挨在一起存储。你可以理解ziplist类似数组,但和数组有一定的区别。

在这里插入图片描述

上面的图很直观的展示了普通双向链表和quicklist快速列表之间的区别。

quicklist节省了内存空间,因为它不像普通链表那样需要维护大量指针,多个ziplist之间使用双向链表方式串起来,又保证了快速插入删除的性能,是一中折中的数据结构。

Hash

Redis中的Hash类型相当于java中的HashMap,它是一个无序字典,内部存储了很多的键值对。散列存储的值既可以是字符产(注意这里不仅仅指人类可读的字符产,还包括各种二进制字符串,实际可以存储各种数据类型),也可以是数值。

下面是一些常用的散列命令:

命令行为
HSET在散列中关联起给定的键值对
HGET获取指定散列键的值
HGETALL获取散列包含的所有键值对
HDEL如果给定键存在于散列里面,那么移除这个键

以下命令语句,感兴趣的可以自己尝试下:

hset hash-key sub-key1 value1  添加键值对到散列 hash-key, 返回一个值1,表示给定的键不存在于散列中

hset hash-key sub-key2 value2  添加键值对到散列 hash-key, 返回一个值1,表示给定的键不存在于散列中

hset hash-key sub-key1 value1  添加键值对到散列 hash-key, 返回一个值0,表示给定的键已存在于散列中

hgetall hash-key 获取散列hash-key的所有键值对信息

hdel hash-key sub-key1  从散列 hash-key 中删除键为sub-key1的值

Set

Redis中的Set集合类型相当于java里面的HashSet,它内部的键值对是无序的、唯一的

说到这里解释下HashSet和HashMap,方便理解Redis中的Set集合:
HashSet 在概念上是一个集合,它用于存储不重复的元素。从用户的角度来看,HashSet 只涉及元素(或者说值),并没有显式的键的概念。但是,从实现的角度讲,HashSet 是通过 HashMap 来实现的,也就是说,HashSet 的底层实际上是一个 HashMap
在 HashSet 的实现中,元素本身充当了 HashMap 的键,而值则是一个静态的私有对象 PRESENT。这个对象在 HashSet 类中定义,是一个 Object 类型的私有静态实例。这意味着在 HashSet 中的每个元素都会在 HashMap 中有一个相应的条目,其中键是集合中的元素,值是同一个 PRESENT 对象。
这样做的原因是 HashMap 要求键是唯一的,而 HashSet 需要保证元素的唯一性。通过将元素作为键,HashSet 可以利用 HashMap 的哈希表结构来高效地存储和检索元素,同时自动处理元素的去重问题。

下面是一些常用的操作集合Set的命令:

命令行为
SADD将给定元素添加到集合
SMEMBERS返回集合包含的所有元素
SISMEMBERS检查给定元素是否存在于集合中
SREM如果给定的元素存在于集合中,那么移除这个元素

同样的,以下是一些测试命令:

sadd set-key item  添加元素item到集合set-key中,返回1,表示成功添加

sadd set-key item2 添加元素item2到集合set-key中,返回1,表示成功添加

sadd set-key item3 添加元素item3到集合set-key中,返回1,表示成功添加

sadd set-key item  添加元素item到集合set-key中,返回0,表示元素已存在

smembers set-key 获取集合set-key的所有元素

sismember set-key item4 检查集合set-key是否存在元素item4,返回0表示不存在

sismember set-key item 检查集合set-key是否存在元素item,返回1表示存在

srem set-key item2 从集合set-key中移除元素item2,返回1表示移除一个元素

srem set-key item2 再次从集合set-key中移除元素item2,返回0表示没有移除到元素

smembers set-key 获取集合set-key的所有元素

ZSet

ZSet有序集合算是Redis中最有特色的数据结构,类似于java中SortedSet和HashMap的结合体,一方面它是一个Set保证内部value的唯一性,另一方面它可以给每一个value赋予一个score,代表这个value的排序权重

一个使用场景是:zset可以用来存储粉丝列表,value值是用户的id,score是关注时间,可以对粉丝列表按照关注时间来排序。

另一个使用场景是:zset可以用来存储学生成绩,value值是学生的id,score是学生成绩,对成绩按照分数排名可以得到学生的名次。

ZSet内部的排序功能是通过"跳跃列表"来实现的。skiplist跳跃列表是一种高阶数据结构,较为复杂。

下面的是一个有序链表,首尾的节点分别为头节点和尾节点
在这里插入图片描述

在这样一个链表中,如果我们要查找某个数据,那么需要从头开始逐个进行比较,直到找到包含数据的那个节点,或者找到第一个比给定数据大的节点为止(没找到)。也就是说,时间复杂度为O(n)。同样,当我们要插入新数据的时候,也要经历同样的查找过程,从而确定插入位置。

假如我们每相邻两个节点增加一个指针,让指针指向下下个节点,如下图:

在这里插入图片描述
这样所有新增加的指针连成了一个新的链表,但它包含的节点个数只有原来的一半(上图中是7, 19, 26)。现在当我们想查找数据的时候,可以先沿着这个新链表进行查找。当碰到比待查数据大的节点时,再回到原来的链表中进行查找。比如,我们想查找23,查找的路径是沿着下图中标红的指针所指向的方向进行的:

在这里插入图片描述

  • 23首先和7比较,再和19比较,比它们都大,继续向后比较。

  • 但23和26比较的时候,比26要小,因此回到下面的链表(原链表),与22比较。

  • 23比22要大,沿下面的指针继续向后和26比较。23比26小,说明待查数据23在原链表中不存在,而且它的插入位置应该在22和26之间。

在这个查找过程中,由于新增加的指针,我们不再需要与链表中每个节点逐个进行比较了。需要比较的节点数大概只有原来的一半。

利用同样的方式,我们可以在上层新产生的链表基础上,继续为每相邻的两个节点增加一个指针,从而产生第三层链表。如下图:

在这里插入图片描述
在这个新的三层链表结构上,如果我们还是查找23,那么沿着最上层链表首先要比较的是19,发现23比19大,接下来我们就知道只需要到19的后面去继续查找,从而一下子跳过了19前面的所有节点。可以想象,当链表足够长的时候,这种多层链表的查找方式能让我们跳过很多下层节点,大大加快查找的速度,类似于二分查找。

上面的方式确实大大加快了查找速度,但是缺点也很明显,新插入一个节点之后,就会打乱上下相邻两层链表上节点个数严格的2:1的对应关系。如果要维持这种对应关系,就必须把新插入的节点后面的所有节点(也包括新插入的节点)重新进行调整,这会让时间复杂度重新蜕化成O(n)。删除数据也有同样的问题。

skiplist为了避免这一问题,它不要求上下相邻两层链表之间的节点个数有严格的对应关系,而是为每个节点随机出一个层数(level)。比如,一个节点随机出的层数是3,那么就把它链入到第1层到第3层这三层链表中。为了表达清楚,下图展示了如何通过一步步的插入操作从而形成一个skiplist的过程:

在这里插入图片描述
从上面skiplist的创建和插入过程可以看出,每一个节点的层数(level)是随机出来的,而且新插入一个节点不会影响其它节点的层数。因此,插入操作只需要修改插入节点前后的指针,而不需要对很多节点都进行调整。这就降低了插入操作的复杂度。实际上,这是skiplist的一个很重要的特性,这让它在插入性能上明显优于平衡树的方案。

刚刚创建的这个skiplist总共包含4层链表,现在假设我们在它里面依然查找23,下图给出了查找路径:

在这里插入图片描述
以上就是跳表的原理解释,需要详细理解的请自行搜索相关资料。

有序集合的常用命令如下:

命令行为
ZAAD将一个带有给定分值的成员添加到有序集合中
ZRANGE根据元素在有序排列中所处的位置,从有序集合中获取多个元素
ZRANGEBYSCORE获取有序集合在给定分值范围内的所有元素
ZREM如果给定成员存在于有序集合,那么移除这个元素
zadd zset-key 728 member1  向有序集 合zset-key 添加新元素member1,分值为728,返回1 ,添加成功

zadd zset-key 982 member0  向有序集 合zset-key 添加新元素member0,分值为982,返回1 ,添加成功

zadd zset-key 982 member0  向有序集 合zset-key 添加新元素member0,分值为982,返回0,添加失败

zrange zset-key 0 -1 withscores  获取有序集合所有元素,并按照分值大小排序

zrangebyscore zset-key  0 800 withscores  获取0-800分值的所有元素

四、总结

通用规则

五个常用的Redis数据结构前面已经介绍完毕,其中list、hash、set、zset这四种数据结构都是容器型数据结构,它们共享下面两条规则:

  1. create if not exists:如果容器不存在,那就创建一个,然后进行操作。比如hset刚开始没有集合的,Redis会自动创建,然后往其中添加元素。
  2. drop if no elements:如果容器中的元素没有了,那么立即删除容器,释放内存。

过期时间
Redis中的所有数据结构都可以设置过期时间,时间到了Redis会自动删除相应对象。注意的是过期是以对象为单位,比如一个hash结构的过期是整个hash对象的过期,不是其中的某个子key过期。

对于字符串若已经设置了过期时间,调用set方法修改它,它的过期时间会消失。

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

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

相关文章

从零入手人工智能(6)—— 聚类

1.小故事 有一家零售连锁店,他们以其精准的市场定位和个性化的顾客服务而闻名,随着市场竞争的加剧和顾客需求的多样化,他们的管理层开始意识到,只有更加深入地了解他们的顾客群体,以便更好地满足他们的需求。 他们定…

渗透测试——利用公网反弹shell到本地的两种方式,vmware虚拟机与主机的端口转发,本地ssh无法上线的问题解决

解决问题: 因长期使用本地模拟靶场,实战护网时并非模拟靶场,shell反弹需要利用公网测试。解决目标站无法反弹到本地的情况。解决本地是windows,虚拟机是kail、linux,无法相互转换流量的情况。 环境搭建 靶机 centOS7 …

HarmonyOS(45) 控件拖动或者拖拽PanGesture

PanGesture实现控件拖动的效果,通过拖动的坐标位置调用position或者translate方法来更新UI的位置。效果见下图: 具体代码如下: // xxx.ets Entry Component struct PanGestureExample {State offsetX: number 0State offsetY: number 0pos…

做视频混剪都是去哪里找高清素材的?分享10个高清视频素材库

提升视频混剪质感的10个高清素材库推荐 在这个视觉体验至上的时代,视频的视觉质量对吸引观众至关重要。如果你正在寻找高清素材以提升视频混剪作品的层次,那么你来对地方了。今天,我将为你揭秘10个视频混剪达人常用的高清素材库,…

html+css+js前端作业 王者荣耀官网5个页面带js

htmlcssjs前端作业 王者荣耀官网5个页面带js 下载地址 https://download.csdn.net/download/qq_42431718/89574989 目录1 目录2 目录3 项目视频 王者荣耀5个页面(带js) 页面1 页面2 页面3 页面4 页面5

大数据-46 Redis 持久化 RDB AOF 配置参数 混合模式 具体原理 触发方式 优点与缺点

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…

前端文件下载word乱码问题

记录一次word下载乱码问题: 用的请求是axios库,然后用Blob去接收二进制文件 思路:现在的解决办法有以下几种,看看是对应哪种,可以尝试解决 1.将响应类型设为blob,这也是最重要的,如果没有解决…

LeetCode 2766题: 重新放置石块(原创)

【题目描述】 给你一个下标从 0 开始的整数数组 nums ,表示一些石块的初始位置。再给你两个长度 相等 下标从 0 开始的整数数组 moveFrom 和 moveTo 。 在 moveFrom.length 次操作内,你可以改变石块的位置。在第 i 次操作中,你将位置在 moveF…

C++STL详解(一)——String接口详解(上)!!!

目录 一.string类介绍 二.string类的构造赋值 2.1string类的拷贝和构造函数 2.2深拷贝 三.string类的插入 3.1push_back 3.2append 3.3操作符 3.4insert 四.string的删除 4.1pop_back 4.2erase 五.string的查找 5.1find 5.2rfind 六.string的比较 6.1compare函…

LeetCode 热题 HOT 100 (011/100)【宇宙最简单版】

【图论】No. 0200 岛屿数量 【中等】👉力扣对应题目指路 希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【力扣详解】谢谢你的支持&#xf…

使用AOP优化Spring Boot Controller参数:自动填充常用字段的技巧

欢迎来到我的博客,代码的世界里,每一行都是一个故事 🎏:你只管努力,剩下的交给时间 🏠 :小破站 使用AOP优化Spring Boot Controller参数:自动填充常用字段的技巧 前言为什么使用AOP为…

web网站组成

web网站由四部分组成:浏览器 前端服务器 后端服务器 数据库服务器 流程: 1.浏览器输入网站后,向前端服务器发送请求,前端服务器响应,静态的数据给浏览器。 2.前端代码中script中有url,这个是向后台发送请求的网…

项目标红,识别不了maven项目,解决办法

首先,检查 preferences 其次,检查IDEA 的 jdk。File-》Project Structure 最后: 1. 2. mvn clean install -Dmaven.test.skiptrue 跳过单元测试 maven跳过单元测试-maven.test.skip和skipTests的区别-CSDN博客

vue3+g2plot实现词云图

词云图 效果预览: 核心代码: import {WordCloud } from @antv/g2plot;fetch(https://gw.alipayobjects.com/os/antfincdn/jPKbal7r9r/mock.json).then((res) => res.json()).then((data) => {const wordCloud = new WordCloud(container, {data,wordField: x,weigh…

细说MCU用DMA实现DAC输出的方法

目录 一、建立新工程 1.项目依赖的硬件 2.配置DAC 3.配置DMA 4.配置TIM3 5.选择时钟源和Debug 6.配置系统时钟 二、代码修改 1. 启动定时器和DMA 2.定义输出波形数据 3.通过MATLAB产生这个波形数据的方法 三、查看结果 用DMA的方式将位于存储器(数组)中的数据传递…

centos中zabbix安装、卸载及遇到的问题

目录 Zabbix简介Zabbix5.0和Zabbix7.0的区别监控能力方面模板和 API 方面性能、速度方面 centos7安装Zabbix(5.0)安装zabbix遇到的问题卸载Zabbix Zabbix简介 Zabbix 是一个基于 WEB 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix 能监视各种网络参…

三分钟带你了解Python文件操作与IO流

在探索编程世界的奇幻旅程中,文件操作和IO(输入/输出)流是每一个探险者必须掌握的基础技能。在Python的世界中,这些技能尤为关键,它们像是巫师手中的魔杖,能让我们与文件进行深度的交流。本文将带你快速了解…

springboo 整合 redis

springBoot 整合 redis starter启动依赖。—包含自动装配类—完成相应的装配功能。 引入依赖 <!--引入了redis整合springboot 的依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis&…

泵浦光与斯托克斯光相遇耦合效应的matlab模拟与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1拉曼散射基础 4.2非线性耦合方程 5.完整程序 1.程序功能描述 泵浦光与斯托克斯光相遇耦合效应的matlab模拟与仿真. 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 &#xff0…

面试场景题系列--(2)短 URL 生成器设计:百亿短 URL 怎样做到无冲突?--xunznux

文章目录 面试场景题&#xff1a;短 URL 生成器设计&#xff1a;百亿短 URL 怎样做到无冲突&#xff1f;1. 需求分析2. 短链接生成算法2.1 自增法2.2 散列函数法2.3 预生成法 3. 部署模型3.1 其他部署方案 4. 设计4.1 重定向响应码4.2 短 URL 预生成文件及预加载4.3 用户自定义…