【Redis的那些事 · 上篇】Redis的介绍、五种数据结构演示和分布式锁

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis,全称是Remote Dictionary Service,翻译过来就是,远程字典服务。redis属于nosql非关系型数据库。Nosql常见的数据关系,基本上是以key-value键值对形式存在的。Key-value: 就像翻阅中文字典或者单词字典,通过指定的需要查询的字或者单词(key),可以查找到字典里面对应的详细内容和介绍(value)


Redis是什么


Redis,全称是Remote Dictionary Service,翻译过来就是,远程字典服务。


redis属于nosql非关系型数据库。Nosql常见的数据关系,基本上是以key-value键值对形式存在的。


Key-value: 就像翻阅中文字典或者单词字典,通过指定的需要查询的字或者单词(key),可以查找到字典里面对应的详细内容和介绍(value)

 

Redis的一些特点:支持数据持久化、支持多种数据结构、支持数据备份、原子性操作等。

原子性:操作不能被中途打断。

 

Redis的由来


Redis的作者:意大利人 —— Salvatore Sanfilippo,现在至少四十几岁了,还在写代码。


Redis灵感来源:Alessia Merz,意大利一个舞者女郎。Merz在意大利有愚蠢的含义(俚语)。于是,Redis的默认服务端口号6379的来源灵感,来自于Mers这个词,详情可看九宫格输入法:

 

1995789-20211218005247427-682349481.jpg

 

Redis的安装


Mac系统:brew install redis

Linux系列系统:apt-get install redis  或 yum install redis 或apt-get install redis-server 或 yum install redis-server

1995789-20211218005310375-770244659.png

 

Windows系统:下载地址:https://github.com/tporadowski/redis/releases

1995789-20211218005325703-150507364.png

 

Redis启动方式


Mac/Linux: 启动服务端redis-server  启动客户端:redis-cli  

如果需要后台启动,需要修改 redis.conf  文件,设置daemonize 为 yes


然后使用 redis-server /xxx/redis.conf 指定配置文件进行启动。xxx是指定的路径。

 

以下下载的姿势可能不对,版本有点低,所以后面暂且用windows环境下的进行测试。

 1995789-20211218005357690-1981601855.png


Windows启动方式:双击redis-server.exe文件即可运行

1995789-20211218005409783-326035689.png

 

可以点击cli.exe文件,启动客户端。

输入ping,返回pong,代表服务是通的。

通过使用:set key value

可以用来设置一个键值对。

通过:get key

可以获取到key对应的value值。

1995789-20211218005425122-1947042439.png


通过命令创建redis密码: config set requirepass 密码


1995789-20211218005437258-420151160.png

 

通过使用 命令:auth 密码

进行redis权限验证。

使用:keys * 可以显示所有当前存在的key

 1995789-20211218005448004-1537050876.png

 

使用命令: select index

可以选择指定的Redis的Index(数据库)。Redis默认有最多16个数据库(或者叫Index),默认从0开始。例如上面设置的默认是0库,选择1库进行查询,就会没有东西。

1995789-20211218005457339-1363108647.png


Redis的数据结构


Redis的数据结构,体现在key-value的value上。Key默认都是字符串,value的基本数据结构包括字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(zset)

 

字符串数据结构


字符串在redis里面是可变的。用一个图来简单说明一下。

 1995789-20211218005608126-1107806929.png

 

字符串存储规则:Redis存储字符串期间,额外的空间分配规则是,当数据小于1MB的时候,每次扩容的空间是成倍增长的。大于1MB的时候,每次扩容的空间是1MB。


上面这段话如果不太理解,可以看Redis源码,源码内容如下。

1995789-20211218005639251-928036817.png

 

并且String单个数据最大的长度为 2^32-1=512M

关于字符串的其他操作:

使用命令: exists key

可以查看是否存在该key;

使用命令:del key

可以直接删除指定的key以及对应的value。


1995789-20211218005656201-1383149815.png


如果已有key,使用:set key xxx

会直接把key原有的值设置为xxx


1995789-20211218005708058-26928406.png

 

使用命令: expire key second

可以给指定的key设置过期时间。例如我设置了10s过期,十秒以后,就会被自动销毁了。


1995789-20211218005720037-1275507812.png

 

使用命令: setex  key  second  value

可以设置key-value键值对,并且可以同时设置过期时间的秒数。


1995789-20211218005729383-249262016.png

 

 

使用命令: ttl key

可以查看指定的key的剩余的过期时间。

1995789-20211218005738760-223155868.png

 

对于数值型的字符串,可以使用命令:incr key 和 decr key 进行自增1和自减1

使用命令:incrby key number 和 decrby key number 进行自增或自减指定的数值。

 1995789-20211218005749052-1985447738.png

 

可以通过批量设置命令:mset key value key value……

进行批量设置。

通过:mget key key key……

进行批量读取。不过mget批量读取的结果集是个列表(因为带有序号)

 1995789-20211218005801397-1701714475.png

 

列表数据结构


Redis的列表,最大可以存储40亿+个元素(2^32-1)。


列表的插入速度很快,时间复杂度是O,但是当数据量特别庞大的时候,使用索引进行查询操作会变得很慢,因为通过索引定位查询的时间复杂度为O(n)。


设置列表的key和value命令:lpush key value value value ……

可以设置一个key,带有多个元素的列表。l:left,代表的是左边,相当于每个元素是从左边被写入的(倒序插入)。

使用命令: lpop  key


可以取出最左边的元素的值,同时会把该值舍弃掉。

 1995789-20211218005816310-333017116.png


rpush是依次从右边插入(正序插入),rpop是取出最右边的元素的值,然后舍弃掉。r: right,代表右边

1995789-20211218005827331-182186118.png

 

可以使用命令:linsert key before|after 指定的value 要插入的value

进行插入元素。before 会把要插入的元素插入到指定的value的前面;after会把要插入的元素插入到指定的value的后面。

1995789-20211218005839733-40979910.png


通过使用命令:lset key index 新的value

可以把列表指定的索引对应的值给替换掉。

 1995789-20211218005852856-697614680.png

 

可以通过命令:lindex key index

获取指定的索引的值,并且不会被舍弃。操作索引期间,需要注意时间复杂度,元素多的情况下慎用。

1995789-20211218005905992-1494046518.png

 

可以使用命令:lrange key 起始索引 结束索引

获取在索引区间的所有元素。元素包含起始索引和结束索引的值。

1995789-20211218005917184-1752189717.png

 

列表还可以用来当作消息队列使用,因为列表存取的一些方式,可以用来先进先出、先进后出等堆栈操作,先进先出与消息队列机制雷同。

 

哈希数据结构


哈希数据结构,可以当作是字典(key-value)里面嵌套了个字典(value数据类型又是一个 key-value的结构)。类似Json,或者类似俄罗斯套娃,例如:

person:{

“Name”:”wesky”,

 “age”:18

}

 

使用命令: hset  key field value

可以设置哈希数据结构的key,以及一个属性和属性对应的值。

使用命令:hget key field

可以获取指定哈希数据的key对应的属性的值。

使用命令:hmset key field value field value ……

可以批量设置哈希数据指定key的多个属性和值。

使用命令:hmget key field1 field2 ……

可以批量获取指定的key下指定的多个属性的值。

使用命令:hgetall key

可以获取指定的哈希数据的key下的所有属性和值的列表。如下图所示。


1995789-20211218010002875-353290825.png


使用命令:hkeys key

可以获取哈希数据指定key的所有属性名称的列表;

使用命令:hvals key

可以获取哈希数据指定key的所有属性的值的列表;

使用命令: hlen key

可以获取到哈希数据里面指定key的属性个数。


1995789-20211218010014597-2020955091.png

 

集合数据结构


集合结构也可以看成是一个没有属性值的哈希数据结构,并且属性不能重复且无序的。

类似于:

Person{

“name”,

“age”

}

 

使用命令: sadd key field1 field2……

可以设置集合的key和元素集。由于集合是不可重复的,所以重复新增的元素会被自动剔除。

1995789-20211218010032346-1649280973.png


使用命令:smembers key

可以返回指定集合的所有元素;

使用命令:scard key

可以查询集合元素的个数;

使用命令:srandmember key (number:可选)

可以随机返回指定集合的一个或多个元素。不指定个数,即返回一个。

1995789-20211218010045576-512060601.png

 

集合数据,可以进行一些集合运算操作。

命令:sdiff  key1  key2

可以比较集合key1和集合key2的差集,差集结果为写在前面的集合元素减去后面集合的元素;

命令:sinter key1 key2

可以获取到集合key1和集合key2的交集。


1995789-20211218010100557-754194944.png

 

命令:sunion key1 key2

可以获取集合key1和集合key2的并集。

1995789-20211218010113028-1333356982.png

 

有序集合


有序集合比较常见的一个场景,是用来做排行榜。

命令:zadd  key  score1(分数,用于排行的值)  member1(集合的元素)  score2(分数,用于排行的值)  member2(集合的元素) ……

可以用来新增有序集合。其中,分数代表权重,值越低,排越前。

命令:zrange key 起始索引 结束索引

可以查询指定集合索引区间的所有元素的属性。

命令: zincrby key 增加权重值 menber

可以对有序集合指定的元素进行增加权重(对分数进行增加指定的值)

1995789-20211218010148040-1789854114.png

 

命令:zcard  key

可以获取有序集合的个数;

命令: zcount  key  最小分数  最大分数

可以获取到有序集合在指定的分数区间的所有元素;

命令:zcount key member

可以获取有序集合里面指定的元素当前的分数;

命令:zrange key  起始索引 结束索引 withscores

可以获取到有序索引里面指定的索引区间内所有的元素以及元素对应的分数。

 

1995789-20211218010205326-1178161752.png

 

备注:以上五种数据结构,都属于容器型,它们的特点是,当没有元素的时候,会被自动释放掉。

 

 

Redis分布式锁


Redis的操作是原子性的,如果存在多客户端同时操作的情况下,会发生一些干扰问题。原子性指的是,redis在进行读写期间是不会被打断的,会一直进行到底。下面用一个图片进行说明。

1995789-20211218010226690-1721183493.png

 

如上图所示,A和B同时都要操作Redis数据库里面的Key1。假设此刻Key1存储的是银行的存款,然后在A的地方消费掉了,此刻A触发了扣减余额的操作。这个时候,修改redis的值是通过先读取值出来到内存里面,然后进行扣减的;读取出来的时候,还没扣减完成,这个时候B(比如说是信用卡自动还款扣钱)也要扣减Key1的余额,也要进行先读取出来,然后才进行扣减。由于Redis是原子性操作,所以A的步骤不会被打断,B也不会被打断。这个时候,A扣减完成了,例如原本余额是100元,扣减了10元,A更改完毕以后,值变成了90元。此刻,B也要扣减,例如扣减20元,但是读取的是A改完之前的值,所以改完以后是80元。以上就产生了冲突,于是就有了Redis的分布式锁用来避免这个问题。

 

 

 

通过命令: set  key  value  ex  second  nx

可以设置一个锁,key代表锁的名称,value是值;second是锁的超时时间。

如下图所示,我开了两个客户端,并且标注了我的操作顺序号。


1995789-20211218010404910-1386975311.png

 

锁如果没有过期或删除,其他客户端创建锁会失败;但是其他客户端也可以删除锁,所以具有一定风险。建议可以对锁设置不同客户端所需要的不同的值用来区分。然后把需要操作的地方,放到锁里面操作,来避免产生的同时操作产生的问题。

例如伪代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

If(exists(lock))

{

 

  returnfalse// 存在锁,修改失败

 

}

 

Else<br>{

 

  Set locktrueex 5 nx;

 

  Set key1 100;

 

  del lock;

 

  Return true// 修改成功

 

}


今天暂且写到这儿了,后续还有redis的位图、布隆过滤器、限流、线程模型、通讯协议、订阅模式、管道、内存回收、源码解读等等内容,敬请期待~~

 

今天2021-12-18刚好也是自己生日(农历11月15),祝自己生日快乐。同时也祝大家学习愉快~~

 

欢迎各位大佬留下宝贵意见,欢迎点赞、推荐、或者留言~~ 感谢观看!


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
7天前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
40 16
|
18天前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
23天前
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
54 8
|
22天前
|
存储 NoSQL Java
介绍下Redis 的基础数据结构
本文介绍了Redis的基础数据结构,包括动态字符串(SDS)、链表和字典。SDS是Redis自实现的动态字符串,避免了C语言字符串的不足;链表实现了双向链表,提供了高效的操作;字典则类似于Java的HashMap,采用数组加链表的方式存储数据,并支持渐进式rehash,确保高并发下的性能。
介绍下Redis 的基础数据结构
|
18天前
|
存储 NoSQL 关系型数据库
Redis的ZSet底层数据结构,ZSet类型全面解析
Redis的ZSet底层数据结构,ZSet类型全面解析;应用场景、底层结构、常用命令;压缩列表ZipList、跳表SkipList;B+树与跳表对比,MySQL为什么使用B+树;ZSet为什么用跳表,而不是B+树、红黑树、二叉树
|
18天前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
存储 NoSQL 算法
「Redis」数据结构与对象
Redis数据结构与对象介绍
|
NoSQL 算法 Java
Redis进阶 - 数据结构:对象机制详解,一文深入底层分析
我们在前文已经阐述了Redis 5种基础数据类型详解,分别是字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(zset),以及5.0版本中Redis Stream结构详解;那么这些基础类型的底层是如何实现的呢?Redis的每种对象其实都由对象结构(redisObject) 与 对应编码的数据结构组合而成, 本文主要介绍对象结构(redisObject) 部分。
Redis进阶 - 数据结构:对象机制详解,一文深入底层分析