Redis基础篇

目录

1. 启动redis

2. 背景信息

3. 五大基本数据类型+三大特殊类型 

3.1 String

3.2 List 列表

3.3 Set 集合

3.4 Hash 哈希

 3.5 Zset 有序集合

3.6 Geospatial 地理空间

3.7 Hyperloglog

3.8 BitMap 位存储

4. 基本事务

4.1 乐观锁

5. SpringBoot使用Redis

6. 持久化

7. 扩展

7.1 redis是单线程的,为什么还那么快?

7.2 缓存穿透,缓存击穿,缓存雪崩的区别


1. 启动redis

切换目录到redis目录下,在当前目录打开一个CMD窗口, 输入以下命令

# 启动redis
redis-server.exe redis.windows.conf

 切换目录到redis目录下,在当前目录再打开一个CMD窗口,输入以下命令

redis-cli.exe -h 127.0.0.1 -p 6379

# 检测连接
ping

2. 背景信息

1. redis一共16个数据库

2. 为什么选择6379这个端口号?

6379对应手机按键MERZ,是一个意大利舞女;REDIS作者早年看电视觉得MERZ在节目中的一些话可笑愚蠢。为REDIS选为一个数字作为默认端口号时,REDIS作者就拿MERZ对应手机按键的号码6379来当作这个端口号了。

3. Springboot2.XX后,原来使用的jedis被替换成了lettuce

        jedis: 采用的直连,多线程的话是不安全的,如果想要安全,需要使用jedis pool连接池。BIO模式

        lettuce:采用netty,实例可以在多个线程内共享,不存在线程不安全的情况。更像是NIO的模式。

3. 五大基本数据类型+三大特殊类型 

3.1 String

#清空数据库
FLUSHDB

#清空全部数据库内容
FLUSHALL

#增加1
INCR views

#减少1
DECR views

#增加10
INCRBY views 10
 
#减少10
DECRBY views 10

#截取key对应的value的 0-3位字符串
GETRANGE key 0 3

#截取key对应的value
GETRANGE key 0 -1

#替换key对应的value 第1位的字符串开始替换成nihao,比如“helloworld”变成“hnihaoorld”
SETRANGE key 1 nihao

#20秒后过期, set with expire
SETEX key 20

# 如果没有值,则插入, set if not exist
SETNEX

# 如果不存在,则返回nil,如果存在之
# 如果存在值 ,获取原来的值,并设置新的值
GETSET 

使用场景:

计数器,统计多单位的数量,粉丝数,对象缓存存储

3.2 List 列表

所有list命令都是以L开头的

#将一个值从列表的头部(左)边插入
LPUSH list one

#将一个值从列表的头部(左)边移除
LPOP

#将一个值从列表的尾部(右)边插入
RPUSH list one

#将一个值从列表的尾部(右)边移除
RPOP

# 获取list的下标为1的值
LINDEX list 1

# 获取list的长度
LLEN list

# 移除列表指定个数的value
# 移除列表里2个为“three”的值
LREM list 2 three

# 截取指定的长度
# [1,2,3,4] -> [2,3]
LTRIM list 1 2


# 移动值:list右边弹出一个值,左边插入newlist
# list: [1,2,3,4] -> list: [1,2,3]
# newlist: [] -> newlist: [4]
RPOPLPUSH list newlist

#在某个值前面插入
LINSERT list BEFORE"world" “hello”

#在某个值后面插入
LINSERT list AFTER"world" “~”

使用场景:消息排队,消息队列(LPUSH,RPOP), 栈(LPUSH,LPOP) 

3.3 Set 集合

# 将一个值从set中插入
SADD set "hello"

# 查看set中所有值
SMEMBERS set

# 查看set中某个值是否存在
SISMEMBERS set "hello"

# 查看set值的个数
SCARD set

# 将一个值从set中移除
SREM set "hello"

# 随机抽选出指定的值
SRANDMEMBER

# 随机删除set中一个元素
SPOP

#将指定的值,移动到另一个set
#将set中“nihao”这个值,移动到另一个set2
SMOVE set set2 "nihao"

#差集
SDIFF s1 s2

#交集
SINTER s1 s2

#并集
SUNION s1 s2

使用场景:微博B站,共同关注,共同爱好

差集交集并集

3.4 Hash 哈希

# 形式:key:[key:value]

# 给key为hash的值里插入[name:yangjiling]这个hashmap
HSET hash name yangjiling

# 查询key为hash值里的 hashmap 查询key为name的值
HGET hash name 

# 获取hash里的所有键值对
HGETALL hash

# 获取hash里的键值个数
HLEN hash

 3.5 Zset 有序集合

#给有序的set加1
ZADD set 1 one

# 从最小到最大排序
# ZRANGEBYSCORE key min max
ZRANGEBYSCORE salary -inf +inf

# 移除有序集合中的元素
ZREM salary xiaohong

# 获取有序集合中的个数
ZCARD salary

# 获取指定区间的成员数量
ZCOUNT salary 1 2

使用场景:

set排序,统计全班成绩,工资表排序,带权重进行判断,排行榜应用,top N测试

3.6 Geospatial 地理空间

# 添加地理位置
# 规则添加,两级无法添加,
GEOADD key longitude latitude member

# 两点间的距离
GEODIST key member1 member2 

使用场景:附近的人

3.7 Hyperloglog

hyperloglog是基数(不重复的元素个数)统计的算法,优点:占用的内存是固定的,2^64不同元素的基数,只需要废12k的内存!缺点:0.81%的错误率。

# 添加
PFADD key a b c d

# 查看key里当前的个数 
PFCOUNT key

# 将key1和key2合并为mergeKey
PFMERGE mergeKey key1 key2

使用场景:页面的UA,页面访问量,一个人放问页面多次,还是算作一个人

传统:set保存用户的id,set中元素的数量就是基数;缺点:如果id比较长,保存大量的id,会浪费内存,重点是计数,不是保存id

3.8 BitMap 位存储

使用场景:疫情感染人数,统计用户信息(统计活跃用户/非活跃用户| 登录/非登录用户),查看打卡天数(365天打卡),两种状态就可以使用位图,操作二进制进行操作。

365天=365bit,1字节=8bit, 大概365/8约等于46字节左右


# 打卡7天 SET key [代表周一-周天] [0:未打卡;1:打卡]
SETBIT sign 0 1
SETBIT sign 1 0
SETBIT sign 2 1
SETBIT sign 3 0
SETBIT sign 4 1
SETBIT sign 5 1
SETBIT sign 6 1

#查看某一天是否打卡: 查看周四是否打卡
GETBIT sign 3 

# 查看多少个1
# 统计一周打卡记录 
BITCOUNT sign

4. 基本事务

【不保证事物的原子性】redis单条命令是保证原子性的,事务是不保证原子性的。

【无事务隔离级别】没有事务隔离级别的概念

【一次性】如果把命令放在队列里执行,执行错误的就会被去除,继续下一个执行。

【顺序性】一个事务中的所有命令都会被序列化,会按照顺序执行。

【排他性】

MULTI # 多个命令放入队列
set key1 value1
set key2 value2
get key2
set key3 value3
EXEC # 执行
DISCARD # 放弃事务

# 监视
WATCH key
# 取消监视
UNWATCH key

编译型异常:(例如:执行一个redis不存在的命令)执行事务也是报错的,所有的命令都不会被执行

运行时异常:(例如:给一个不存在的值加1),虽然一条命令失败,其他的还是可以正常执行

4.1 乐观锁

乐观锁的执行:更新数据的时候判断一下,在此期间有没有人修改过这个数据。

        1. 获取version

        2. 更新的时候比较version, 如果和第一步的version不一样了,事务执行失败

多线程修改值后,redis的watch可以当作乐观锁的操作。

监视money, 正常执行结束

127.0.0.1:6379> SET money 100
OK
127.0.0.1:6379> get key *
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> get keys
(nil)
127.0.0.1:6379> keys
(error) ERR wrong number of arguments for 'keys' command
127.0.0.1:6379> keys *
1) "money"
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

监视money, 非正常执行结束返回(nil)

线程1,在线程2还没进行exec执行操作的时候,更改了money的值

127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 1000
OK

线程2,最后执行exec执行操作的时候,不会成功,只返回了(nil)

127.0.0.1:6379> watch money #监视线程
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
127.0.0.1:6379> exec #执行之前,另外一个线程修改了值,那么就会导致事务的失败
(nil)

如果事务执行失败,就解锁(unwatch),再获取最新的值再次进行监视(watch key),在最后exec的时候,监视值是否发生变化,没有变化就执行成功,如果没有变化就继续解锁,监视...

5. SpringBoot使用Redis

1. 导入依赖,在pom.xml的dependencies里导入

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

2.  配置文件,在application.properties下配置

spring.redis.host= 127.0.0.1
spring.redis.port= 6379

3. 序列化配置:

pojo都要序列化

中文的乱码:默认的序列化方式是JDK序列化 

6. Redis.confg文件

1. 单位,对大小写不敏感,可以配置多个配置文件

配置讲解

bind 127.0.0.1 #绑定的ip

protected-mode yes #保护是,默认开

port 6379 #端口号


#通用配置
daemonize yes #以守护线程的方式运行,默认,自己设置为yes

# 如果以后台方式运行,就需要指定一个pid(进程)文件
 pidfile /var/run/redis.pid


# 900秒内,如果至少有1个key修改过,就可以进行持久化操作
save 900 1
save 300 10
save 60 10000

# 持久化出错,是否继续工作
stop-writes-on-bgsave-error yes

# 是否压缩rdb文件,需要消耗性能
rdbcompression yes


# 保存rdb文件,进行错误的检查校验
rdbchecksum yes

# 是都需要密码
requirepass

maxclients 10000  #连接客户端的最大数量
maxmemory <bytes> #配置的最大容量
maxmemory-policy noeviction #内存达到上线的处理策略


# APPEND ONLY 模式 aof配置
appendonly no # 默认不开启aof模式的,默认是rdb方式持久化的,在大部分的情况下,rdb完全够用
appendfilename "appendonly.aof" # 持久化的文件的名字

# appendfsync everysec 每次修改都会sync,消耗性能
appendfsync everysec #每秒执行一次sync,可能会丢失这1s的数据
# appendfsync no 不执行sync,操作系统自己同步数据,速度最快

6. 持久化

  dump.rdb触发规则:

1. save规则满足的情况下,会自动触发规则

2. 执行flushall命令,也会触发rdb规则

3. 推出redis, 也会生成rdb文件

如何恢复rdb文件?

只需要将rdb文件放在redis启动目录即可,redis启动的时候会自动检查dump。rdb恢复其中的数据。

优点:

1. 适合大规模数据的回复,dump.rdb

2. 如果对数据的完整性不高

缺点:

1. 需要一定的个时间间隔进程操作,如果redis意外宕机了,最后一次修改数据就没有了

2. fork进程时,会占用一定的空间

AOF Append only file 将我们的所有命令都记录下来,history,恢复的时候一起恢复

默认是不开启的,需要手动开启,将appendonly 改成yes

如果aof配置文件错误,redis是启动不起来的,就需要使用redis-check-aof进行修复。

7. 扩展

7.1 redis是单线程的,为什么还那么快?

核心:redis的数据全部反正该内存中的,所以说单线程去操作效率就是最高的。多线程(CPU会上线文进行切换,耗时) ,对于内存系统用来说,如果没有上下文切换效率就是最高的。

redis是基于内存操作的,redis的瓶颈是根据机器的内存和网络带宽。

7.2 缓存穿透,缓存击穿,缓存雪崩的区别

缓存穿透:一直查询缓存redis里面没有的值,就只能去数据库mysql查询一个值。大量的请求,因为在缓存redis里查询不到,全部砸向数据库mysql,导致持久层的数据库很大的压力。解决方案:1. 布隆过滤器,2. 给缓存里查询不到的值->数据库查->数据库查询不到就在缓存里设置当前值为空值,这样下次在查询这个值的时候,缓存就会有对应的空值,不会再去数据库查询了。

缓存击穿:指的是一个key非常的热点,在不停的抗着大并发,并发集中对这一个点进行访问。解决方案:设置热点数据永不过其,加互斥锁(多个线程查询,只有一个线程能够获取到这个资源)。

缓存雪崩:指的是某一个时间段,缓存集中过期失效,redis宕机。全部的请求全部砸到数据库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值