redis

redis

redis-benchmark是一个压力测试工具!官方自带的性能测试工具

redis-benchmark命令参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cARXNWPb-1632618216286)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210920151728679.png)]

测试:

#测试100个并发连接,100000请求
redis-benchmark -h localhost -p 6739 -c 100 -n 100000

redis 默认有16个数据库:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5w1rDMTG-1632618216289)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210920154420019.png)]

默认使用的是第0个

可以使用select进行切换

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> select 3    切换数据库
OK
127.0.0.1:6379[3]> dbsize    查看当前数据库大小
(integer) 0
127.0.0.1:6379[3]> 

查看当前数据库中所有的key

127.0.0.1:6379> keys *
1) "name"

flushdb   清空当前数据库
flushall  清空所有数据库

redis 是单线程的!!!

Redis是很快的,Redis是基于内存操作的,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和带宽,既然可以使用单线程来实现,就是用单线程。

Redis为什么单线程还这么快?

1.误区1;高性能的服务器一定是多线程的

2.误区2:多线程(CPU上下文会切换!)一定比单线程效率高

核心:

redis是将所有的数据全部放在内存中的,所以说使用单线程操作效率就是最高的,多线程(CPU上下文切换,非常耗时间)对于内存系统来说,如果没有上下文切换效率就是最高的!

五大基本数据类型:

Redis-key

exists  name   判断key是否存在
move name 1   移除key=name
expire  name    设置过期时间
ttl name    查看当前key的剩余时间
type name   查看当前key的类型
append name  向一个字符串后面添加一个字符串
strlen name 一个字符串的长度


incr  views     加1
incrby  views 10  加10
decr  views     减1
decrby views 10 减10


getrange key start end 截取字符串从start到end的子串
setrange key 开始 要替换的字符串 替换指定位置开始的字符串!
setex   set with expire   设置过期时间
setex key3 30 "hello"   设置key3的值为hello,30秒后过期
setnx   set if not exists  如果不存在就设置
mset   k1 v1 k2 v2 k3 v3   同时创建多个
mget k1 k2 k3 同时获取多个

msetex  同时设置多个值的过期时间
msetnx  同时设置如果某个值不存在的话,原子性操作,要么一起失败,要么一起成功

getset,  如果不存在则返回null返回0,如果存在则返回原来的值,设置新的值

set user:1{name:hanxing, age:1}=
mset user:1:name=hanxing user:1:age=1

List

所有的list操作前面都以l开头

lpush  list one  从列表的左边插入一个值
lrange list 0 -1  获取list中的值
rpush list righr  从列表的右边插入一个值
lpop list 从左边移除第一个值
Lindex list 1 取list中下标为1的值
Llen list   获取list的长度

lrem  list 1 one  移除list中为one的1个
ltrim  mylist  1 2 截取list中1到2

rpoppush   移动列表的最后一个元素将它放到新的列表中
lset
将列表中指定下标的值替换为另外一个值,更新操作

Linsert mylist before "world" "other"

小结:

实际上是一个链表,befor Node after, left, right都可以插入值

如果key不存在,创建新的链表

如果key存在,新增内容

如果移除所有值,空链表,也代表不存在

在两边插入或者改动值,效率最高,中间元素,相对来说效率会低一点!

消息排队,消息队列

set

sadd myset hello  set集合中添加值
sadd myset kuangshen
sadd myset loveyu

smemebers myset  查看指定set的所有制

sismember myset hello  查看指定set中是否存在hello
scard myset  查看集合中元素的个数
srem myset hello

srandmember myset 2   随机抽出集合中的指定个数的元素
spop myset         随机删除集合中的一个元素
sdiff set1 set2   求两个集合的差集
sinter set1 set2  求两个集合的交集
sunion set1 set2  求两个集合的并集

hash

Map集合,key-map,本质和String类型没有太大区别,还是一个简单的key-value!

127.0.0.1:6379> hset myhash field1 kuangshen  #set 一个具体的key-value
(integer) 1
127.0.0.1:6379> hget myhash field
(nil)
127.0.0.1:6379> hget myhash field1
"kuangshen"
127.0.0.1:6379> hmset myhash field1 hello field2 world  #同时设置多个key-value
OK
127.0.0.1:6379> hmget myhash field1 field2 #同时获取多个字段值
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash   #获取全部的数据
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> hdel myhash field1   #删除一个指定key-value
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
hlen    myhash   #求hash里面的key-value字段的个数
hkeys   myhash   #获取所有的字段名
hvalues  myhash  #获取所有的

hash变更的数据 user name age, 尤其是用户信息之类的,经常变动的信息!hash更适合对象的存储,String更加是个字符串存储!

Zset(有序集合)

在set基础上,增加了一个值,zset k1 score1 v1

zadd myset 1 one   # 添加一个值
 
zadd myset 2 two 3 three   #添加多个值
###############################################################
实现排序
127.0.0.1:6379> zrangebyscore salary -inf +inf  #从小到大排序
1) "kuangshen"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> zrevrange salary 0 -1     		#从大到小排序
1) "zhangsan"
2) "kuangshen"

127.0.0.1:6379> zrangebyscore salary -inf +inf withscores    #从小到大排序,并且附带成绩
1) "kuangshen"
2) "500"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"

zrem salary xiaohong   #移除一个元素
zcard salary       #获取集合中的个数
zcount salary     #获取指定区间的元素的数量


三种特殊数据类型

GEO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-14A1ydTW-1632618216291)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210921212129315.png)]

geoadd

#getadd   添加地理位置
#规则:  两级无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqin 114.05 22.52 shengzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2

geopos 一个地方的经纬度

127.0.0.1:6379> geopos china:city beijing

  1. “116.39999896287918091”
  2. “39.90000009167092543”

127.0.0.1:6379> geopos china:city beijing chongqin

  1. “116.39999896287918091”

  2. “39.90000009167092543”

    1.“106.49999767541885376”

    2.“29.52999957900659211”

GEODIST

两个人之间的距离:

单位:

​ m表示单位为米

​ km表示单位为千米

​ mi表示单位为英里

​ ft表示单位为英尺

27.0.0.1:6379> GEodist china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> GEodist china:city beijing shanghai km   #查看北京到上海的直线距离
"1067.3788" 
127.0.0.1:6379> GEodist china:city beijing chongqin km    #查看北京到重庆的直线距离
"1464.0708"

GEOradius 以给定经纬度为中心,找出某一半径内的元素

我附近的人(获得所有附近的人的地址,定位!),通过半径来查询!

127.0.0.1:6379> georadius china:city 110 30 500 km    # 以110 30 为中心,500km为半径查找
1) "chongqin"
2) "xian"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 3   # 以110 30 为中心,500km为半径查找3个用户
1) 1) "chongqin"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"

GEOHASH 将二维的经纬度转化为一维的字符串,如果两个字符串越接近,那么距离越近

27.0.0.1:6379> geohash china:city beijing chongqin
1) "wx4fbxxfke0"
2) "wm5xzrybty0"
geo的底层就是zset,所以可以使用zset的命令对geo进行操作
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqin"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city hangzhou
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqin"
2) "xian"
3) "shengzhen"
4) "shanghai"
5) "beijing"

Hyperloglog

什么是基数?

A{1,3,5,7,8,7}

B{1,3,5,7,8}

基数(不重复的元素) = 5,可以接受误差

不能重复

所以当做页面统计时(一个人访问一个网站多次,但是还是算作一个人),可以容错的情况下,可以使用Hyperloglog

127.0.0.1:6379> pfadd mykey a b c d e f g h i j   #创建第一组mykey
(integer) 1
127.0.0.1:6379> pfcount mykey   #统计mykey中元素的个数
(integer) 10
127.0.0.1:6379> pfadd i m k y b u g r s x
(integer) 1
127.0.0.1:6379> pfcount i
(integer) 9
127.0.0.1:6379> pfadd mykey2 i m k y b u g r s x
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 10
127.0.0.1:6379> pfmerge mykey mykey2  #合并两组
OK
127.0.0.1:6379> pfcount mykey
(integer) 17

Bitmaps

统计用户信息,活跃,不活跃,登录,未登录。。。。两个状态的都可以使用Bitmaps!

Bitmaps位图,数据结构!都是操作二进制为来进行记录,就只有0和1两种状态

127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> getbit sign 1
(integer) 0
127.0.0.1:6379> bitcount sign   #统计打卡的天数:
(integer) 2
127.0.0.1:6379> 

事务

Redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行,一次性、顺序型、排他性、执行一系列的命令

----------队列  set  set  set  set  执行-------

Redis事务没有隔离级别的概念

所有的命令在事务中,并没有直接执行,只有在发起执行命令的时候才会执行。

== Redis单条命令保存原子性的,但是事务不保证原子性要么同时成功,要么同时失败。==

Redis事务:

开启事务 (multi)
命令入队()

执行事务(exec)

正常执行事务

127.0.0.1:6379> multi   #开启事务
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED 
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec   #执行事务
1) OK
2) OK
3) "v1"

放弃事务

127.0.0.1:6379> multi   #开启事务
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> DISCARD  #放弃事务
OK
127.0.0.1:6379> get k4   #事务队列中的事务都不会被执行
(nil)

编译型异常(代码有问题!命令有错!)事务中所有的命令都不会被执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k3    #错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> exec   #执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4   #所有的命令都会被执行
(nil)

运行时异常,如果事务队列中存在语法性,那么执行命令的时候,其他命令可以正常执行,错误命令抛出异常

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 "v1"
QUEUED
127.0.0.1:6379(TX)> incr k1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range  #虽然第一条命令报错了,但是后面可以正常执行
3) OK
4) OK

乐观锁:

测试多线程,一个线程在另一个线程执行事务时修改值,结果该线程的事务执行失败,监视失败

127.0.0.1:6379> watch money   #使用watch可以当作redis的乐观锁
OK
127.0.0.1:6379> decrby money 10
(integer) 70
127.0.0.1:6379> incrby out 10
(integer) 30
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 10
QUEUED
127.0.0.1:6379(TX)> incrby out 10
QUEUED
127.0.0.1:6379(TX)> exec   #执行之前,另外一个线程修改了监视的值
(nil) 
如果发现事务执行失败,就先解锁
127.0.0.1:6379> unwatch   #解锁
OK
127.0.0.1:6379> watch money   #上锁
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 10
QUEUED
127.0.0.1:6379(TX)> incrby out 10
QUEUED
127.0.0.1:6379(TX)> exec    #在事务执行时,会比对监视的值是否发生变化
1) (integer) 990
2) (integer) 40

Jedis

我们要是使用java来操作Redis

什么是jedis, 是Redis官方推荐的java连接开发工具!使用java操作Redis中间件! 如果你要是用java操作redis,那么一定要对jedis十分熟悉

1.导入对应的依赖

<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.7.0</version>
        </dependency>

<!--        fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>

2.编码测试

​ 连接数据库

​ 操作命令

​ 断开连接

常用的API

String

list

set

hash

zset

继承SpringBoot

springBoot操作数据,spring-data, jpa, jdbc, mongodb, redis!

SpringData也是和SpringBoot齐名的项目

说明:在SpringBoot2.x之后,原来使用的jedis被替换成了lettuce

jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool连接池

lettuce:采用netty ,实例可以在多个线程中共享,不存在线程不安全的情况,可以减少线程数据。

整合测试:

1.导入依赖


    org.springframework.boot
    spring-boot-starter-data-redis

2.配置连接

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

3.测试

Redis.conf详解

启动的时候,通过配置文件来启动

行家有没有,出手就知道

1.配置文件 unit单位对大小写不敏感

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4tmYL0vm-1632618216294)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923162917788.png)]

2.可以包含其他配置文件(导入其他)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCxjHv0T-1632618216296)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923162956515.png)]

3.网络

bind 127.0.0.1 -::1   #绑定的ip
protected-mode yes    #开启保护模式
port 6379    #绑定端口号

4.通用GENERAL

daemonize yes   #以守护进程的方式运行,默认是no,需要自己开启
pidfile /var/run/redis_6379.pid    #如果以后台的方式运行,我们就需要指定一个pid文件!

#日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)    #成产环境使用
# warning (only very important / critical messages are logged)
loglevel notice


logfile ""    #生成的日志文件名
databases 16    #数据库的数量,默认是16
always-show-logo no    #是否显示LOGO

5.快照

持久化,在规定的时间内,执行了多少次操作,则会持久化到文件 .rdb .aof

redis是内存数据,如果没有持久化,那么数据断电即失

#如果3600s内,如果至少有1个key进行了修改,我们就进行了持久化操作
save 3600 1 
#如果300s内,如果至少有10个key进行了修改,我们就进行了持久化操作
save 300 100
#如果60s内,如果至少有10000个key进行了修改,我们就进行了持久化操作
save 60 10000
#我们之后学习持久化,会自己定义这个标准

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

rdbcompression yes   #是否压缩rdb文件,需要消耗一些cpu资源

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

dir ./   #rdb文件保存的目录!

6.REPLICATION复制,我们后面讲解主从复制

7.SECURITY

127.0.0.1:6379> config set requirepass 111111   #设置redis密码
OK
127.0.0.1:6379> config get requirepass   
1) "requirepass"
2) "111111"
127.0.0.1:6379> auth 111111  #登录
OK

8.CLIENTS

maxclients 10000    #最大的客户端数量
maxmemory <bytes>   #redis设置最大的内存容量
maxmemory-policy noeviction   #内存到达最大的上限之后的处理策略
#  随机删除key
#  删除快过期的key

9.APPEND ONLY 模式 AOF配置

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

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

Redis持久化

面试和工作,持久化都是重点!

redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程推出看,服务器中的数据库也会消失,所以Redis提供了持久化功能!

RDB

在主从复制中,rdb就是备用,在从机上面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFtZ5ou0-1632618216298)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923204219461.png)]

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,他恢复是将快照文件直接读到内存里。

Redis会单独创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,在用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效,RDB的缺点是最后一次持久化后的数据可能丢失,我们默认的就是RDB,一般情况下不需要修改这个配置!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ibInthRd-1632618216299)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923172709364.png)]

save   60  5    #60s内修改了5次,就会触发rdb操作

触发规则

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

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

3.退出redis,也会产生rdb文件

如何恢复rdb文件?

1.只需将rdb文件放在我们的redis启动目录就可以了,redis启动的时候会自动检查dump.rdb恢复其中的数据!

2.查看需要存在的位置

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"   #如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中的数据

优点:

1.适合大规模的数据恢复

2.对数据的完整性要求不高!

缺点:

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

2.fork子进程,会占用一定的内存空间

AOF(Append Only File)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wr59O87I-1632618216301)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923204137657.png)]

将我们的所有命令都记录下来到history文件,恢复的时候将命令重新执行一遍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zNSqUDK2-1632618216302)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923201458648.png)]

默认是不开启的,我们需要手动进行配置!我们只需要将appendonly改为yes就开启了aof!

如果这个aof文件有错误,这时候redis是启动不起来的,我们需要修复这个aof文件

redis给我们提供了一个工具 redis-check-aof --fix

重写规则

aof默认就是文件的无线追加,文件会越来越大。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4QnCa4XE-1632618216303)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923203945429.png)]

redis会记录上一次文件的大小,如果aof大于64m,太大了,就会fork一个新进程来将文件重写!

优点和缺点

优点:

1.每一次修改都同步,文件的完整性会更好,每秒同步一次,可能会丢失一秒的数据

2.每秒同步一次,可能会丢失一秒的数据

3.从不同步,效率最高。

缺点:

1.相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢

2.运行效率也要比rdb慢,所以redis默认的持久化配置是rdb持久化

建议总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cM6KcItX-1632618216304)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923204714913.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mgAqVz0f-1632618216305)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923204635084.png)]

Redis发布订阅

redis发布订阅是一种消息通信模式:发送者发送消息,订阅者接收消息,微博、微信、关注系统

发布订阅图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fcHpMNDP-1632618216306)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923212550490.png)]

订阅端:

127.0.0.1:6379> subscribe redis    #订阅一个频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redis"
3) (integer) 1     #等待推送的信息
1) "message"       #消息
2) "redis"		   #频道
3) "hello redis"   #消息具体内容

发送端

127.0.0.1:6379> publish redis "hello redis"   #发布者发送消息到频道
(integer) 1  
127.0.0.1:6379> publish redis "thankyou kuangshen"
(integer) 1

原理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZvrnOOwo-1632618216307)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923213440042.png)]

使用场景

1.实时消息系统!

2.实时聊天!(频道当作聊天,将信息回显给所有人即可!)

3.订阅,关注系统

Redis主从复制

主从复制,是值将一台redis服务器的数据,复制到其他redis服务器上。数据的复制是单向的,只能由主节点到从节点。

主机以写为主,从机以读为主,主从复制,读写分离,80%的情况下都在进行读操作!减缓服务器的压力,架构中经常使用!一主二从!

只要在公司中,主从复制就是必须要使用的

主从复制的作用主要包括:

1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

2.故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余

3.负载均衡:主节点提供写服务,从节点提供读服务

4.高可用基石(集群),除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础

环境配置

只配置从库,不用配置主库!

127.0.0.1:6379> info replication   #查看当前库的信息
# Replication
role:master    #角色  master
connected_slaves:0   #没有从机
master_failover_state:no-failover
master_replid:cbf1945394a5563112925562703737343fcd78b6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> 

复制3个配置文件,然后修改对应的信息

1.端口

2.pid名字

3.log文件名字

4.dump.rdb名字

一主二从

默认情况下,每台Redis服务器都是主节点:我们一般情况下只用配置从机就好了

slaveof ip port   #设置该机的主机  
info replication   #查看该机的信息(为主机还是从机,从记得信息。。。。)

真实的主从配置应该在配置文件中配置,这样的话是永久的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-or2m6iJP-1632618216309)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210923235757310.png)]

设置主机的信息,以及密码

细节

主机可以写,从机不能写只能读!主机中的所有数据都会被从机保存

测试:主机断开连接,从机依旧连接到主机的,如果主机重新回来,依旧可以读取主机写入的值。

如果是使用命令行,来配置的主从关系,这个时候如果从机重启了,就会变回主机,只要再次变回从机,依旧可以读取主机写的数据

slave启动成功连接到master后会发送一个sync同步命令,master将传送所有的数据到slave,并完成一个完全同步

增量复制:

全量复制:

如果没有主机了,这个时候能不能选出一个老大呢?

谋朝篡位

如果主机断开了连接,我们可以使用SLAVEOF no one 将自己变为主机,其他节点就可以手动连接到最新的这个主节点(手动)这个时候原来的主机修复了,只能重新连接

哨兵模式

(自动选举新的主机的模式)

概述

自动将从库转换为主库

哨兵有两个作用:

1.通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。

2.当哨兵检测到master宕机,会自动将slave切换为master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让他们切换主机。

然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此会出现问题,为此,我们可以使用多个哨兵进行监控,各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o5Cm7Tlw-1632618216310)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210924094056089.png)]

假设主服务器宕机,哨兵检测主服务器不可用,当数量达到一定值时,那么哨兵模式就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作,切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线

测试

我们的目前状态时一主二从!

1.配置哨兵配置文件sentinel。conf

#sentinel monitor 被监控的名称 host port  1
sentinel monitor myredis 127.0.0.1 6379 1

后面的1代表主机挂了,slave投票看让谁接替称为主机,票数最多的,就会成为主机!

2.启动哨兵!

哨兵模式

如果主机宕机了,那么会重新在从机中选择一个作主机,此时如果原来的主机回来就会作为从机连接主机。

优点:

1.哨兵集群,基于主从复制模式,所有的主从配置优点,它全由

2.主从可以切换,故障可以装换,系统的可用性就会更好

3.哨兵模式就是主从模式的升级,手动到自动,更加健壮。·

缺点:

1.Redis不好在线扩容的,集群容量一旦到达上限看,在线扩容就十分麻烦!

2.实现哨兵模式的配置其实是很麻烦的,里面有很多选择。

缓存穿透雪崩

面试高频

缓存穿透(查不到,一直查)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2zSNL38-1632618216311)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210925214058260.png)]

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败,当用户很多的时候,缓存都没有命中(秒杀)于是都去请求了持久层数据库,这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

解决方案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-51FFEzZV-1632618216311)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210925214508000.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a49ThsKw-1632618216313)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210925214812526.png)]

但是这种方法会存在两个问题:

1.如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

2.即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于保持一致性的业务会有影响。

缓存击穿(大量的用户访问同一个点,缓存过期)

缓存击穿,是指一个点非常热点,在不停的扛着高并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在屏幕上凿开一个洞。

解决方案

1.设置热点数据库永不过期

​ 从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生问题。

2.加互斥锁(setnx)

​ 每一个key只有一个线程取查询后端服务,其他线程没有获得分布式锁的权限。

缓存雪崩

指在某一个时间段,缓存集体失效,Redis宕机!

产生雪崩的原因之一,比如在写本文的时候,马上就要到双12零点,热点商品集中放入了缓存,假设缓存了一个小时,那么到了凌晨1点的时候,这批商品就过期了,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰,于是所有的请求都会达到了存储层,存储层的调用量会暴增,造成存储挂掉的情况。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-57NRTtTI-1632618216314)(C:\Users\Yu_zhiqiang\AppData\Roaming\Typora\typora-user-images\image-20210925222108036.png)]

解决方案

1.redis高可用

redis有可能挂掉,就多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。

2.限流降级

这个在缓存失效后,通过加锁或者队列来控制读数据库,写缓存的线程数量。

3.数据预热

在正式部署之前,先把可能的数据预先访问一遍,这样可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀。

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败,当用户很多的时候,缓存都没有命中(秒杀)于是都去请求了持久层数据库,这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

解决方案

[外链图片转存中…(img-51FFEzZV-1632618216311)]

[外链图片转存中…(img-a49ThsKw-1632618216313)]

但是这种方法会存在两个问题:

1.如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

2.即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于保持一致性的业务会有影响。

缓存击穿(大量的用户访问同一个点,缓存过期)

缓存击穿,是指一个点非常热点,在不停的扛着高并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在屏幕上凿开一个洞。

解决方案

1.设置热点数据库永不过期

​ 从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生问题。

2.加互斥锁(setnx)

​ 每一个key只有一个线程取查询后端服务,其他线程没有获得分布式锁的权限。

缓存雪崩

指在某一个时间段,缓存集体失效,Redis宕机!

产生雪崩的原因之一,比如在写本文的时候,马上就要到双12零点,热点商品集中放入了缓存,假设缓存了一个小时,那么到了凌晨1点的时候,这批商品就过期了,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰,于是所有的请求都会达到了存储层,存储层的调用量会暴增,造成存储挂掉的情况。

[外链图片转存中…(img-57NRTtTI-1632618216314)]

解决方案

1.redis高可用

redis有可能挂掉,就多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。

2.限流降级

这个在缓存失效后,通过加锁或者队列来控制读数据库,写缓存的线程数量。

3.数据预热

在正式部署之前,先把可能的数据预先访问一遍,这样可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀。

你可能感兴趣的:(redis,数据库,测试工具)