Redis学习笔记

Redis官网:https://www.redis.net.cn/tutorial/3505.html

Nosql概述

为什么要用Nosql:

我们现在处于大数据时代,大数据一般的数据库无法进行分析处理。
关系型数据库:表,列,行。
NoSQL= not only sql
泛指非关系型数据库。随着web2.0互联网诞生,传统的关系型数据库很难对付web2.0时代,尤其是超大规模的高并发的社区。NoSQL在当今大数据环境下发展的十分迅速,Redis是发展最快的,而且是当下必须掌握的一个技术。
很多数据类型用户的个人信息,社交网络,地理位置,这些数据类型的存储不需要一个固定的格式,不需要多余的操作就可以横向扩展的。
NoSQL特点:
1、方便扩展(数据之间没有关系,很好扩展)
2、大数据量高性能(Redis一秒可以写八万次,可以读取十一万次。Nosql的缓存记录级,是一种细粒度的缓存,性能比较高)
3、数据类型是多样型的。(不需要事先设计数据库,随取随用,如果是数据量十分大的表,很多人就无法设计了)
4、传统的RDBMS和Nosql:
传统的RDBMS:

  • 结构化组织
  • SQL
  • 数据和关系都存在单独的表中
  • 操作数据定义语言
  • 严格的一致性
  • 基础的事务操作
    NoSQL:
  • 不仅仅是数据
  • 没有固定的查询语言
  • 键值对存储,列存储,文档存储,图形数据库(社交关系)
  • 最终一致性。
  • CAP定理,BASE理论(异地多活)
  • 高性能,高可用,高可扩
    大数据时代的3V:海量、多样、实时
    大数据时代的3高:高并发,高可拓,高性能
    在公司中的事件是NoSQL+关系型数据库,一起使用才是最强的。
NoSQL的四大分类:

1、KY键值对

  • 新浪:Redis
  • 美团:Redis+Tair
  • 阿里:Redis+memecache
    2、文档型数据库
  • MongoDB(基于分布式文件存储的数据库,是介于关系型数据库和非关系型数据库中中间产品,非关系型数据库中功能最丰富,最像关系型数据库的)
  • ConthDB
    3、列存储数据库
  • HBase
  • 分布式文件系统
    4、图关系数据库
    (不是存图形,是存关系,比如:社交网络)
  • Neo4j
Redis概述:

Redis:即远程字典服务,是一共开源的使用ANSI C语言编写,可基于内存亦可持久化的日志型,KV数据库,并提供多种语言的API。
是当下最热门的NoSQL技术之一,也被人们称为结构化数据库。
Redis能干嘛?

  • 内存存储,持久化。
  • 效率高,可以用于高速缓存
  • 发布订阅系统
  • 地图信息分析
  • 计时器、计数器
    特点:
  • 多种的数据类型
  • 持久化
  • 集群
  • 事务
基础知识:

redis默认有16个数据库。默认使用的是第0个,可以使用select进行切换数据库。

127.0.0.1:6379>  select 3 #切换数据库
OK
127.0.0.1:6379[3]> dbsize#查看数据库大小
(integer) 0
127.0.0.1:6379[3]> set name shuanggem
OK
127.0.0.1:6379[3]> dbsize
(integer) 1
127.0.0.1:6379[3]> get name
"shuanggem"
127.0.0.1:6379[3]> flushdb #清除当前数据库
OK

Redis是单线程的,Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能的瓶颈。Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了。
Redis为什么单线程还能这么快?

  • 误区一:高性能的服务器一定是多线程的。
  • 误区二:多线程一定比单线程效率高。
    核心:Redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的。
    对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写在一个CPU上,在内存情况下,就是效率最高的。

什么是Redis五大基本类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
String类型

127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1 #获取值
"v1"
127.0.0.1:6379> keys *  #查看值
1) "age"
2) "key1"
127.0.0.1:6379> move age  #删除值
(error) ERR wrong number of arguments for 'move' command
127.0.0.1:6379> move age 1
(integer) 1
127.0.0.1:6379> append key1 "hello"  #追加字符串,如果key1不存在,则新建
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> strlen key1 #获取字符串长度
(integer) 7
127.0.0.1:6379> append key1 "world"  #追加字符串
(integer) 12
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> decr views  #自减1
(integer) 0
127.0.0.1:6379> incrby views 10  #增10
(integer) 10
127.0.0.1:6379> get views
"10"
127.0.0.1:6379> decrby views 5  #减5
(integer) 5
127.0.0.1:6379> get views
"5"
127.0.0.1:6379> set key1 "hello,shuangge"
OK
127.0.0.1:6379> get key1
"hello,shuangge"
127.0.0.1:6379> getrange key1 0 3 #获取【0,3】范围的字符
"hell"
127.0.0.1:6379> getrange key1 0 -1  #获取全部字符串
"hello,shuangge"
127.0.0.1:6379> setrange key1 1 xx  #替换指定位置的字符串
(integer) 14
127.0.0.1:6379> get key1
"hxxlo,shuangge"

setex(设置过期事件)
setnx(不存在设置)在分布式锁中常使用

127.0.0.1:6379> setex key3 30 "hello" #设置key3值三十秒后过期
OK
127.0.0.1:6379> setnx mykey "redis"  #如果mykey不存在,创建mykey,如果存在,创建失败
(integer) 1
127.0.0.1:6379> ttl key3
(integer) 5
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey "mysql"
(integer) 0
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379>  mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #是个原子性操作,,要么一起成功,要么一起失败

set user:1{name:zhangsan,age:3} #设置一个user:1对象 值为json字符来保存一个对象。

127.0.0.1:6379>  mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"

List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
实例

127.0.0.1:6379> lpush  k1 redis
(integer) 1
127.0.0.1:6379> lpush k1 mongodb
(integer) 2
127.0.0.1:6379> lpush k1 rabitmq
(integer) 3
127.0.0.1:6379> lrange k1 0 10
1) "rabitmq"
2) "mongodb"
3) "redis"

list实际上是一个链表。

Set(集合)
Redis的Set是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

sadd 命令
添加一个string元素到,key对应的set集合中,成功返回1,如果元素以及在集合中返回0,key对应的set不存在返回错误。

sadd key member
实例

127.0.0.1:6379> sadd redis.net.cn redis
(integer) 1
127.0.0.1:6379> sadd redis.net.cn mongodb
(integer) 1
 127.0.0.1:6379> sadd redis.net.cn rabitmq
(integer) 1
127.0.0.1:6379> sadd redis.net.cn rabitmq
(integer) 0
127.0.0.1:6379> smembers redis.net.cn
1) "rabitmq"
2) "mongodb"
3) "redis"

注意:以上实例中 rabitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。

Hash(哈希)
Redis hash 是一个键值对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

实例

127.0.0.1:6379> HMSET user:1 username redis.net.cn password redis.net.cn points 200
OK
 127.0.0.1:6379> HGETALL user:1
1) "username"
2) "redis.net.cn"
3) "password"
4) "redis.net.cn"
5) "points"
6) "200"
127.0.0.1:6379>

以上实例中 hash 数据类型存储了包含用户脚本信息的用户对象。 实例中我们使用了 Redis HMSET, HEGTALL 命令,user:1 为键值。

zset(sorted set:有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

zadd 命令
添加元素到集合,元素在集合中存在则更新对应score

zadd key score member
实例

redis 127.0.0.1:6379> zadd redis.net.cn 0 redis
(integer) 1
redis 127.0.0.1:6379> zadd redis.net.cn 0 mongodb
(integer) 1
redis 127.0.0.1:6379> zadd redis.net.cn 0 rabitmq
(integer) 1
redis 127.0.0.1:6379> zadd redis.net.cn 0 rabitmq
(integer) 0
redis 127.0.0.1:6379> ZRANGEBYSCORE redis.net.cn 0 1000
 
1) "redis"
2) "mongodb"
3) "rabitmq"

Hyperloglog
基数,不重复的元素。
Hyperloglog是用来做基数统计的算法。
优点:占用的内存是固定的。

127.0.0.1:6379> PFadd mykey a b c d e f g h i j
(integer) 1
127.0.0.1:6379> pfcount mykey
(integer) 10
127.0.0.1:6379> pfadd mykey2 i j z x  c v b n m
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 9
127.0.0.1:6379> pfmerge mykey3 mykey mykey2
OK
127.0.0.1:6379> pfcount mykey3
(integer) 15

Bitmaps
位存储
使用bitmap记录三天内打卡情况(模拟)

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0

事务

Redis事务没有原子性,没有隔离级别的概念。
Redis事务本质:一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程中,会按顺序执行。一次性、顺序性、排他性。
Redis事务:

  • 开启事务(multi)
  • 命令入队
  • 执行事务(exec)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379> discard #放弃事务

锁:Redis可以实现乐观锁
悲观锁:很悲观,什么时候都会出问题,无论做什么都会加锁
乐观锁:很乐观,认为什么时候都不会出问题,所以不会上锁。更新数据的时候去判断一下,在此期间是否有人修改过数据。

  • 获取version
  • 更新时比较version
    正常执行成功
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

Redis持久化

RDB:redis database
在指定的时间间隔内将内存中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存里。
rdb保存的文件是dump.rdb,都是在我们的配置文件中配置的。
触发机制:
1、save的规则满足的情况下,会自动触发。
2、执行flushall命令,也会触发。
3、推出redis也会产生rdb文件。
如何恢复rdb文件:
只需要将rdb文件放在redis启动目录就可以。redis启动时会自动检查dump.rdb恢复其中的数据。
优点:
1、适合大规模数据恢复
2、对数据完整性要求不高
缺点:
1、需要一定的时间间隔进行操作。
2、fork进程的时候,会占用一定的内存空间。
AOF:append only file

将我们所有命令都记录下来aof保存的是appendonly.aof文件。默认不开启,需要我们手动配置。
优点:
1、每一次修改都同步,文件的完整会更好。
2、每秒同步一次。
3、从不同步,效率是最高的。
缺点:
1、相对于数据文件来说,aof远远大于rdb,修复速度也慢。
2、aof运行效率也慢。所以我们redis默认的配置是rdb持久化。

Redis主从复制

主从复制,读写分离,架构中经常使用,一主二从。
默认情况下,每一台服务器都是一个主节点。
一般只需要配置从机即可。

哨兵模式

主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器。这就需要人工干预,更多时候,我们会优先考虑哨兵模式来解决这个问题。
哨兵模式是一种特殊的模式,哨兵是一个独立的进程,作为进程,它会独立运行,其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
这里的哨兵有两个作用:
1、通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
2、当哨兵检测到主服务器宕机,会自动将从服务器切换为主服务器,然后通过发布订阅模式通知其他服务器,修改配置文件,让他们切换主机。
优点:
1、哨兵集群,基于主从复制模式,所有的主从配置优点,它都有。
2、主从可以切换,故障可以转移,系统的可用性就会更好。
3、哨兵模式就是主从模式的升级,手动到自动,更加健壮。
缺点:
1、Redis不好在线扩容。
2、实现哨兵模式的配置其实很麻烦。

缓存穿透和雪崩

缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义。 缓存穿透问题可能会使后端存储负载加大,由于很多后端持久层不具备高并发性,甚至可能造成后端存储宕机。通常可以在程序中统计总调用数、缓存层命中数、如果同一个Key的缓存命中率很低,可能就是出现了缓存穿透问题。
造成缓存穿透的基本原因有两个。第一,自身业务代码或者数据出现问题(例如:set 和 get 的key不一致),第二,一些恶意攻击、爬虫等造成大量空命中(爬取线上商城商品数据,超大循环递增商品的ID)
解决方案:

  1. 缓存空对象
    缓存空对象:是指在持久层没有命中的情况下,对key进行set (key,null)

缓存空对象会有两个问题:第一,value为null 不代表不占用内存空间,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间,比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象

  1. 布隆过滤器拦截

在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截,当收到一个对key请求时先用布隆过滤器验证是key否存在,如果存在在进入缓存层、存储层。可以使用bitmap做布隆过滤器。这种方法适用于数据命中不高、数据相对固定、实时性低的应用场景,代码维护较为复杂,但是缓存空间占用少。

布隆过滤器实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

二、缓存雪崩
由于缓存层承载着大量请求,有效地保护了存储层,但是如果缓存层由于某些原因不可用(宕机)或者大量缓存由于超时时间相同在同一时间段失效(大批key失效/热点数据失效),大量请求直接到达存储层,存储层压力过大导致系统雪崩。

解决方案:
可以把缓存层设计成高可用的,即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务。利用sentinel或cluster实现。
采用多级缓存,本地进程作为一级缓存,redis作为二级缓存,不同级别的缓存设置的超时时间不同,即使某级缓存过期了,也有其他级别缓存兜底
缓存的过期时间用随机值,尽量让不同的key的过期时间不同(例如:定时任务新建大批量key,设置的过期时间相同)
三、缓存击穿
系统中存在以下两个问题时需要引起注意:

当前key是一个热点key(例如一个秒杀活动),并发量非常大。
重建缓存不能在短时间完成,可能是一个复杂计算,例如复杂的SQL、多次IO、多个依赖等。
在缓存失效的瞬间,有大量线程来重建缓存,造成后端负载加大,甚至可能会让应用崩溃。

解决方案:

  1. 分布式互斥锁 只允许一个线程重建缓存,其他线程等待重建缓存的线程执行完,重新从缓存获取数据即可。set(key,value,timeout)
  2. 永不过期
    从缓存层面来看,确实没有设置过期时间,所以不会出现热点key过期后产生的问题,也就是“物理”不过期。
    从功能层面来看,为每个value设置一个逻辑过期时间,当发现超过逻辑过期时间后,会使用单独的线程去更新缓
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mingshengda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值