学习资源整理自:B站《狂神说》
NoSql四大分类:
KV键值对:
引用菜鸟截图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9TuryoZf-1598462218016)(E:\TheGreatWaterway\Redis全解析.assets\20200807124452620.png)]
中文官网:www.redis.cn
1、Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
2、Redis作用
3、特性
默认端口6379的由来:redis作者当时特别喜欢一个女明星,然后她的名字对应九宫格的数字是6379。
直接拿官网最新版: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)]
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)]
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是基于内存操作,cpu不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了。
数据直接存储在内存上,操作数据速度非常快,无需使用多线程导致cpu指针的切换造成不必要的资源损失。
命令 | 举例 | 解释 |
---|---|---|
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
value除了是存储字符串之外还可以是数字;
所有的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 |
可以想象成链表结构,有各种变化,可以从左边插入、右边插入或改动,但从中间操作元素效率相对较低;
无序,不重复集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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的合集 |
共同好友:查看交集
二度好友:朋友的朋友的朋友的朋友…
推荐好友:我的多个朋友的共同好友
想象成 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)]
有序集合
在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(权重);
排行榜
等等
地理位置
(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
基数统计算法
简介
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合并在一起 |
位存储 位图
只存放 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的和。场景:统计一周的打卡次数 |
Redis单条命令是保留原子性的,但是事务是不保证原子性的。
Redis事务的本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行。
一次性、顺序性、排他性
------- 队列 set set set 执行 -------
在事务中,存在某一条语句错误,但是事务不会终止,但最终执行时,全部命令都不会执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w8shseAJ-1598462218034)(E:\TheGreatWaterway\Redis全解析.assets\20200808131804230.png)]
当exec时,其它语句会照样执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqT9uXTu-1598462218036)(E:\TheGreatWaterway\Redis全解析.assets\20200808132045816.png)]
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)]
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();
}
}
SpringBoot操作数据:SpringData jpa jdbc mongodb 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所有的配置类,都有一个自动配置类
自动配置类都会绑定一个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();
}
默认配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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)]
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,操作系统自己同步数据
Redis是内存数据库,数据属于断电既失的情况,所以需要持久化的能力。
redis有两种持久化策略 rdb 和 aof,默认使用rdb模式。
触发机制:
1、save规则,满足则执行rdb持久化
2、执行flushall
3、退出redis
数据恢复:
当redis启动的时候,会自动检查redis.conf中配置的持久化规则,去寻找是否有对应的持久化文件,如果有则会回复文件中的数据。
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进程会占用一定的系统资源
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
引用菜鸟资料
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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
实时消息系统
实时聊天(频道当作聊天室,将信息回显给聊天的人)
订阅,关注系统
稍微复杂的场景使用消息队列实现。
主从复制是指将一台Redis服务器的数据,复制到其它的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower)。数据的复制是单向的,只能由主节点到从节点(主从复制、读写分离)Master以写为主、Slave以读为主。
PS:默认情况下,每台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
端口:port 6379
后台服务:daemonize yes
pid文件 :pidfile /var/run/redis_6379.pid
rdb文件:dbfilename dump.rdb
日志文件:logfile “6379.log”
分别启动三个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,就会完成一次全量复制。
这种模式下,当Master宕机之后,需要手动执行命令让Slave1成为老大:
slaveof on one
此时如果Master回来了,需要手动配置集群结构。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wu66ESi5-1598462218066)(E:\TheGreatWaterway\Redis全解析.assets\20200809173909773.png)]
自动选取老大
主从切换技术的方法是:当主服务器宕机后,手动把一台从服务器切换为主服务器,需要人工干预,耗时费力并且会造成一段时间内服务不可用情况。这不是一种推荐的方法,更多时候我们优先考虑哨兵模式。Redis2.8开始正式提供Sentinel(哨兵)架构来解决这个问题。
谋朝篡位自动版,能够后台监控主机是否故障,如果故障了将根据投票决定自动将一台从机转换为主机。
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程。进程原理:哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OEp2bRWa-1598462218067)(E:\TheGreatWaterway\Redis全解析.assets\20200809173930698.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wGsWEMqG-1598462218068)(E:\TheGreatWaterway\Redis全解析.assets\20200809173943250.png)]
目前集群结构为:一主二从
#sentinel monitor 监听名 host port 票数
sentinel monitor myredis 127.0.0.1 6379 2
后面的票数代表主机挂了之后,Slave投票让谁成为主机,票数多的成为主机。
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
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)]
存在两个问题:
(某个热点缓存持续高并发查询)
指的是一个key非常热门,一直在被大并发集中查询,然后当这个key瞬间过期失效时,持续的大并发就会穿透缓存,直接冲击到数据库(类似于一堵墙,在一个空被穿出一个洞)
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期问题,避免了缓存击穿
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其它线程没有获得分布式锁的权限不能去查询。这种实现方式将高并发的压力转移到分布式锁上,因此对分布式锁的考验较大。
指的是缓存在某一个时间点,集体失效。(Redis宕机、集体过期)
比如:双十一的时候,热门商品被放入缓存中,过期设置1小时,那么凌晨一点时,缓存集体过期,那么就会对数据库造成一个压力波峰,极有可能将持久层冲垮;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-McqWdENg-1598462218077)(E:\TheGreatWaterway\Redis全解析.assets\20200809174123800.png)]
集中过期还不是非常危险,更为致命的是缓存服务器某个节点宕机断网,将全部压力直接卸到持久层上。
redis集群,当一台挂了还会有别的redis顶上。(异地多活)
意思是在正式启用之前,先把可能访问的数据预先访问一遍,让大部分数据先存入缓存中。
在即将发生大并发访问前,手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点分布均匀。
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询攻击。
[外链图片转存中…(img-jnCvViKf-1598462218073)]
当存储层不命中后,即使返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据会从缓存中获取,保护了后端数据源
[外链图片转存中…(img-iaCfr6CO-1598462218073)]
存在两个问题:
(某个热点缓存持续高并发查询)
指的是一个key非常热门,一直在被大并发集中查询,然后当这个key瞬间过期失效时,持续的大并发就会穿透缓存,直接冲击到数据库(类似于一堵墙,在一个空被穿出一个洞)
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期问题,避免了缓存击穿
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其它线程没有获得分布式锁的权限不能去查询。这种实现方式将高并发的压力转移到分布式锁上,因此对分布式锁的考验较大。
指的是缓存在某一个时间点,集体失效。(Redis宕机、集体过期)
比如:双十一的时候,热门商品被放入缓存中,过期设置1小时,那么凌晨一点时,缓存集体过期,那么就会对数据库造成一个压力波峰,极有可能将持久层冲垮;
[外链图片转存中…(img-McqWdENg-1598462218077)]
集中过期还不是非常危险,更为致命的是缓存服务器某个节点宕机断网,将全部压力直接卸到持久层上。
redis集群,当一台挂了还会有别的redis顶上。(异地多活)
意思是在正式启用之前,先把可能访问的数据预先访问一遍,让大部分数据先存入缓存中。
在即将发生大并发访问前,手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点分布均匀。