爬梯:Redis全解析(一)

学习资源整理自:B站《狂神说》

Redis全解析

1、NoSql介绍

NoSql四大分类:
KV键值对:

  • 新浪:Redis
  • 阿里、百度:Redis+memcache
    文档型数据库(Bson格式和Json一样):
  • MongoDB
    • 基于分布式文件存储的数据库,C++编写,主要存储大量的文档;
    • 介于非关系型数据和关系型数据库的中间产品,mongoDB是非关系型数据库中功能最丰富的,最像关系型数据库的非关系型数据库。
  • CouchDB
    列存储数据库
  • Hbase
  • 分布式文件系统
    图关系数据库(不是存图形的,放的是关系比如:朋友圈社交网络,广告推荐)
  • Neo4j
  • InfoGrid

引用菜鸟截图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9TuryoZf-1598462218016)(E:\TheGreatWaterway\Redis全解析.assets\20200807124452620.png)]

2、Redis概述

中文官网:www.redis.cn

1、Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
2、Redis作用

  • 内存存储、可以持久化(rdb、aof)
  • 效率高,可以高速缓存
  • 发布订阅系统(简单消息功能)
  • 地图信息分析
  • 计时器、计数器(页面浏览量等)
  • 等等

3、特性

  • 数据类型多样
  • 持久化
  • 集群
  • 事务
  • 等等

默认端口6379的由来:redis作者当时特别喜欢一个女明星,然后她的名字对应九宫格的数字是6379。

3、Linux下Redis安装

直接拿官网最新版:https://redis.io/
然后丢到linux上
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U1k6O3Pg-1598462218019)(E:\TheGreatWaterway\Redis全解析.assets\20200807135039163.png)]
解压 安装

tar -zvxf redis-5.0.8
make 
......
#然后在目录下会有个src文件夹
cd src
redis-server #启动
reids-cli -h localhost -p 6379 #访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jv3f7oP0-1598462218020)(E:\TheGreatWaterway\Redis全解析.assets\20200808181309385.png)]

4、Redis性能测试工具

redis-benchmark 官方自带压力测试工具
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 10000
命令 菜鸟截图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qeZAlOhe-1598462218024)(E:\TheGreatWaterway\Redis全解析.assets\20200807142853556.png)]
结果分析:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWrsT86i-1598462218026)(E:\TheGreatWaterway\Redis全解析.assets\20200807143652927.png)]

5、Redis基础知识

Redis默认有16个数据库,默认使用第0个数据库。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m60wbPid-1598462218027)(E:\TheGreatWaterway\Redis全解析.assets\20200807144125504.png)]

命令 举例 解释
select切换数据库命令 select 3 切换数据库到第四个
keys查看全部key的命令 keys 查看全部都key
flushdb清空当前数据库命令 flushdb
flushall清空全部数据库命令 flushall
exists是否存在命令 exists key
move移动key命令 move key 1 将key移动到数据库1号
expire设置key时效 expire key 10 设置key十秒后过期
ttl查看key的剩余时间 ttl key
type查看数据类型 type key

Redis单线程

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

数据直接存储在内存上,操作数据速度非常快,无需使用多线程导致cpu指针的切换造成不必要的资源损失。

6、Redis五个基础数据类型

String

命令 举例 解释
append追加命令 append key “hello” 在key的值末尾添加 hello,如果当前key不存在,则新建这个key(相当于set)
strlen查询值的长度 strlen key
incr加一命令 incr key 给key的值加一
decr减一命令 decr key 给key的值减一
incrby增加步长,指定增量 incryby key 10 加10
decrby减少步长,指定增量 decrby key 10 减10
getrange获取字符串指定索引区间的值 getrange key 0 3 获取key值从0到3位置的值
getrange key 0 -1 获取key值的全部字符串
setrange把某个位置的值替换成新的值 setrange key 1 xx 将key值从指定位置开始,替换为新的值
setex设置过期时间命令 setex key 30 “hello” set with expire设置key,值为hello,30秒后过期
setnx如果不存在则执行set setnx key “world” set if not exist如果key不存在则存入key,值为world,如果存在,则不操作 (设置分布式锁时常用)
mset批量设置值 mset key1 val1 key2 val2 存入key1和key2,值分别为val1和val2
mget批量获取值 mget key1 key2 同时获取key1和key2的值
msetnx批量设置 原子性,只有同时成功,或者同时失败,不会部分存入部分不存入
getset命令 getset key 123 先执行get,在执行set,若不存在则返回null,set新键值,若存在则获取值,再设值。这里返回key原来的值,并将key的值设置为123

对象操作思想

设置一个key为user,值为json格式的数据保存用户信息
set user {name:xiaoming,age:3}
这样做不便于解析,应使用:
mset user:name xiaoming user:age 3

String类型使用场景

value除了是存储字符串之外还可以是数字;

  • 计数器
  • 统计数量(阅读量+1)
  • 粉丝数
  • 对象缓存存储

List

  • 在redis里面,可以吧list设置成栈、队列、阻塞队列;
  • 数据可以重复;

所有的list命令,都是以 “l” 开头。
lpush存入命令
存入时的顺序是 one two three,而取出时的顺序是 three two one,先进后出FILO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mqqo3Ox4-1598462218028)(E:\TheGreatWaterway\Redis全解析.assets\20200807163013195.png)]

命令 举例 解释
lpush存入命令 lpush list val1 在list的最前面/左边加入值val1
rpush存入命令 rpush list four 将数据存入list的末尾,最后一个位置
lrange获取列表对应位置的值 lrange list 0 3 第0位置到第3位置
lpop移除列表第一个元素 lpop list 移除list的左边第一个值
rpop移除列表最后一个元素 rpop list 移除list的最右边最后一个元素
lindex通过下标获取值 lindex list 0 获取第0个位置的值
llen获取长度 llen list
lrem移除指定个数的值 lrem list 2 one 移除list中的 两个 one值
ltrim截取指定位置区间的值 ltrim list 1 2 截取从1到2位置的值,覆盖原来的值,保留截取后的值
rpoplpush移除最后一个元素加入另一个list的第一个位置 rpoplpush list1 list2 将list1的最后一个值删除,并在list的第一个位置插入这个值
lset给列表指定位置替换/设置 值 lset list 1 val 给list的1下标位置的值,替换为“val”。若list的1位置没有值,则会报错:不存在
linsert给list指定位置的插入一个值 linsert list before val1 val2 指的是在值为val1的位置 前 插入值:val2
linsert list afterval1 val2 指的是在值为val1的位置 后 插入值:val2

List使用场景

可以想象成链表结构,有各种变化,可以从左边插入、右边插入或改动,但从中间操作元素效率相对较低;

  • 简单的消息队列:Lpush Rpop(双向队列)
  • 栈:Lpush Lpop

Set

无序,不重复集合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OX3w5DqV-1598462218029)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826162955638.png)]

命令 举例 解释
sadd添加数据命令 sadd myset “hello” 向myset里面添加“hello”值
smembers查看数据 smembers myset 加载myset全部数据
sismember查看某个值是否存在 sismember myset 判断某一个值是否在集合中,存在返回1,不存在返回0
scard查看集合中个数 scard myset 查看myset的长度
srem移除单个值的命令 srem myset hello 将myset中的hello移除
srandmember随机抽取指定个数的元素 srandmember myset 1 在myset随机抽取一个元素
spop随机移除元素 spop myset 随机加载myset中的一个值,并移除
smove移动数据命令 smove myset myset2 “hello” 将myset中的“hello”移动到myset2中
sdiff集合差集 sdiff myset myset2 加载myset和myset2的差集
sinter查看交集 sinter myset myset2 加载myset和myset2的交集,查看共同好友
sunion查看合集 sunion myset myset2 加载myset和myset2的合集

Set简单应用:

共同好友:查看交集

二度好友:朋友的朋友的朋友的朋友…

推荐好友:我的多个朋友的共同好友

Hash

想象成 key-val 结构
本质和String类型没有太大区别
hash更适合于对象的存储

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VfT4Pqve-1598462218030)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826163600925.png)]

命令 举例 解释
hset添加值 hset myhash item1 val1 存入值item1-val1
hget获取hash指定key的值 hget myhash item1 读取myhash中的item1
hget myhash item1 item2 读取myhash中的item1和item2的值
hgetall获取全部值 hgetall myhash 加载myhash全部数据
hdel删除指定key命令 hdel myhash item 删除myhash中item的key和对应的值
hlen获取hash长度 hlen myhash 查询myhash的长度
hexists判断是否存在命令 hexists myhash item3 判断myhash中的指定key是否存在
hkeys查询全部的key hkeys myhash
hvals查询全部的值 hvals myhash
hincrby指定某个key增加指定数值 hincrby myhash item1 1
hsetnx如果不存在则设置 hsetnx myhash item1 hello 如果myhash中的item1不存在,则设入hello,若存在则不操作

使用hash类型存储用户信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WW50p25V-1598462218031)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826163949945.png)]

ZSet

有序集合
在set的基础上增加了一个值,多了一个只能是数字的序号

所以ZSet诞生的目的多半是为了排序~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IRlHoEjR-1598462218033)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826164113630.png)]

命令 举例 解释
zadd存入值 zadd myset 1 one 在myset的1位置存入one
zadd myset 2 two 3 three
zrange myset 0 -1
zrangebyscore排序加载数据 zrangebyscore myset -inf +inf 加载myset中从负无穷到正无穷,小到大排序
zrangebyscore myset -inf +inf withscores 排序并附带score数据
zrangebyscore myset -inf 2 withsocres 最小到2
zrange myset 0 -1 从大到小排序
zrem移除命令 zrem myset three 移除three
scard加载集合长度 scard myset 获取集合长度
zcount区间内的数量 zcount myset 1 2 获取1和2之间的有多少个值

简单案例:
班级成绩表、工资表;
普通消息:1 重要消息:2(权重);
排行榜
等等

7、Redis三个特殊数据类型

geospatial

地理位置
(key 纬度 经度 val)

朋友的定位、附近的人、打车距离计算等
推算地理位置的信息、两地之间的距离,方圆几里的人
Redis的Geo在3.2版本推出
经度纬度网站:http://www.jsons.cn/lngcode/
两极无法添加。
一般使用程序配置文件直接处理。

命令 举例 解释
geoadd添加 geoadd china:city 116 39 beijing 添加北京市经纬度
geopos获取经度纬度 geopos china:city beijing 获取北京的经纬度
geodist返回两个给定位置之间的距离 geodist china:city beijing shanghai km 以千米为单位计算北京到上海的距离,单位可以从官网获取
georadius以给定的经纬度为中心获取半径内的元素 georadius china:city 110 30 1000 km withdist 获取经度110纬度30,半径1000千米内的元素,携带经度
georadius china:city 110 30 1000 km withcoord count 1 携带纬度,限定数量1个
georadiusbymember以某个元素为中心获取指定半径内的元素 georadiusbymember china:city beijing 100 km 获取china:city数据中的北京以100千米为半径的距离的元素
geohash将经纬度转换为十一位字符串展示 geohash china:city beijing 获取北京的经纬度,以字符串展示

底层实现原理其实是zset,属于zset变种。故可以使用zset命令:zrange china:city、zrem china:city

Hyperloglog

基数统计算法

简介
Redis2.8.9版本更新后发布Hyperloglog数据格式
优点
占用的内存是固定的,2^64不同的元素的技术,只需要12KB内存,如果从内存角度考虑的话Hyperloglog是首选。
官方表示,数据量大时存在0.81%的错误率。
简单应用
网页UV(一个人访问某个网站多次,统计为一个人)
传统方式,set保存用户的id,然后统计set中的元素数量作为判断标准。
传统方式弊端:会保存大量的用户ID,如果用户ID使用分布式ID或uuid的形式,就会比较耗内存。

命令 举例 解释
pfadd添加元素 pfadd mypf a b c d e f g
pfcount统计数量 pfcount mypf 统计不重复的元素的个数
pfmerge合并 pfmerge mypf mypf2 mypf3 将mypf、mypf2、mypf3合并在一起

Bitmap

位存储 位图

只存放 0 1

统计用户信息:活跃、不活跃,登录、未登录。
统计打卡:打卡、未打卡
统计疫情感染人数,0为感染、1为未感染
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1

命令 举例 解释
setbit存值 setbit sign 0 1 在sign的0位置存储1
setbit sign 1 1 假定sign为一周的打卡情况,周一打卡
setbit sign 2 0 假定sign为一周的打卡情况,周二未打卡
getbit获取 getbit sign 2 读取sign2位置的值。场景:周二是否打卡
bitcount统计 bitcount sign 获取数据中的1的和。场景:统计一周的打卡次数

8、Redis事务

Redis单条命令是保留原子性的,但是事务是不保证原子性的。

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

  • 开启事务(multi)
  • 命令入队(…)
  • 执行事务(exec)
  • 放弃事务(discard)事务中的命令都不会执行

编译型异常:

在事务中,存在某一条语句错误,但是事务不会终止,但最终执行时,全部命令都不会执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w8shseAJ-1598462218034)(E:\TheGreatWaterway\Redis全解析.assets\20200808131804230.png)]

运行时异常:

当exec时,其它语句会照样执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqT9uXTu-1598462218036)(E:\TheGreatWaterway\Redis全解析.assets\20200808132045816.png)]

监控 Watch

redis的 watch是一个乐观锁,认为什么时候都不会出问题,所以不会上锁,在更新数据的时候判断,在此期间是否有人修改过这个数据,version版本号。

获取version>更新的时候比较version

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EL9MPbHj-1598462218037)(E:\TheGreatWaterway\Redis全解析.assets\20200808132925545.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sW5o1CX0-1598462218038)(E:\TheGreatWaterway\Redis全解析.assets\20200808133106535.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qk9CX3Zy-1598462218040)(E:\TheGreatWaterway\Redis全解析.assets\20200808133502982.png)]

9、Jedis操作Redis

Jedis是Redis官方推荐的java链接开发工具,使用Java操作Redis中间件。

就是一个java操作reids的jar包


    redis.clients
    jedis
    3.3.0

全部指令都在此直接使用

    public static void main(String args[]){
     
        //1 创建Jedis对象 192.168.0.106
        Jedis jedis = new Jedis("192.168.1.181",6379);
        // 使用jedis可以执行之前学习的全部命令
        System.out.println(jedis.ping());
        System.out.println(jedis.set("1", "1"));
    }

Jedis操作事务

public static void main(String[] args) {
     
    Jedis jedis = new Jedis("192.168.1.181",6379);
    System.out.println(jedis.ping());
    jedis.select(10);//切换数据库

    JSONObject user1 = new JSONObject();
    user1.put("name","石似心");
    user1.put("age",24);
    //1、创建事务
    Transaction multi = jedis.multi();
    try {
     
        //2、填充事务
        multi.set("user1",user1.toJSONString());
        multi.set("user2",user1.toJSONString());
        // 产生异常
        int i = 1/0;
        //3、执行事务
        multi.exec();
    } catch (Exception e) {
     
        //4、放弃事务
        // 若产生异常,则放弃,整个事务内容不会执行
        multi.discard();
        e.printStackTrace();
    } finally {
     
        System.out.println(jedis.get("user1"));
        System.out.println(jedis.get("user2"));
        //4、关闭redis链接
        jedis.close();
    }
}

10、SpringBoot操作Redis

SpringBoot操作数据:SpringData jpa jdbc mongodb redis

引用操作Redis的工具包


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>

底层是SpringData操作的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ju1cGRTU-1598462218041)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826173908273.png)]

SpringBoot1.x 底层使用的是 Jedis操作redis

SpringBoot2.x 底层使用的是lettuce操作redis

jedis:采用直连,多个线程操作是不安全的,如果想要避免线程安全问题,就需要使用jedis pool连接池。BIO模式

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

SpringBoot配置Redis

SpringBoot所有的配置类,都有一个自动配置类

自动配置类都会绑定一个properties配置文件

找到配置类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mB6W5k0B-1598462218043)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826175002065.png)]

配置类源码

@Bean
// 如果redisTemplate不存在则创建,也意味着可以自定义一个代替
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
      throws UnknownHostException {
     
   // 默认redisTemplate没有过多设置,而redis对象都是需要序列化的,需要自定义配置
    //两个参数泛型都是Object,正常工作多半是String,Object  
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
   template.setConnectionFactory(redisConnectionFactory);
   return template;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wTw2DH8f-1598462218044)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826175201439.png)]

工厂类有两个实现类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YCIsniIT-1598462218045)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826175839530.png)]

其中jedis很多类都是不存在了的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ONFL1Ur-1598462218047)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826175859672.png)]

而lettuce是正常的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OXTy4xct-1598462218047)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826175927188.png)]

故此,在配置的时候,需要使用lettuce,因为jedis的代码已经不存在,配置也不会生效。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ijihgboh-1598462218049)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826180033318.png)]

代码实测

@Autowired
RedisTemplate redisTemplate;

@Test
void contextLoads() {
     
    // opsForValue() 操作 String
    // opsForList() 操作 List
    // opsForSet() 操作 Set
    // opsForHash() 操作 Hash
    System.out.println(redisTemplate.opsForList().leftPush("ssx", "handsome"));
    System.out.println("输出:"+redisTemplate.opsForList().range("ssx",0,-1));

    // 获取链接
    // RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
    // connection.flushDb();
}

RedisTemplate

默认配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PIEsEjkA-1598462218050)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826183823108.png)]

默认使用JDK序列化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eDvyJ1OG-1598462218051)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826183942065.png)]

自定义redisTemplate

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
        throws UnknownHostException {
     
    // 日常使用一般使用 
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    template.setConnectionFactory(redisConnectionFactory);

    //json序列化配置
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    //String的序列化
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

    //key采用String的序列化方式
    template.setKeySerializer(stringRedisSerializer);
    //hash的key采用String序列化方式
    template.setHashKeySerializer(stringRedisSerializer);
    //value序列化方式采用jackson
    template.setValueSerializer(jackson2JsonRedisSerializer);
    //hash的value序列化方式采用jackson
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();

    return template;
}

企业中都会有RedisUtil类,让redis操作更流畅顺手

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ldGweYPi-1598462218052)(E:\TheGreatWaterway\Redis全解析.assets\image-20200826232024423.png)]

11、Redis配置文件详解

redis.conf以下都是默认配置

######### INCLUDES #########
# 包含,可以想properties一样包含其他配置文件
# include /path/to/local.conf
# include /path/to/other.conf
######### NETWORK ##########
# 绑定地址,可以接收请求的链接,改成 0.0.0.0 或者 * 表示通配
bind 127.0.0.1

# 保护模式,非本机访问需要将其关闭
protected-mode yes

port 6379 # 监听端口
######### GENERAL ########
# 以守护进程的方式运行,默认no,意思是是否可以后台运行redis
daemonize no

# 如果以后台方式运行,我们需要制定一个pid文件
pidfile /var/run/redis_6379.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个

#是否显示logo,就是运行redis-server的时候那个redis logo
always-show-logo yes

########## SNAPSHOTTING  ########
# 快照 

# 持久化的执行规则,复合条件则执行一次数据持久化 .rdb .aof
# 如果900秒内,有至少1个key修改过
# 如果300秒内,有至少10个key修改过
# 如果60秒内,至少有10000个key修改过
save 900 1
save 300 10
save 60 10000

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

rdbcompression yes # 是否压缩rdb文件(压缩会消耗cpu资源)

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

dbfilename dump.rdb # rdb文件名

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

########## SECURITY #########
# 密码,默认是注释掉,没有密码的
# requirepass foobared
# 也可以通过命令修改密码:config set requirepass 123

######### CLIENTS ##########
# 最大连接数,默认不限制,指的是同时存活的redis客户端
# maxclients 10000

######## MEMORY MANAGEMENT ########
# 最大内存容量
# maxmemory <bytes>

# 内存满了之后的处理策略
# maxmemory-policy 六种方式
# 1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) 
# 2、allkeys-lru : 删除lru算法的key   
# 3、volatile-random:随机删除即将过期key   
# 4、allkeys-random:随机删除   
# 5、volatile-ttl : 删除即将过期的   
# 6、noeviction : 永不过期,返回错误
# maxmemory-policy noeviction

####### APPEND ONLY MODE #######
# aof
# 默认不开启aof模式,默认使用rdb模式
appendonly no    
    
# aof持久化文件名
appendfilename "appendonly.aof"
    
# aof同步模式 
# appendfsync always  # 每次修改都会 sync,比较消耗性能
appendfsync everysec  # 每秒执行一次sync,可能会丢失1秒的数据
# appendfsync no # 不执行 sync,操作系统自己同步数据

12、Redis持久化

概念

Redis是内存数据库,数据属于断电既失的情况,所以需要持久化的能力。

redis有两种持久化策略 rdb 和 aof,默认使用rdb模式。

触发机制:

1、save规则,满足则执行rdb持久化

2、执行flushall

3、退出redis

数据恢复:

当redis启动的时候,会自动检查redis.conf中配置的持久化规则,去寻找是否有对应的持久化文件,如果有则会回复文件中的数据。

rdb

redis database

在指定持久化条件符合时,将内存中的数据集写入磁盘中。

redis会创建一个fork子进程来进行持久化操作:

1、首先将数据写入一个临时文件中;

2、等到全部数据都写入临时文件后,再用这个临时的rdb文件替代上一次持久化的rdb文件,成为正式rdb文件。

在整个持久化过程中,全部io操作都由fork进程完成,确保了主进程的高性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydCBjd3f-1598462218055)(E:\TheGreatWaterway\Redis全解析.assets\image-20200827002430561.png)]

redis.conf

dbfilename dump.rdb # rdb文件名
dir ./   # rdb文件保存的目录 

优点:高性能、适合大规模恢复数据

缺点:可能会丢失最后一次持久化的数据(持久化过程中宕机等情况)、fork进程会占用一定的系统资源

aof

append only file 将命令追加到文件

aof策略是指,将每一条写指令以日志的形式存入aof文件,在需要恢复时redis会将aof文件中的写指令逐行执行

aof文件修复:

如果aof文件遭到破坏,aof模式的redis将无法启动。使用redis-check-aof工具修复:

redis-check-aof --fix appendonly.aof

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2FbeswAx-1598462218056)(E:\TheGreatWaterway\Redis全解析.assets\image-20200827004152612.png)]

redis.conf

##### APPEND ONLY MODE #####
# 默认不开启,修改为yes重启生效
appendonly no
appendfilename "appendonly.aof"

# appendfsync always
appendfsync everysec
# appendfsync no

# 是否不需要重写aof文件
no-appendfsync-on-rewrite no

# 当aof文记达到64兆的100%时,重写一个新的文件来继续存储指令
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

优点

1、数据的完整性会更好

2、最多丢失1秒的数据

3、不需要同步则不需要fork进程周期进行持久化

缺点

1、aof的文件远大于rdb的文件大小

2、数据恢复的速度慢于rdb

持久化总结扩展

  1. rdb持久化方式能够在指定的时间间隔内对数据进行快照存储
  2. aof持久化方式记录每次对服务器的写操作,当服务器重启的时候会重新执行这些命令来恢复原始数据,aof命令以Redis协议追加保存命令到文件末尾,Redis还能对aof文件进行后台重写,使得AOF文件的体积不至于过大;
  3. 只需要缓存功能,如果你只希望你的数据在服务器运行的时候存在,你也可以不做任何持久化
  4. 同时开启两种缓存的方式
    • 在这种情况下,当Redis重启的时候会优先载入AOF文件来恢复原始数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的更完整;
    • RDB的数据不实时,同事使用两者时服务器重启也只会找AOF文件,即便如此,也不是说仅仅只开启AOF模式就可以,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不能保证AOF不会出现语句错误,留一个后手;
  5. 性能建议
    • 因为rdb文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次即可,只保留900 1的规则;
    • 如果开启AOF,好处是在恶劣情况下也只会丢失不超过两秒的数据,启动脚本较简单只load AOF文件就可以,代价是:1.带来持续的IO 2、AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成阻塞几乎是不可避免的,所以只要硬盘大小允许,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认为64m太小了,可以设置到5G以上,默认超过原始大小100%时重写可以改到适当值;
    • 如果不启动AOF,仅靠Master-Slave Replication 实现 高可用也可以,能节省大部分IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave同事崩掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个(微博使用这种架构)。

13、Redis发布订阅

引用菜鸟资料
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s1maKBfg-1598462218057)(E:\TheGreatWaterway\Redis全解析.assets\20200809173417968.png)]
订阅/发布消息图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5POpKus-1598462218059)(E:\TheGreatWaterway\Redis全解析.assets\20200809173504370.png)]

演示

订阅端:

127.0.0.1:6379> subscribe ssxChennel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "ssxChennel"
3) (integer) 1
#进入等待阶段,等待频道消息推送
1) "message" 	#消息
2) "ssxChennel" #频道名
3) "helloCust" 	#消息内容

发送端:

127.0.0.1:6379> publish ssxChennel helloCust
(integer) 1

应用场景

  1. 实时消息系统

  2. 实时聊天(频道当作聊天室,将信息回显给聊天的人)

  3. 订阅,关注系统

    稍微复杂的场景使用消息队列实现。

14、Redis主从复制

概念

主从复制是指将一台Redis服务器的数据,复制到其它的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower)。数据的复制是单向的,只能由主节点到从节点(主从复制、读写分离)Master以写为主、Slave以读为主。

PS:默认情况下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有),而一个从节点只能由一个主节点。

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

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的数据冗余方式;
  2. 故障恢复:当主节点出问题时,可以由从节点提供服务,实现快速的故障恢复(服务冗余);
  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载;一般系统是读的压力更大可以通过多个从节点分担“读”的压力;
  4. 高可用:主从复制还是哨兵和集群能够实现的基础,因此说主从复制是Redis高可用的基础。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zECNvL2m-1598462218061)(E:\TheGreatWaterway\Redis全解析.assets\20200809173535344.png)]

一般生产环境是不可以使用单台Redis;

环境配置

默认情况下,每台Redis服务器都是主节点

127.0.0.1:6379> info replication
# Replication
role:master #主节点
connected_slaves:0
master_replid:d1ca96e10d765ebb85d9db44475211bade81534d
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

配置集群:

三份配置文件:实例:6379 6380 6381

  1. 端口:port 6379

  2. 后台服务:daemonize yes

  3. pid文件 :pidfile /var/run/redis_6379.pid

  4. rdb文件:dbfilename dump.rdb

  5. 日志文件:logfile “6379.log”

  6. 分别启动三个redis
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tLx6qQmY-1598462218062)(E:\TheGreatWaterway\Redis全解析.assets\20200809173732822.png)]

集群配置:一主二从

让从机去认老大
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nk4HWNL1-1598462218063)(E:\TheGreatWaterway\Redis全解析.assets\20200809173749451.png)]

使用命令配置主从集群

配置6380:

127.0.0.1:6380> slaveof 127.0.0.1 6379	#配置主机的host和port  (我使用localhost能连接成功,但主机没找到从机....)
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:d507237df1352cd264dfe399b439c2872dca4977
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0

主机6379:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=14,lag=1
master_replid:d507237df1352cd264dfe399b439c2872dca4977
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

一般生产环境直接在配置文件中配置,永久配置

# replicaof  
# masterauth 

主写 从读

#主机写入
127.0.0.1:6379> set key1 v1
OK

#从机读取
127.0.0.1:6380> get key1
"v1"
127.0.0.1:6380> set key2 v2
(error) READONLY You can't write against a read only replica. #从机不能进行写操作

主机宕机重连

127.0.0.1:6379> shutdown
not connected> exit

此时关闭了主机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iP6aauNL-1598462218064)(E:\TheGreatWaterway\Redis全解析.assets\20200809173837159.png)]
然后主机重启 设值

[root@localhost redis-5.0.8]# src/redis-server redis.conf
[root@localhost redis-5.0.8]# src/redis-cli -p 6379
127.0.0.1:6379> set key2 v2
OK

从机读取值

127.0.0.1:6380> get key2  
"v2"   #还是可以读取到,意味着恢复了主从链接关系

从机宕机重连

如果使用命令配置的主从关系,从机重启会失去关联主机(重启不能恢复主从结构)

但如果再使用命令关联到主机 slaveof,此时会将主机中的数据全部恢复过来从机。

复制原理

Slave启动成功连接到Master后会发送一个sync同步命令。

Master接到命令后,启动后台存盘进程,收集所有接收到的写命令,在后台进程执行完毕之后,Master将传送整个文件到Slave完成一次数据同步;

官方名词:

  • 全量复制:Slave服务器接收到数据文件后,将其存盘并全数加载到内存中;
  • 增量复制:Master在接收到写命令时,依次将命令发送给Slave完成同步;

只有Slave重新连接到Master,就会完成一次全量复制。

集群配置:链路集群

这种模式下,当Master宕机之后,需要手动执行命令让Slave1成为老大:

slaveof on one

此时如果Master回来了,需要手动配置集群结构。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wu66ESi5-1598462218066)(E:\TheGreatWaterway\Redis全解析.assets\20200809173909773.png)]

15、Redis哨兵模式

自动选取老大

概述

主从切换技术的方法是:当主服务器宕机后,手动把一台从服务器切换为主服务器,需要人工干预,耗时费力并且会造成一段时间内服务不可用情况。这不是一种推荐的方法,更多时候我们优先考虑哨兵模式。Redis2.8开始正式提供Sentinel(哨兵)架构来解决这个问题。

谋朝篡位自动版,能够后台监控主机是否故障,如果故障了将根据投票决定自动将一台从机转换为主机

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程。进程原理:哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

单哨兵模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OEp2bRWa-1598462218067)(E:\TheGreatWaterway\Redis全解析.assets\20200809173930698.png)]

多哨兵模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wGsWEMqG-1598462218068)(E:\TheGreatWaterway\Redis全解析.assets\20200809173943250.png)]

  1. 当主服务器宕机后,假设哨兵1先检测到这个结果,此时这个主服务会被判定为“主观下线”,不会立刻进行failover(故障转移)操作。
  2. 当另外的哨兵都检测到主服务器宕机并且数量达到一定值后,那么哨兵之间就会进行一次投票,投票的行为由其中一台哨兵发起,即进行failover操作。
  3. 切换成功后,会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机操作,这个过程成为“客观下线”。

实操

目前集群结构为:一主二从

  1. 配置哨兵文件 sentinel.conf
#sentinel monitor 监听名 host port 票数
sentinel monitor myredis 127.0.0.1 6379 2

后面的票数代表主机挂了之后,Slave投票让谁成为主机,票数多的成为主机。

  1. 启动哨兵进程
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OD8TbdJw-1598462218068)(E:\TheGreatWaterway\Redis全解析.assets\20200809174011893.png)]
    当主机宕机,一定时间后会由哨兵进行选举另外一台作为主机。

优点

  1. 哨兵集群,基于主从复制模式,所有的主从配置优点
  2. 主从可以自动切换,故障自动转移,Redis实现高可用
  3. 从手动模式的主从模式升级,更加健壮实时

缺点

  1. Redis不好进行在线扩容,集群容量一旦达到上限后,在线扩容十分麻烦
  2. 实现哨兵模式的全套配置较为麻烦

哨兵模式全套配置:

bind 172.31.11.235
port 26380
daemonize yes
logfile "/usr/local/redis-4.0.9/sentinel.log.26380"

#master1
# 哨兵监控这个master,在至少1个哨兵实例都认为master down后把master标记为odown
sentinel monitor master1 172.31.11.235 6380 1#多少毫秒后,sentinel 认定redis master 服务器已掉线sentinel down-after-milliseconds master1 5000
# 若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败
sentinel failover-timeout master1 10000
#sentinel can-failover master1 yes
sentinel parallel-syncs master1 2
# Generated by CONFIG REWRITE
dir "/usr/local/redis-4.0.9"
sentinel auth-pass master1 xxxxx

16、Redis缓存穿透、击穿和雪崩

Redis缓存的使用极大的提升了性能和效率,特别是数据查询方面。但是也带来了一些问题,其中最致命的是数据一致性问题,从严格意义上讲这个问题无解。如果对数据一致性要求较高,那么就不能使用缓存。

另外一些典型问题如:缓存穿透、缓存雪崩和缓存击穿。

缓存穿透

(某类绕过缓存查询数据库的数据)

缓存穿透的意思是,当用户想要查询一个数据,然后Redis中并没有,于是缓存没有命中,那么就会进入持久层中去数据库查,发现也没有,于是本次查询失败。

然后当这类查询被无数次执行时(恶意攻击、秒杀等),一直无法存入缓存,一直向数据库进行查询,则会造成数据库被攻击的现象,这就叫做 缓存击穿。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLpIDOcb-1598462218072)(E:\TheGreatWaterway\Redis全解析.assets\20200809174036123.png)]

布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询攻击。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jnCvViKf-1598462218073)(E:\TheGreatWaterway\Redis全解析.assets\20200809174043599.png)]

缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据会从缓存中获取,保护了后端数据源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iaCfr6CO-1598462218073)(E:\TheGreatWaterway\Redis全解析.assets\20200809174106968.png)]
存在两个问题:

  1. 如果空值被存储存储起来,也意味着使用了更多的内存空间;
  2. 虽然对空值设置了过期时间,还是会存在缓存层和存储层会有一段时间数据不一致问题,此时业务对一致性要求较高时则会造成不必要的影响。

缓存击穿

(某个热点缓存持续高并发查询)

指的是一个key非常热门,一直在被大并发集中查询,然后当这个key瞬间过期失效时,持续的大并发就会穿透缓存,直接冲击到数据库(类似于一堵墙,在一个空被穿出一个洞)

设置热点数据不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期问题,避免了缓存击穿

加互斥锁

分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其它线程没有获得分布式锁的权限不能去查询。这种实现方式将高并发的压力转移到分布式锁上,因此对分布式锁的考验较大。

缓存雪崩

指的是缓存在某一个时间点,集体失效。(Redis宕机、集体过期)

比如:双十一的时候,热门商品被放入缓存中,过期设置1小时,那么凌晨一点时,缓存集体过期,那么就会对数据库造成一个压力波峰,极有可能将持久层冲垮;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-McqWdENg-1598462218077)(E:\TheGreatWaterway\Redis全解析.assets\20200809174123800.png)]
集中过期还不是非常危险,更为致命的是缓存服务器某个节点宕机断网,将全部压力直接卸到持久层上。

Redis高可用

redis集群,当一台挂了还会有别的redis顶上。(异地多活)

限流降级

  • 分布式锁限流,控制只能有一个或几个线程可以访问后台;
  • 降级:临时关闭其他不紧急的服务,来为主服务让出服务器资源;

数据预热

意思是在正式启用之前,先把可能访问的数据预先访问一遍,让大部分数据先存入缓存中。

在即将发生大并发访问前,手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点分布均匀。

布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询攻击。
[外链图片转存中…(img-jnCvViKf-1598462218073)]

缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据会从缓存中获取,保护了后端数据源
[外链图片转存中…(img-iaCfr6CO-1598462218073)]
存在两个问题:

  1. 如果空值被存储存储起来,也意味着使用了更多的内存空间;
  2. 虽然对空值设置了过期时间,还是会存在缓存层和存储层会有一段时间数据不一致问题,此时业务对一致性要求较高时则会造成不必要的影响。

缓存击穿

(某个热点缓存持续高并发查询)

指的是一个key非常热门,一直在被大并发集中查询,然后当这个key瞬间过期失效时,持续的大并发就会穿透缓存,直接冲击到数据库(类似于一堵墙,在一个空被穿出一个洞)

设置热点数据不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期问题,避免了缓存击穿

加互斥锁

分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其它线程没有获得分布式锁的权限不能去查询。这种实现方式将高并发的压力转移到分布式锁上,因此对分布式锁的考验较大。

缓存雪崩

指的是缓存在某一个时间点,集体失效。(Redis宕机、集体过期)

比如:双十一的时候,热门商品被放入缓存中,过期设置1小时,那么凌晨一点时,缓存集体过期,那么就会对数据库造成一个压力波峰,极有可能将持久层冲垮;
[外链图片转存中…(img-McqWdENg-1598462218077)]
集中过期还不是非常危险,更为致命的是缓存服务器某个节点宕机断网,将全部压力直接卸到持久层上。

Redis高可用

redis集群,当一台挂了还会有别的redis顶上。(异地多活)

限流降级

  • 分布式锁限流,控制只能有一个或几个线程可以访问后台;
  • 降级:临时关闭其他不紧急的服务,来为主服务让出服务器资源;

数据预热

意思是在正式启用之前,先把可能访问的数据预先访问一遍,让大部分数据先存入缓存中。

在即将发生大并发访问前,手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点分布均匀。

你可能感兴趣的:(Redis,redis)