Redis(一)--概念和基础

主要内容

在这里插入图片描述

引入

Web1.0的时代,数据访问量有限,使用高性能的单点服务器可以解决大部分的问题。
在这里插入图片描述
随着Web2.0的到来,用户访问量大幅度提升,同时产生了大量的用户数据,加上后来的智能移动设备的普及,所有的互联网平台都面临了巨大的性能挑战。
在这里插入图片描述

解决CPU及内存压力

在这里插入图片描述

解决IO压力

在这里插入图片描述

NoSQL数据库

概述

非关系型的数据库,NoSQL不依赖业务逻辑方式存储,而以简单的key-value模式存储,大大增加了数据库的扩展能力。

特点

  • 不遵循SQL标准
  • 不支持ACID
  • 远超于SQL的性能

适用场景

  • 对数据的高并发的读写
  • 海量数据的读写
  • 对数据的高扩展性

例子

Memcache

  • 很早出现的NoSQL数据库
  • 数据都在内存中,一般不持久化
  • 支持简单的key-value模式,支持类型单一
  • 一般作为缓存数据库辅助持久化的数据库

Redis

  • 几乎覆盖了Memcached的绝大部分功能
  • 数据都在内存中,支持持久化,主要用作备份恢复
  • 除了支持简单的key-value模式,还支持多种数据结构的存储,比如:list、set、hash、zset等。
  • 一般作为缓存数据库辅助持久化的数据库

MongoDB

  • 高性能、开源、模式自由的文档型数据库
  • 数据都在内存中,如果内存不足,把不常用的数据保存到硬盘中
  • 虽然是key-value模式,但是对value提供了丰富的查询能力
  • 支持二进制数据以及大型对象
  • 可以根据数据的特点替代RDBMS,成为独立的数据库,或者配合RDBMS,存储特定的数据。

Redis概述

Redis是一种支持key-value等多种数据结构的存储系统。可用于缓存、事件发布或订阅、高速队列等场景。支持网络,提供字符串、哈希、列表、队列、集合结构直接存取,基于内存,可持久化。

什么是Redis

Redis是一款内存高速缓存数据库,全称为Remote Dicomtionary Server(远程数据服务),使用C编写,是一个键值存储系统,支持丰富的数据类型,如:string、list、set、zset、hash

特点

  • 读写性能优异

  • 数据类型丰富

  • 原子性
    Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

  • 丰富的特性
    Redis支持publish、subscribe、通知、key过期等特性。

  • 持久化
    Redis支持RDB、AOF等持久化方式

  • 发布订阅

  • 分布式
    Redis cluster

使用场景

热点数据缓存

缓存是Redis最常见的应用场景,主要是因为Redis读写性能优异,逐渐取代memcached,成为首选服务端缓存的组件,而且Redis内部是支持事务的,在使用的时候能有效的保证数据的一致性。
作为缓存使用时,一般有两种方式保存数据:

  • 读取前,先去读Redis,如果没有数据,读取数据库,将数据拉入Redis。
  • 插入数据时,同时写入Redis。

方案一:实施起来简单,但是有两个需要注意的地方:

  • 避免缓存击穿。(数据库没有需要命中的数据,导致Redis一直没有数据,而一直命中数据库????)
  • 数据的实时性相对会差一点

方案二:数据实时性强,但是开发时不便于统一处理。
方案一适用于对数据实时性要求不是特别高的场景,方案二适用于字典表、数据量不大的存储系统。

限时业务的运用

redis可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。

计数器相关问题

redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。

分布式锁

主要利用redis的setnx命令进行,该命令就是如果不存在则成功设置缓存同时返回1,否则返回0。因为我们的服务器是集群的,定时任务可能在两台机器上都会运行,所以在定时任务中首先通过setnx设置一个lock,如果成功设置则执行,如果没有成功设置,则表明该定时任务已执行。分布式锁主要用在秒杀系统中。

延时操作

举例:在订单生产后我们占用了库存,10分钟后去检验用户是否真正购买,如果没有购买将该单据设为无效,同时还原库存。由于redis自2.8.0之后版本提供Keyspace Notification功能,允许客户订阅Pub/Sub频道,以便以某种方式接收影响resdis数据集的事件。所以我们对于上面的需求就可以直接用下面的解决方案:我们在订单生产时,设置一个key,同时设置10分钟后过期,我们在后台实现一个监听器,监听key的实效,监听到key实效时将后续逻辑加上。
当然我们也可以利用rabbitmq、activemq消息中间件的延迟队列服务实现该需求。

排行榜的相关问题

关系型数据库在排行榜方面查询速度普遍较慢,所以可以借助redis的SortedSet进行热点数据的排序。
比如点赞排行榜,用SortedSet进行实现,然后以用户的openid作为上面的username,以用户的点赞数作为上面的score,然后针对每个用户做一个hash,通过zrangebyscore就可以按照点赞数获取排行榜,然后再根据username获取用户的hash信息。

点赞、好友等相互关系的存储

redis利用集合的一些命令,比如求交集、并集、差集等。在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。

简单队列

由于redis有list push和list pop这样的命令,所以能够很方便的执行队列操作。

Redis技术

Redis是单线程+多路复用技术
多路复用是指用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select或poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程中执行,也可以启动线程执行(比如使用线程池)。

常用的五大数据类型

对redis来说,所有的key都是字符串,我们在谈数据结构的时候,讨论的都是存储值的数据类型,主要包括五种,主要是String、List、Set、Zset、Hash。
在这里插入图片描述

String字符串

String是中最基本的类型,一个key对应一个value,String类型是二进制安全的,意味着Redis的String可以包含任何数据,比如:jpg图片或者序列化的对象。

实战场景:

  1. 缓存:经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。
  2. 计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。
  3. session:常见方案spring session+redis实现session共享。

原子性:所谓的原子操作是指不会被线程调度机制打断的操作。这种操作一旦开始,就一直运行到结束,中间不会有任何context switch(切换到另一个线程)。

  • 在单线程中,能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间。
  • 在多线程中,不能被其他进程(线程)打断的操作叫原子操作。

Redis单命令的原子性主要得益于Redis的单线程。
String的数据结构为简单动态字符串(SDS),是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。
在这里插入图片描述
如图所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串的长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M.

List列表

单键多值,Redis中的List就是一个链表,链表上的每个节点都包含一个字符串。

使用List结构,可以轻松的实现最新消息排队功能。List的另一个应用就是消息队列,可以利用List的PHSH操作,将任务存放在List中,然后工作线程再用POP操作将任务取出进行执行。

Redis列表是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部或者尾部。
底层实现是一个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
在这里插入图片描述
List的数据结构为快速链表quickList
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,即压缩列表。他将所有的元素紧挨着一起存储,分配的是一块连续的内存。
当数据量较多的时候才会变成quickList,因为普通的链表需要的附加指针空间太大,会比较浪费空间。
Redis将链表和ziplist结合起来组成了quickList,也就是将多个ziplist使用双向指针串起来使用,这样既能满足了快速的插入删除性能,又不会出现太大的空间冗余。

Set集合

Redis的Set是String类型的无序集合,集合成员是唯一的,不能出现重复的数据。并且set提供了判断某个成员是否在一个set集合内的重要接口,这个是list所不能提供的。

实战场景:

  1. 标签(tag):给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。
  2. 点赞,或点踩,收藏等:可以放大set中实现。

Redis的Set底层其实是一个value为null的hash表,所以添加、删除、查找的复杂度都是O(1)。
Set数据结构是dict字典,字典是用哈希表实现的。内部也使用hash结构,所有的value都指向同一个内部值。

Hash散列

键值对集合,是一个String类型的field(字段)和value(值)的映射表,hash特别适合用于存储对象。主要结构为:
在这里插入图片描述

通过key(用户ID)+field(属性标签)就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。

实战场景:
缓存:能直观的维护缓存信息,如用户信息,视频信息等,相比String节省空间。

Hash类型对应的数据结构是两种:ziplist(压缩列表)、hashtable(哈希表)。当fileld-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

Zset(sorted set)有序集合

与普通的set非常相似,也是String类型元素的集合,是一个没有重复元素的字符串集合。不同之处是有序集合的每个元素都关联了一个double类型的评分(score),这个评分被用来按照从最低分到最高分的方式排序集合内的成员。集合的成员是唯一的,但是评分可以是重复的

实战场景:
排行榜:经典使用场景。

zset底层使用了两个数据结构:
(1)hash:hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
(2)跳跃表:跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

跳跃表

有序集合比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便于元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。
在这里插入图片描述

三种特殊类型详解

HyperLogLogs(基数统计)

能够解决的问题:
可以非常省内存的去统计各种计数,比如注册IP数、每日访问IP数、页面实时UV、在线用户数、共同好友数等。

Bitmap(位存储)

都是操作二进制位来进行记录,只有0和1两个状态。
能够解决的问题:
比如:统计用户信息,活跃&不活跃;登录&未登录;打卡&未打卡;两个状态的,都可以使用Bitmap

geospatial(地理位置)

可以推算地理位置信息:两地之间的距离,方圆几里的人。底层的实现原理实际上就是Zset,可以通过Zset命令来操作geo。

  • geoadd:添加地理位置
  • geopos:获取指定成员的经度和纬度
  • geodist:获取当前定位,一定是一个坐标值,如果不存在,返回空。
  • georadius:获取所有附近的人的地址,定位,通过半径来查询。
  • georadiusbymember:显示与指定成员一定半径范围内的其他成员。
  • geohash:返回11个字符的hash字符串,将二维的经纬度转换为一维的字符串,如果两个字符串越接近,则距离越近。
    感谢并参考
    https://pdai.tech/md/db/nosql-redis/db-redis-data-type-special.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值