redis

NoSQL

特点

数据之间没有关系,方便扩展

大数据量高性能

数据类型多样, 不需要事前设计数据库

读11w次,写8w次

不仅仅是数据

没有固定的查询语言

键值对存储,列存储,文档存储,图形数据库

最终一致性

CAP定理 和 BASE (异地多活)

四大分类

KV键值对

​ redis

文档型数据库(bson)

  • MongoDB:

    ​ 基于分布式文件存储的数据库,用来处理大量文档

    ​ 介于关系型和非关系型数据库的中间产品

    ​ 属于NoSQL中功能最丰富,最像关系型数据库的

列存储数据库

​ 分布式文件系统

图关系数据库

​ 社交网络、广告推荐

Redis入门

Remote Dictionary Server: 远程字典服务

端口6379

认识

能干嘛?

1、内存存储、持久化。(rbd、aof)

2、效率高,用于高速缓存

3、发布订阅系统

4、地图信息分析

5、计时器计数器

6、。。。

特性

1、多样数据类型

2、持久化

3、集群

4、事务

。。。

WINDOWS

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8zIaI74y-1636819813673)(C:\Users\875415078\AppData\Roaming\Typora\typora-user-images\image-20211030210005160.png)]
如果闪退:redis-server redis.windows.conf
LINUX

安装

直接解压到/opc

配置文件

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

环境安装及启动

yum install gcc-c++:解压完后要下载c++环境,因为redis是c++写的
make:自动安装其他需要的(make2次
make install

自己安装的程序都在/usr/local/bin

将redis配置文件复制到当前目录下
cp /opt/redis-6.2.6/redis.conf kconfig
之后就使用这个配置文件启动

redis默认不是后台启动,要修改配置文件

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

改成yes,以后为后台方式启动

启动redis服务
redis-server kconfig/redis.conf  #(kconfig在/usr/local/bin)

连接服务
redis-cli -p 6379:使用redis客户端连接到端口
ping:返回pong就是成功

设置:set name bb
获取:get name:返回“bb”
查看所有键:keys *

查看服务:ps -ef|grep redis

关闭redis服务
shutdowm :在连接服务中使用

压力测试

redis-benchmark -h localhost -p 6379 -c 100 -n 100000
本机 端口 100个并发连接数  每个连接100000条请求

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

基础知识

数据库

redis默认有16个数据库

默认使用第0个

可以用select num切换

查看DB大小 :DBSIZE

查看DB所有的Key:keys *

清空当前数据库:flushdb

清空全部数据库:flushall

是否存在:exists name:返回1表示存在 / 0

移动:move name 1:移除name到1号数据库

其他

redis是单线程的,是很快的

redis是基于内存操作的,cpu不是redis的性能瓶颈,是机器内存和网络带宽

既然可以使用单线程,那就使用单线程了。

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

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

2、误区:多线程(会产生CPU上下文切换,耗时)一定比单线程效率高

CPU>内存>硬盘

核心:redis是将所有的数据全部放在内存中,所以使用单线程去操作效率是最高的

五大基本数据类型

关于Redis-Key

设置限时:expire key seconds:多长时间后过期

​ 查看剩余时间:ttl key:-2代表没了

查看key的类型:type key

String

set key value 	#设置值
get key			#获取值
keys *			#查看所有key

# 修改
append key1 "hello"		#给key1的value追加字符串"hello","v" -> "vhello"
	ps:如果当前key并不存在  就相当于set key value
strlen key1 #获取字符串长度

# 自增自减
incr key:加1操作
decr key:减1操作
incrby key 10:加10操作
decrby key 11:减11操作

# 截取
getrange key start end	#获取某个范围内 [0,3]  #类似java的substring
# 替换
setrange key offset value #从offset开始,替换成value  #类似java的replace
	例 name:abcd ->  setrange name 1 xx -> axxd 
	
# 设置
setex key seconds value	#set with expire	设置过期时间,跟上面的设置限时同理
setnx key value			#set if not exist	分布式锁
	#如果key不存在再设置,就是如果这个值已经存在了就设置失败(普通set会替换),分布式常用
set key value nx ex 10  #分布式锁:设值的同时加锁并设置过期时间
	
# 一次设置(获取)多对kv
mset k1 v1 k2 v2 k3 v3
mget k1 k2
#特殊
msetnx k1 v1 k4 v4 #是原子性操作,一个失败(k1)全都失败

# getset
getset key newvalue #先get后set
	#如果不存在,返回nil
	#如果已经存在了,先get旧的,再set新的
	#再get,得到的才是新的

# 设置对象

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

List

栈、队列

list所有命令都是l开头的

# 插入
lpush list one 	#将一个值或多个值插入到列表头
lpush list two three	#插入多个
rpush list fuor	#插入到尾(right,从右边插入)
# 查看
lrange list 0 1 #显示list里面[0,1]的数据(从头开始:two one)
lrange list 0 -1#显示list全部数据
# 移除
lpop list [count] #从头移除count个
rpop list [count] #从尾移除count个
# 用下标获取值
lindex list 0 #获取第0个的值
# 查看长度
llen list #返回长度
# 移除指定值
lrem list count element #移除count个指定值element
# 修剪
ltrim list start stop #只保留[start,stop]之间的值
# 移除并添加 
rpoplpush source destination #将列表1最右边的值移除并添加到列表2
# 更新值
lset key index newvalue # 将链表key里面 下标为index的值更新为newvalue
	# 不存在的话会报错 下标越界
# 插入
linsert key before|after which element #在which的前面或后面插入元素element

Set

集合,不能重复

set所有命令都是s开头的

# 添加
sadd key v1 v2 v3.. #可以添加多个
# 查看
smembers key 		#查看这个key的所有元素
sismember key value #判断key中是否存在value(无返回0 有返回1)
scard key			#查看key中元素个数
srandmember key [count]  #随机查看count个元素
# 移除
srem key value 	 #移除元素
spop key [count] #弹出顶部count个元素
smove set1 set2 element #把set1中的元素element移动到set2中

集合

127.0.0.1:6379> SMEMBERS set1
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> SMEMBERS set2
1) "v5"
2) "v4"
3) "v3"

# 差集 sdiff
127.0.0.1:6379> SDIFF set1 set2
1) "v1"
2) "v2"

SDIFF set1 set2 # 以set1为基准(not in set2)

# 交集 sinter (共同关注)
127.0.0.1:6379> SINTER set1 set2
1) "v3"
SINTER set1 set2 # 查找set1 set2的交集

# 并集 sunion
127.0.0.1:6379> SUNION set1 set2
1) "v5"
2) "v2"
3) "v3"
4) "v1"
5) "v4"
SUNION set1 set2 # set1与set2的并集

实战中,将所有关注的人放在set中,粉丝也放在一个set中…

共同关注、共同爱好 推荐好友 你可能认识的人

Hash

类 Map集合, key-Map集合 key-

hash所有命令都是h开头的

# 添加
hset key field1 value1 field2 value2 #已有则替换(会返回0)
# 特殊
hsetnx key field value #如果已存在field就不创建了
# 查看
hget key field #返回value
hmget key field1 field2 #一次性查询多个field
hgetall key #获取所有field和value
hkeys key	#只获取所有的field
hvals key	#只获取所有的value
hlen key	#获取长度(数量)
hexists key field #查看这个feild是否存在(0/1)
# 移除
hdel key field
# 自增自减
hincrby key field increment #给field的value增加increment

Zset

有序集合,底层是条约链表

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

score可以是1 2 3 4 … 自己进行(优先级)排序

# 添加
zadd key score value #score是自己排序
# 查看
zrange key min max 		  # 0 -1 可以查看全部
zrangebyscore key min max [withscores] #查看范围[min,max]; 
	#[-inf,+inf]代表正负无穷到正无穷
	#withscores可以value和score都显示,不添加则只显示value
zrevrangebyscore key max min [withscores] #倒序查看
zcard key #获取集合个数
# 移除
zrem key value1 value2

三种特殊数据类型

geospatial(地理位置)

有6个命令

geo底层实现原理其实是zset,所以可以使用zset命令来操作geo

geoadd 添加

# geoadd 添加地理位置
# 经度从-180 到 180
# 纬度从-85 到 85
geoadd key 经度 纬度 value #geoadd city 116.40 39.90 beijing

geopos 获取

# geopos 获得定位
geopos key value1 value2... #获得value的经纬度

geodist 距离

# geodist 获得两个value之间的距离
geodist key value1 value2 [m|km|...] #返回两地距离

georadius 坐标查找

# georadius 以给定的经纬度为中心,查找半径内的元素
georadius key 经度 纬度 半径 m|km #根据输入的经纬度,查找该地点 指定半径内的其他元素
georadius key 经度 纬度 半径 m|km [withdist] [withcoord]
	# [withdist]  顺带显示其他元素到指定坐标的距离
	# [withcoord] 顺带显示其他元素的定位信息127.0.0.1:6379> georadius city 110 30 500 km
1) "chongqing"
2) "xian"
127.0.0.1:6379> georadius city 110 30 500 km withdist
1) 1) "chongqing"
   2) "341.9374"
2) 1) "xian"
   2) "483.8340"
127.0.0.1:6379> georadius city 110 30 500 km withcoord
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"

georadiusbymember 元素查找

# georadiusbymember 以给定的元素查找半径范围内的其他元素
georadiusbymember key 元素 半径 m|km [withdist] [withcoord] #返回元素半径内的元素(包含自己)

geohash 返回元素hash

# geohash 将二位的经纬度转化成以为的字符串,两个元素字符串越接近,距离越近
geohash key 元素... #beijing->"wx4fbxxfke0"

zset 查看与移除

因为底层是zset,所以可以用zset来操作!!!

# 查看
zrange key 0 -1 [withscores] #查看所有的value [顺带显示hash]
# 移除
zrem key value #移除

hyperloglog(基数统计)

基数:不重复的元素的个数

hf开头,会有0.81%容错率

# 添加
pfadd key element1 element2...
# 查看
pfcount key #查看总数量(会去重)
# 合并
pfmerge key1 key2... #将key2...去重合并到key1(key1不存在会新建)

bitmap(位图)

位存储, 只有0 1,数据结构,都是操作二进制位来记录

场景:登录、活跃、打卡等 两个状态的都可以用

只要1个bit,1字节=8bit,省

# 添加
setbit key offset value #offset自己设(只能数字),value只能0 1
# 查看
getbit key offset #查看value(0/1)
bitcount 

事务操作

事务

一次性、顺序性、排他性

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 k2
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec		#执行事务
1) OK
2) OK
3) "v2"
4) "v1"
5) OK

放弃事务:discard

编译型异常,事务中所有命令都不执行

27.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)> getset k2	# 错误的命令 (set k2 )也不行
(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)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> exec	# 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k5		# 命令没有执行
(nil)

运行时异常,只有错误的那条语句不执行

监控 watch

锁: redis可以实现乐观锁

set money 100
set out 0

watch money #监视money对象
multi		#事务开启
decrby money 20
incrby out 20
#exec		#这里 先不提交事务
############这时插入了另一个线程对money改动############
	set money 1000
##################################################
#接着回到这边,提交事务
exec
(nil)	#返回空,代表事务执行失败,有其他线程对这个money进行了修改

解决办法:如果获取失败,获取最新的值即可
unwatch #先解锁
watch	#再加锁,这样获取的就是最新的值了

Jedis

1、导入对应以来

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

2、编码测试

  • 连接数据库
  • 操作命令
  • 断开连接

测试 事务

public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1",6379);

        Transaction multi = jedis.multi();//开启事务
        try {
            multi.set(new String("a"),new String("hihi"));
            multi.set(new String("b"),new String("hoho"));

            multi.exec();   //执行
        } catch (Exception exception) {
            multi.discard();//回滚
        } finally {
            System.out.println(jedis.get(new String("a")));//hihi
            jedis.close();  //关闭连接
        }
    }

SpringBoot集成Redis

导入依赖

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

简单测试

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("a","hi");
        System.out.println(redisTemplate.opsForValue().get("a"));
    }
}

复杂测试(序列化、json

@Test
void test2() throws JsonProcessingException {
    User bb = new User("bb", 18);
    //        redisTemplate.opsForValue().set("user",bb);
    //没有序列化是不能传输的 //User要加实现序列化接口
    // :User(name=bb, age=18)

    //转化成json对象  //所有对象都要序列化(这里是转json对象
    String jsonBB = new ObjectMapper().writeValueAsString(bb);
    redisTemplate.opsForValue().set("user",jsonBB); 
    // :{"name":"bb","age":18}
    System.out.println(redisTemplate.opsForValue().get("user"));
}

自定义RedisTemplate

因为

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

所以我们自定义redisTemplate

@Configuration
public class redisConfig {

    //自定义RedisTemplate
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate();

        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

自定义redisUtils封装类

代码太多,另见文章

redis.conf配置文件详解

  1. 单位

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

  1. 包含其他配置文件

可以组合其他配置文件

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

  1. 网络
bind 127.0.0.1 -::1  #绑定的ip
protected-mode yes	 #保护模式
port 6379			 #端口号
  1. 通用配置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 #数据库数量
always-show-logo no #是否总是显示logo
  1. 快照

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

redis是内存数据库,如果没持久化,那么数据断电就会丢失

# save 3600 1		#如果3600秒内至少有1个key做了修改,就持久化
# save 300 100
# save 60 10000

stop-writes-on-bgsave-error yes #持久化如果出错了,是否还继续工作
rdbcompression yes	#是否压缩rdb文件(rdb:持久化文件)
rdbchecksum yes		#保存rdb时是否进行检查校验
dir ./				#rdb文件保存的目录
  1. 复制REPLICATION
  1. 安全

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

自定义密码 root

也可以用命令来设置密码

127.0.0.1:6379> config get requirepass	#查看密码
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "root"	#设置密码

auth root #输入密码  才能进行操作
  1. 限制CLIENTS
# maxclients 10000   #最大客户端数量
# maxmemory <bytes>	 #redis配置的最大内存容量
# maxmemory-policy noeviction #内存满了之后的处理策略
	1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
	2、allkeys-lru : 删除lru算法的key   
	3、volatile-random:随机删除即将过期key   
	4、allkeys-random:随机删除   
	5、volatile-ttl : 删除即将过期的   
	6、noeviction : 永不过期,返回错误
  1. APPEND ONLY 模式 aof配置
appendonly no   # 默认不开启aof模式,默认使用rdb方式持久化,大部分情况下
appendfilename "appendonly.aof"  # 持久化文件的名字

# 同步
# appendfsync always	#每次修改都同步(消耗性能
appendfsync everysec	#每秒执行一次(可能丢失这一秒数据
# appendfsync no		#不同步

具体配置在持久化中详细讲解

持久化

如果只做缓存,就不需要持久化了

因为Redis是内存数据库,如果不保存到磁盘中,断电就消失,所以要持久化。

同时开启两种方式,优先载入aof文件来恢复数据,因为aof文件保存的数据更完整,

RDB(Redis DataBase)

默认的redis数据库,在主从复制中,rdb是备用的,在从机上面用

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

在指定的时间间隔将内存中的数据集快照写入磁盘,恢复时是将快照文件直接读到内存。

redis会单独fork创建一个子线程来进行持久化,会先将数据读到一个临时文件,等持久化过程结束了,再用这个临时文件替换上次持久化好的文件。

整个过程中,主线程不进行IO操作,确保高性能。

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

dump.rdb

触发机制

1、save命令(保存配置),会自动触发rdb规则

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

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

4、触发快照也会触发rdb操作

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

恢复rdb

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

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

2、查看需要存放的位置

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

优缺点

优点:

1、适合大规模的数据恢复 :dump.rdb

2、对数据完整性要求不高

缺点:

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

2、fork进程的时候,会占用一定的内存空间

AOF(Append Only File)

将我们的所有命令都记录下来,history,恢复的时候,就把这个文件全部执行一边

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

一般来说,只需要将no改成yes,开启就行了,其他使用默认即可

aof文件被破坏了,如何恢复

如果 appendonly.aof 文件被破坏了,redis启动不了(redis-cli -p 6379会报错)

需要恢复: redis-check-aof

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

redis提供了工具:redis-check-aof --fix

redis-check-aof --fix appendonly.aof 会丢弃错误的数据

重写规则

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

如果aof文件大于64m,就会fork一个新的进程来将文件重写

aof默认就是文件只限制追加,文件就会越来越大

优缺点

appendonly no  #默认不开启aof
appendfilename "appendonly.aof"  # 持久化文件的名字

# 同步策略
# appendfsync always	#每次修改都同步(消耗性能
appendfsync everysec	#每秒执行一次(可能丢失这一秒数据
# appendfsync no		#不同步

优点:

1、每一次修改都同步,完整性更好

2、每秒同步一次,可能会丢弃一秒的数据

3、从不同步,效率最高

缺点:

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

2、aof运行效率低,是io操作,所以我们默认rdb持久化而不是aof

订阅发布(消息队列)

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

测试

订阅端:

127.0.0.1:6379> subscribe c1	#订阅频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "c1"
3) (integer) 1

#等待接收消息
1) "message"	#消息
2) "c1"			#频道
3) "nihao"		#接收的消息

发送端:

publish chanel message 发布消息

主从复制

概念

主从复制,就是将一台redis服务器的数据复制到其他redis服务器,分为主节点和从节点。

主从复制,读写分离。80%的读操作放到从,写放到主中进行。一主二从。

单台redis最大使用内存不应该超过20G

作用

1、数据冗余:主从复制实现了数据热备份

2、故障恢复:主节点出现问题时可以由从节点提供服务

3、负载均衡:读写分离,提高并发量

4、高可用(集群)基石:哨兵和集群的基础

info replication:查看复制信息

127.0.0.1:6379> info replication
# Replication
role:master			#角色
connected_slaves:0	#没有从机
master_failover_state:no-failover
master_replid:8a09e83b5cdd576df8f7a83f09fe43478a5cdc4c
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

准备工作

复制并修改多个redis.conf配置文件

​ (改端口,改pidfile,改日志名,改dump.rdb名字

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

一主二从

默认情况下,每台redis服务器都是主节点,所以只要配置从机

配从机:认主银!

1、这里是用命令配,实际中使用配置文件配

slaveof host port

#在6380中:
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave	#角色:从机
master_host:127.0.0.1	#主机地址
master_port:6379		#主机端口

用配置文件配主,这样才是永久的

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

主机负责写,从机负责读

结论一:主机才能写,从机只能读,从机写会报错

结论二:如果主机关了(宕机),从机依然是连接主机的,但是没有写操作,这时候如果主机回来了,从机依然可以读取主机写的东西

结论三:如果使用命令配置从机的,从机断了重启后,会变回主机;但是再把他配回从机后,这期间主机写的数据他还是能获取的(同步

原理

slave启动成功连接到主机后会发送一次sync同步命令

master接到命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,

在后台进程完毕后,master将传送整个数据文件到slave,并完成一次完全同步

  • 全量复制:而slave在接收到数据库文件数据后,将其存盘并加载到内存中
  • 增量复制:master继续将新的所有收集到的修改命令依次传给lave,完成同步

但是只要是重新连接master,依次完全同步(全量复制)将自动进行,我们的数据一定可以再从机得到

哨兵模式

自动选举老大模式

测试

目前:1主(6379)2从(6380/6381)

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

#sentinel monitor 被监控的名称 主机 端口 1
sentinel monitor myredis 127.0.0.1 6379 1
# 最后的1代表 主机挂了,从机投票看让谁接替成为主机,票数最多的当主机

2、启动哨兵

bin目录下文件redis-sentinel

redis-sentinel kconfig/sentinel.conf

[root@localhost bin]# redis-sentinel kconfig/sentinel.conf
27788:X 11 Nov 2021 22:14:54.239 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
27788:X 11 Nov 2021 22:14:54.239 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=27788, just started
27788:X 11 Nov 2021 22:14:54.239 # Configuration loaded
27788:X 11 Nov 2021 22:14:54.241 * Increased maximum number of open files to 10032 (it was originally set to 1024).
27788:X 11 Nov 2021 22:14:54.241 * monotonic clock: POSIX clock_gettime
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 6.2.6 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 27788
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           https://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

27788:X 11 Nov 2021 22:14:54.243 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
27788:X 11 Nov 2021 22:14:54.264 # Sentinel ID is 62b26ebe620df2ef05a3d045fb2164efc54bd23d
27788:X 11 Nov 2021 22:14:54.264 # +monitor master myredis 127.0.0.1 6379 quorum 1
27788:X 11 Nov 2021 22:14:54.270 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:14:54.273 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

然后,如果主机宕机了shutdown,哨兵配置文件这里就会发现,然后选择一个从机当主机

27788:X 11 Nov 2021 22:23:36.567 # +sdown master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.567 # +odown master myredis 127.0.0.1 6379 #quorum 1/1
27788:X 11 Nov 2021 22:23:36.567 # +new-epoch 1
27788:X 11 Nov 2021 22:23:36.567 # +try-failover master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.571 # +vote-for-leader 62b26ebe620df2ef05a3d045fb2164efc54bd23d 1
27788:X 11 Nov 2021 22:23:36.571 # +elected-leader master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.571 # +failover-state-select-slave master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.630 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.     0.1 6379
27788:X 11 Nov 2021 22:23:36.630 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 63     80 @ myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:36.686 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @      myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:37.236 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.     0.1 6379
27788:X 11 Nov 2021 22:23:37.236 # +failover-state-reconf-slaves master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:37.290 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127     .0.0.1 6379
27788:X 11 Nov 2021 22:23:38.255 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 1     27.0.0.1 6379
27788:X 11 Nov 2021 22:23:38.255 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127     .0.0.1 6379
27788:X 11 Nov 2021 22:23:38.355 # +failover-end master myredis 127.0.0.1 6379
27788:X 11 Nov 2021 22:23:38.355 # +switch-master myredis 127.0.0.1 6379 127.0.0.1 6380
27788:X 11 Nov 2021 22:23:38.356 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6380
27788:X 11 Nov 2021 22:23:38.356 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380
27788:X 11 Nov 2021 22:24:08.387 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ myredis 127.0.0.1 6380

注意最后 可以看出6380成了新的主机

如果后来6379回来了,则6379会变成从机,主机依然是6380

6380: 现在我是老大了,回来只能做我小弟

优缺点

优点:

1、哨兵集群,基于主从复制,所有主从复制优点他都有

2、主从可以切换,故障可以转移,系统可用性更好

3、哨兵模式就是主从模式的升级:手动到自动

缺点:

1、redis不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦

2、实现哨兵模式的配置很麻烦,里面有很多选择(我们配的是最基础的

缓存穿透(查不到)

概念

当用于查询数据时,如果redis内存数据库中没有,就向持久层数据库查询,发现也没有,于是查询失败。当用户很多的时候,缓存都没有命中,于是都去请求持久层数据库,这会给持久层数据库带来很大压力,这就是缓存穿透

解决方案

布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免对底层存储系统的查询压力。

缓存空对象

当存储层不命中后,即时返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据就会从缓存中获取,保护了后端数据源

缓存击穿(量太大,缓存过期)

概念

key是有时效的

一个key非常热点,不断地大并发请求这个key,在这个key失效的瞬间,持续的大并发就会穿破缓存,直接请求数据库。

解决方案

设置热点数据永不过期

不设置过期时间,也就不会出现热点key过期后产生的问题

缺点:不现实,浪费

ps:也可以设置久一点

加互斥锁

set key value nx ex 10

nx: 加锁

ex 10 :过期时间10秒

分布式锁:使用分布式锁,保证每个key同时只有一个线程去查询后端,其他线程等待。

缺点:这种方式把高并发的压力转移到了分布式锁

缓存雪崩

概念

在某一个时间段,缓存集中过期失效,或是redis宕机

比如双十一,马上0点,这时集中放入了缓存,过了一个小时后,这批商品的缓存集体失效了,于是对这批商品的查询就落到数据库上,对数据库而言就会产生周期性压力波峰,造成存储层也挂掉的现象。

解决方案

1、redis高可用,搭建集群,多增设几台redis,一台挂了其他还可以用

2、限流降级:缓存失效后,通过加锁或者队列来控制数据库写缓存的线程数量

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值