传统 RDBMS 和 NoSQL
传统的 RDBMS(关系型数据库)
- 结构化组织
- SQL
- 数据和关系都存在单独的表中 row col
- 数据定义语言(crud)
- 严格的一致性
- 基础的事务(ACID)
- ...
NoSQL
- 不仅仅是数据
- 没有固定的查询数据
- 键值对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性
- CAP定理和BASE (异地多活,即一个地方的应用宕机了,不影响其他地区的)
- 高性能,高可以,高可扩
- ...
了解:3V+3高
大数据时代的3V:主要是描述问题的
海量Volume
多样Variety
实时Velocity
大数据时代的3高:主要是对程序的要求
真正在公司中的实践:NoSQL+RDBMS
KV键值对:
文档型数据库(bson格式 和 json一样)
列存储数据库
图关系数据库
4 种数据库结构的详解与各自优缺点
Redis 是什么?
Redis(Remote Dictionary Server ),即远程字典服务!
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis会周期性的把更新的数据写入磁盘或者修改操作写入追加的记录文件,并且在此基础上实现master-slave(主从)同步。也被人们称之为结构化数据库!
Redis 能干嘛?
1、内存存储、持久化,内存中是断电即失、所以说持久化很重要(rdb、aof)
2、效率高,可以用于高速缓存
3、发布订阅系统
3、地图信息分析
5、计数器、计时器(浏览量!)
6、…
特性
1、多样的数据类型
2、持久化
3、集群
4、事务
5、Redis单线程,单进程
6、Redis是一个高性能key/value内存型数据库
…
Redis推荐都是在Linux服务器上搭建,基于Linux学习
官方介绍
redis-benchmark性能测试执行
https://www.bilibili.com/video/BV1S54y1R7SB?p=10&spm_id_from=pageDriver
redis默认有16个数据库:可以去她的config文件里查看:databases 16
默认使用的是第0个:
select n 进入你想进的数据库
DBSIZE 查看DB大小(数据库大小)
keys * 查看数据里面的所有键
flushdb 清空当前库 flushall 清空全部库
Redis 是单线程的!
Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程,就使用单线程!快阿,没人争! 单线程,其根本其实就是进程!那就没有其他线程进行上下文的切换!
Redis是C语言写的,官方提供的数据为 100000+的QPS,完全不比同样是使用了key-value的Memecache差!
Redis为什么单线程还这么快!
1、误区1:高性能的服务器一定是多线程的?
2、误区2:多线程一定比单线程效率高?(CPU上下文会切换,所有肯定不是拉)
CPU>内存>硬盘的速度!
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在CPU上的,在内存情况下,这个就是最佳的方案!
Redis的启动方式三种:
因为个人已经弄过软链接了,所以直接:redis-server 就可以了
启动一个 ,进入到redis中的src目录下 在控制台输入指令:
redis-server (注意:这样启动默认端口是 6379 )
进入客户端输入:redis-cli
查看进程,杀死进程
指定端口启动redis服务
redis-server --port 8888
进入客户端:redis-cli -p 8888
配置文件启动(注意:这里一定要注意 必须是root 用户操作)
redis中的配置文件是 redis.conf
我们先看看如何使用配置文件启动:
启动指令:./src/redis-server redis-01.conf
注意:这里要注意 我这里的启动方式加了 目录 。 有的兄弟 可能 有一点差异(redis-server redis-6379.conf 直接输入这个即可)
daemonize 守护进程是否启动 Yes/No
注意:如果开启(yes),redis将以服务的形式存在,日志将不再打印到命名窗口中。
port 6… 设定当前端口号
注意:如果使用配置文件启动多个服务,这里一定要记得改端口。
logfile “xxx.log” 设定存放日志的文件。
注意:每个服务都必须对应一个日志文件,这样方便我们查阅。
dir 存放日志“目录的路径”
注意:日志要统一管理。
redis里存储的有这5种类型嘛!按照这些类型存储在库中,然后按照对应查询语句可以去查询对应里面的内容。
例:查看所有数据: keys *
1) "list" 这个是以 list 存的
2) "name" 这个是以 k-v 存的
127.0.0.1:6379> lrange list 0 -1 这个是查的list里面还包含了这些数据
1) "item0"
2) "item1"
keys * 查看所有的key
set 'key' 'value' 插入key
exists 'keyName' 判读当前key是否存在
move 'keyName' 1(1代表第几个库) 移除当前key
expire 'keyName' value 设置key的过期时间 ttl 'keyName' 查看当前key的剩余时间
type 'keyName' 查看当前key的存储类型
append 'keyName' 'value' 往某个key追加字符串 如果key不存在,就相对于set key 新建一个
strlen 'keyName' 获取key的length
incr 'keyName' 增一 (这个'keyName'的vlaue是一个数字的情况下)
decr 'keyName' 减一
incrby 'keyName' 10 增步长 一下增10
decrby 'keyName' 10 减步长 一下减10
getrange 'keyName' stare end 截取字符串
getrange 'keyName' 0 -1 获取全部字符串 和 get key 是一样的
setrange 'keyName' value 串 从第value位向后替换串
##########################################################################################################
setex 'keyName' 'second' 'value' (set with expire) # set一个值的同时设置过期时间
setnx 'keyName' 'value'(set if not exist) # 值不存在再设置,即如果存在这个值就不插入 (在分布式锁中会常常使用!)
##########################################################################################################
批量插入
mset k1 v1 k2 v2 k3 v3
批量获取
mget k1 k2 k3
批量set,如果不存在值
msetnx k1 v1 k4 v4 ,在上面的条件下,会失败。这是一个原子性操作,即要么全成功,要么全失败,而上面k1已经有了,所有是不成功的。
#对象
set user:{name:zhangsan,age:3} # 设置一个user:1对象,值位 json 字符来保存一个对象!
# 这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在Redis中是完全OK的!这也是保存文章浏览量的一个方法,id部分代表对应文章
# 另一种书写(个人感觉上面的set好理解些):mset user:1:name zhangsan user:1:age2
# 获取:mset user:1:name user:1:age
#######################################################################################
getset # 先get再set 如果不存在,就返回nil 再插入这个,如果存在的,就拿出来原先的,更新插入的,这次拿的还是老的,下次就不是了!
深度学习你会发现:数据结构是相通的:例如原子操作CAS比较再交换和这个结构就是有点相通的。
String类型的使用场景:value除了是我们的字符串还可以是我们的数字!
基本的数据类型,列表。
在redis里面,我们可以把list玩成:栈、队列、阻塞队列!
所有的list命令都是 l 开头的, Redis 不区分 大小写 ,list 是可以允许重复值的,不像上面的string
############################################################################
LPUSH 'name' 'value' 填值(头部插入)
LRANGE 'name' 0 -1 获取所有值
LRANGE 'name' 0 1 获取指定区间值
Rpush 'name' 'value' 尾部插入
就像是一个链表:头插法进行的,取也是从头取,所有第一个放,变成在最右边,所以是最后一次拿。
#######################################################################
Lpop 'name' 移除list的第一个元素
Rpop 'name' 移除list的最后一个值
Lindex 'name' 返回列表长度
Lrem 'name' 1 one 移除那个列表里的1个叫one的值,依次搜索one,找到就删了,后面的one就不动它了
lrem 'name' 2 tow 移除俩个tow
###########################################################################
trim 修剪:通过下表截取指定长度,但要明白这个list已经被修改了
ltrim 'name' 1 2 截取 第1、2个数
rpoplpush # 移除列表的最后一个元素增到一个新的列表里
rpoplpush 'listname' 'listname1'
#########################################################################
exists 'listname' 查看是否存在值
lset 将列表中指定下标的值替换为另外一个值,更新操作
# 如果不存在列表我们去更新就会报错
# 如果存在
lset list 0 item 更新当前下标的值,换为item
########################################################################
linsert 在哪个值的前后插入值
linsert 'list' before 'listname' 'value'
linsert 'list' after 'listname' 'value'
小结
消息队列!(Lpush Rpop),栈(Lpush Lpop),这样就变成了队列和栈!
set中的值是无序不重复的!
sadd 'setname' 'value' 存值
smembers 查看指定set所有值
sismember 'setname' 'value' 判断某一个值是不是在set集合中!
#########################################################################
scard 'setname' 获取set集合中的内容的集合个数
srem 'setname' 'value' 移除指定集合里的指定值
spop 'setname' 随机移除元素
##########################################################################
抽奖api
srandmember 'setname' 随机数
srandmember 'setname' 'value' 随机指定数
#########################################################################
将一个指定的值,删除移动到某个set集合
smove 'setname' 'setname1' 'value'
##########################################################################
微博,b站等共同关注!(交集)
数字集合类:
- 差集
- 交集
- 并集
sinter 'setname1' 'setname2' 看第一个和第二个里面的交集
sdiff 'setname1' 'setname2' 看第一个和第二个里面的差集
sunion 'setname1' 'setname2' 并集
场景:微博,b站,一个人关注的人,粉丝各放在一个集合中!
就可以利用上面的交差并查出共同关注等。
Map集合,key-map! 时候这个值是一个map集合!本质和String类型没有太大区别,还是一个简单的key-value!不同的是,这个值是由俩个键组成的。
就是一个hash表名,里面放着 k-v!
hset 'hashname''field' 'value' 存值
hget 'hashname''field' 取值
hmset 'hashname''field1' 'value1' 'field2' 'value2' 存多个值
hmget 'hashname''field1' 'field2' 取多个值
hgetall 'hashname' 获取所有
例如:hgetall 'hashname' 得到
1)"field1"
2)"hello"
3)"field2"
4)"world"
值是以俩个键组成的
hdel 'hashname' 'field' 删除hash指定的key字段! 对应的value值也就消失了!
#########################################################################
hlen 'hashname' 查看里面有多少个key
hexists 'hashname' 'field' 判断hash中指定字段是否存在!
#########################################################################
hkeys 'hashname' 获取所有的key
hvals 'hashname' 获取所有的value
########################################################################
incr decr
127.0.0.1:6379> hset myhash field 5 指定初始量
(integer) 1
127.0.0.1:6379> HINCRBY myhash field 1 加一
(integer) 6
127.0.0.1:6379> HINCRBY myhash field -1 减一
(integer) 5
127.0.0.1:6379> Hsetnx myhash field1 hello 不存在就加入
(integer) 1
127.0.0.1:6379> Hsetnx myhash field1 hello 存在不加入
(integer) 0
hash可以存储变更的数据 user name age(与上方string的介绍类似),尤其是用户信息之类,经常变动的信息!hash更适合对象的存储,string更适合字符串存储!
在set的基础上,增加了一个值,set k1 v1 zst k1 score1 v1
zadd 'Zsetname' '序号' 'value' 存值 (添加一个)
zadd myset 1 one 2 tow 存入多个
############################################################################
排序(-inf +inf 代表从负无限到正无限)
#ZRANGEBYSCORE key min max 官网规定是从最小值到最大值
zrangebyscore 'Zsetname' -1 0 正序得到value
zrangebyscore 'Zsetname' -inf +inf 正序得到value
zrangebyscore 'Zsetname' -inf +inf withscores 正序得到序号+value
zrevrange 'Zsetname' 0 -1 倒序得到value
#########################################################################
移除元素
zrem 'Zsetname' 'value' 移除有序中指定元素
zcard 'Zsetname' 获取有序集合的个数
zcount 'Zsetname' stare end 获取指定区间有多少个值
案例思路:set 排序 存储班级成绩表,工资表排序!
普通消息,1,重要信息,2,带权重进行判断 =》例如b站播放量排行榜!(排行榜)
朋友的定位,附近的人,打车距离计算,这个功能可以推算地理位置的信息,两地间距离,方圆几里的人!
getadd
getpos
geodist
georadius 以给定的经纬度为中心,找出某一半径内的元素
georadiusbymember
geohash 命令 - 返回一个或多个位置元素的 geohash 表示
GEO 底层的实现原理其实就是 Zset ! 我们可以使用Zset命令来操作geo!
基数:不重复的数
hyperloglog只有这三个命令:PFADD、PFCOUNT、PFMERGE,他并不能像set,Zset(有序不重复)等一样获取到里面的值,他只是一个统计数而已!
基数:可理解为不重复的数,例如在一个hyperloglog 里里面的值为 1 3 4 5 3 7 其拿出来是1 3 4 5 7,如下:
127.0.0.1:6379> PFADD a 1 3 4 5 3 7
(integer) 1
127.0.0.1:6379> PFCOUNT a
(integer) 5
并且加入已有的数值也会加入失败
127.0.0.1:6379> PFADD a 1
(integer) 0
如上所说,可以用这个来作为浏览器登录的访问计数,比如可以在1小时内保存下浏览人数,在下一个1小时内再记录一下,然后几个小时后把几小时内的这些数据合并一下,作为访问数量堆加!或者数量小的话。
位存储
统计用户信息,活跃,不活跃!登录、未登录!(QQ),打卡! 两个状态的,都可以使用Bitmaps!
Bitmaps 位图,数据结构! 都是操作二进制来进行记录,就只有 0 和 1 两个状态!
----------------------------------------------------------------------------------------------------------------------
Redis 事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性、顺序性、排他性!执行一系列的命令!
------ 队列 set set set 执行 ------
Redis事务没有隔离级别的概念!(即幻读,脏读,不可重复读都不可能)
所有的命令都在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!Exec
Redis单条命令是保证原子性的,但是事务不保证原子性!
redis的事务:
每一个事务执行完就没了,下一次要重新输入multi,因为你上一个执行完成了就证明结束了,那个事务就结束了。
悲观锁:
乐观锁:
Redis 监视测试
watch … 确定监控对象 watch可以把他想象成锁
单线程情况下:
多线程情况下(开启多个客户端去调试呗):
使用watch可以当作redis的乐观锁操作!
就是在一个端里进行watch一个key, multi 操作,然后set value ,但是并不exec ,在另一个客户端里将刚刚存进去key进行重新set,即修改,那么在第一个端里的exec并不会执行成功,会报nil。
多个端进行操作,模拟多线程。
测试多线程修改值,使用 watch 可以当做 redis 的乐观锁操作!
失败先解锁!
应用场景:redis乐观锁实现秒杀系统
什么是Jedis?
Jedis 是 Redis 官方推荐的java连接开发工具!使用Java操作Redis 中间件!如果你要使用java操作redis,那么一定要Jedis十分的熟悉!
测试
1、导入对应的依赖
<dependencies>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>3.2.0version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.62version>
dependency>
dependencies>
2、编码测试:
package com.kuang;
import redis.clients.jedis.Jedis;
public class TestPing{
public static void main(String[] args) {
// 1、 new Jedis 对象
Jedis jedis = new Jedis("127.0.0.1", 6379);
// jedis 所有的命令就是我们之前学习的所有指令!所以之前的指令学习很重要!
System.out.println(jedis.ping());
}
}
Key、String、List、Set、Hash、Zset、geospatial、hyperloglog、bitmaps 跟上面讲过的一样
java操作key
java操作String
//测试String相关
@Test
public void testString(){
//set
jedis.set("name","小陈");
//get
String s = jedis.get("name");
System.out.println(s);
//mset
jedis.mset("content","好人","address","海淀区");
//mget
List<String> mget = jedis.mget("name", "content", "address");
mget.forEach(v-> System.out.println("v = " + v));
//getset
String set = jedis.getSet("name", "小明");
System.out.println(set);
//............
}
操作List相关API
//测试List相关
@Test
public void testList(){
//lpush
jedis.lpush("names1","张三","王五","赵柳","win7");
//rpush
jedis.rpush("names1","xiaomingming");
//lrange
List<String> names1 = jedis.lrange("names1", 0, -1);
names1.forEach(name-> System.out.println("name = " + name));
//lpop rpop
String names11 = jedis.lpop("names1");
System.out.println(names11);
//llen
jedis.linsert("lists", BinaryClient.LIST_POSITION.BEFORE,"xiaohei","xiaobai");
//........
}
操作Set的相关API
//测试SET相关
@Test
public void testSet(){
//sadd
jedis.sadd("names","zhangsan","lisi");
//smembers
jedis.smembers("names");
//sismember
jedis.sismember("names","xiaochen");
//...
}
操作ZSet相关API
//测试ZSET相关
@Test
public void testZset(){
//zadd
jedis.zadd("names",10,"张三");
//zrange
jedis.zrange("names",0,-1);
//zcard
jedis.zcard("names");
//zrangeByScore
jedis.zrangeByScore("names","0","100",0,5);
//..
}
操作Hash相关API
//测试HASH相关
@Test
public void testHash(){
//hset
jedis.hset("maps","name","zhangsan");
//hget
jedis.hget("maps","name");
//hgetall
jedis.hgetAll("maps");
//hkeys
jedis.hkeys("maps");
//hvals
jedis.hvals("maps");
//....
}
SpringBoot 操作数据 :spring-data jpa jdbc mongodb redis !
SpringData 也是和 SpringBoot 齐名的项目!
说明:在SpringBoot2.x之后,原来使用的jedis被替换为了 lettuce
jedis:采用的直连,多个线程操作的时候是不安全的,如果为了避免不安全,使用jedis pool 连接池! BIO(阻塞的)
lettuce:采用netty,高性能的网络框架,以异步请求,实例可以在多个线程中进行共享,不存在线程不安全的情况!dubbo的底层也是它,可以减少线程数据量,更像NIO模式。(IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO)
源码分析:
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
// 因为这个是不存在才生效,所以我们可以自己定义一个redisTemplate来替换这个默认的!
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
// 默认的 RedisTemplate 没有过多的设置,redis对象都是需要序列化!例如:Dubbo也是需要序列化
// 两个泛型都是 Object,object 的类型,我们后面使用需要强制转换
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean // 由于 String 是redis中最常使用的类型,所以单独提出来一个bean!
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
整合测试
在实际企业工作中,所有的实体类entity都要序列化,即实现 implements Serializable 接口。
不然以类,或者说对象方式存进redis会报错。
使用opsForValue().set() 采用的序列化是 jdk 的序列化方式,即jdk内部封装有了。
如果想要使用其他的序列化方式就要使用自己的config类,自己编写。
企业中还自己封装redisUtils,将我们对redis的一些繁琐代码整合成自己的方法,使调用使用更简单!!!
redisUtil和reidsTemplate要自己写,否则以默认jdk序列化方式序列化数据情况下,中文和对象是不可存储的
启动的时候,就通过配置文件来启动!
行家一出手,就知有没有
单位
1、配置文件 unit单位 对大小写不敏感!
包含
就是好比我们springboot一样,可以有多个config配置文件,把其他配置文件加载过来这样子。
网络
如果开远程访问的话,一般这个
bind 127.0.0.1
是直接注释掉,或者可以换成指定ip,或者直接换0.0.0.0
protected-mode yes #保护模式 远程连接可能需要改成 no
port 6379 #端口号 最好改端口,不然有可能别人会那你主机挖矿
通用 GENERAL
daemonize yes # 以守护进程的方式后台运行,默认是 no,我们要改成yes,不然一退出,redis就停止了。使用docker启动的需要改为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 # notice 生产环境适用
logfile "" # 日志的文件位置名 ,如果为空就是一个默认的输出了,就不管他
databases 16 #默认16个数据库
always-show-logo yes #是否总是显示logo,就开启redis会有那个图
快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到 .rdb .aof文件 (redis 是一个内存数据库,不持久化待会就断电即失了)
# 如果900s内,如果至少有 1个 key进行了修改,我们就进行持久化操作。
save 900 1
# 如果300s内,如果至少有 10个 key进行了修改,我们就进行持久化操作。
save 300 10
# 如果60s内,如果至少有 10000个 key进行了修改,我们就进行持久化操作。
save 60 10000
# 我们之后学习持久化,会自己定义这个测试!
stop-writes-on-bgsave-error yes # 当bgsave快照操作出错时停止写数据到磁盘
rdbcompression yes # 是否压缩 rdb 文件,需要消耗一些cpu的资源。
rdbchecksum yes # 保存 rdb 文件的时候,进行错误检查校验!
dir ./ # rdb 文件保存的目录!
REPLICATION 复制,我们后面讲解主从复制的时候,会搭建3个redis,到时候再一并讲解。
SECURITY 安全
redis默认没有密码,可以自己去设置。
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
# 查看密码可以看得是空的
# 云服务器一定要设置密码
# 通过命令设置密码,这种设置方式是临时的,当服务器重启后,密码会失效。即:
config set requirepass "你的密码" # 注意密码不要设太简单,会被挖矿
# 正确设置密码的方式是在conf配置文件中去配置
# 1.配置文件中有一行是这样的
# requirepass foobared
# 去掉注释,并且把foobared改为自己的密码
# 2.如果你在配置文件设置密码,但启动后仍旧无效,是因为你没有知# 道配置文件运行。服务端也会报出如下警告:
Warning:no config file specified,using the default config.
linux下正确的启动的方式:
切换到redis的根目录,运行如下命令
用下面的那个吧,上面这个正本就不动了,动副本。
# redis-server /usr/local/redis/redis-6.0.5/redis.conf
redis-server /usr/local/bin/kconfig/redis.conf
在指定了配置文件后,再启动就可以读取到设置的密码了。
# 搞定后以后要进入redis-cli 客户端就要输入密码
auth 123456 # 注意,真实去玩密码不要设这么简单
限制 CLIENTS (最大客户端数)
maxclients 10000 # 设置能连接上redis的最大客户端的数量
maxmemory <bytes> # redis 配置最大的内存容量 ,默认是字节,不用管
maxmemory-policy noeviction #内存到达上限之后的处理策略
# 移除一些过期的key
# 报错
# 。。。一系列操作。
8种策略
1)noeviction(默认策略)
内存使用达到阈值,所有引起申请内存的命令(写请求)都报错;也就是说不做任何处理,直接报错。除了DEL请求和部分特殊请求。
(2)allkeys-lru
优先移除最近未使用key,直到腾出可用空间。
适用:当应用对缓存的访问,符合幂律分布(也就说存在相对热点数据),或者不清楚应用的缓存访问分布状态。
(3)allkeys-lfu
优先移除LFU key,直到腾出可用空间。
(4)volatile-lru
设置了过期时间的键空间,优先移除最近未使用key。
如果无可删除键,且内存不够用,就会报错。
适用:把redis实例既用于缓存,又用于持久化存储。
(5)volatile-lfu
设置了过期时间的键空间,优先移除LFU key,直到腾出可用空间。
如果无可删除键,且内存不够用,就会报错。
(6)allkeys-random
主键空间中,随机移除某个key。
适用:应用对于缓存key的访问,概率差不多。
(7)volatile-random
设置了过期时间的键空间,随机移除某个key,直到腾出可用空间。
如果无可删除键,且内存不够用,就会报错。
适用:把redis实例既用于缓存,又用于持久化存储。
(8)volatile-ttl
设置了过期时间的键空间,优先移除最近过期时间的key。
如果没有就直接报错。
volatile-lru、volatile-random、volatile-ttl这三种策略,没有key淘汰时,跟noeviction一样返回错误。
APPEND ONLY 模式 aof 配置
在配置文件差不多56%处。
appendonly no # 默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分情况下,rdb完全够用!
appendfilename "appendonly.aof" #持久化的文件的名字
# appendfsync always # 每次修改都会sync 同步,消耗性能。
appendfsync everysec # 每秒执行一次 sync 同步,可能会丢失这1s的数据!
# appendfsync no # 不执行 sync 同步,这个时候操作系统自己同步数据,这个时候速度最快!
aof记录的是命令数据,rdb存储的是特有的数据格式。
俩种存储形式都使用情况下,AOF会优先于RDB
面试和工作,持久化都是重点!
Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以Redis提供了持久化功能!
什么是RDB
在主从复制中,rdb就是备用的!从机上面!
在指定的时间间隔将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上传持久化好的文件。整个过程中,主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。我们默认的就是RDB,一般情况下不需要修改这个配置!
有时候在生产环境我们会将这个文件进行备份!
rdb保存的文件是 dump.rdb 都是在我们的配置文件的快照中进行配置的!
save 触发机制
1、save的规则满足的情况下,会自动触发rdb规则!
2、执行flushall命令,也会触发我们的rdb规则!(flushall触发创建的文件是空的,没有意义)
3、退出redis,也会产生rdb文件!
备份就自动生成一个 dump.rdb(dump没有生成的,要注意,redis在哪个路径下启动的dump文件就会在个路径下生成;dump.rdb放在redis-server同级目录)
如何恢复rdb文件!
Redis启动时会自动扫描rdb文件
1、只需要将rdb文件放在我们redis启动目录就可以了,redis启动的时候会自动检查dump.rdb 恢复其中的数据!
2、查看需要存在的位置!
127.0.0.1:6379> config get dir
1) "dir"
2) "/"
几乎就它自己默认的配置就够用了,但是我们还是需要去学习!
优点:
1、适合大规模的数据恢复!
2、对数据的完整性要求不高!
缺点:
1、需要一定的时间间隔进程操作!如果redis意外宕机了,这个最后一次修改的数据就没有了!
2、fork进程的时候,会占用一定的内存空间!
将我们的所有命令都记录下来,history,恢复的时候就把这个文件全部执行一遍!
是什么!
以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
那如果是大数据的情况下,重新加载一次就很耗时间了
AOF保存的是appendonly.aof文件
append
默认aof形式持久化是不开启的,要的话需要手动进行配置,然后重启,redis就可以生效了。
如果aof有错位,这时候redis是启动不起来的,就是服务端server可以启动,但是cli客户端是链接不上去的。这个时候,我们就要修复这个aof文件!
redis给我们提供了一个工具 redis-check-aof --fix “aof文件名” (出错的命令会被删除)
修好了文件正常后,重启redis就可以恢复了。
AOF 重写
由于AOF持久化是Redis不断将写命令记录到 AOF 文件中,随着Redis不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令 bgrewriteaof 来重新。被破坏的文件破坏点之后的指令在下一次启动时都不会被执行了,aof文件里面也没有了
其他详解:https://blog.csdn.net/qq_45800640/article/details/119189270
aof默认就是文件的无限追加,文件会越来越大!
如果aof文件大于64m,太大了!fork一个新的进程新开个临时文件来将我们的文件进行重写!
优点和缺点!
appendonly no # 默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分情况下,rdb完全够用!
appendfilename "appendonly.aof" #持久化的文件的名字
# appendfsync always # 每次修改都会sync 同步,消耗性能。
appendfsync everysec # 每秒执行一次 sync 同步,可能会丢失这1s的数据!
# appendfsync no # 不执行 sync 同步,这个时候操作系统自己同步数据,这个时候速度最快!
优点:
1、每一次修改都同步,文件完整性会更加好!
2、每秒同步一次,可能会丢失一秒的数据
3、从不同步,效率是最高的
缺点:
1、相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢!
2、Aof运行效率也要比rdb慢,所有我们redis默认的配置就是rdb持久化!
两种持久化方案既可以同时使用(aof),又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定。
无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)。
企业一般也有俩种混合着用,就是都用!
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。微信、微博、关注系统!
Redis 客户端可以订阅任意数量的频道。
订阅/发布消息图:
https://blog.csdn.net/w15558056319/article/details/121490953
应用场景:
1、实时消息系统!
2、聊天室系统!
3、订阅,关注系统!
稍微复杂的场景我们就会使用 消息中间件 MQ
概念:什么是Redis主从复制?
主从复制就是将主节点(master)redis的数据同步到其他从节点(slave)redis数据库上。
为什么需要Redis主从复制?
单机状态有两个问题:
1、服务器宕机,直接导致数据丢失。
2、内存问题,一台服务器的内存肯定会到达峰值,不可能对一台服务器进行无限升级的。
主从复制可以将数据保存在多个服务器上,并且保证每个服务器的数据是同步的。即使有一个服务器宕机了,也不会影响用户的使用。redis可以继续实现高可用、同时实现数据的冗余备份。
Redis主从复制的作用
1、数据冗余:实现了数据的热备份,是持久化之外的另一种方式。
2、故障恢复:当主节点(master)出现问题时,可以由从节点(slave)来提供服务,实现了快速恢复故障,也就是服务冗余。
3、读写分离:master服务器主要是写,slave主要用来读数据,可以提高服务器的负载能力。同时可以根据需求的变化,添加从节点的数量。
4、负载均衡:配合读写分离,有主节点提供写服务,从节点提供读服务,分担服务器负载,尤其在写少读多的情况下,通过多个从节点分担读负载,可以大大提高redis服务器的并发量和负载。
5、高可用(集群)的基石:主从复制是哨兵和集群能够实施的基础,因此我们可以说主从复制是高可用的基石。
更多详情:https://blog.csdn.net/qq_42410605/article/details/122895891
一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下:
1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
2、从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是"多读少写"。
对于这种场景,我们可以使用如下这种架构:
主从复制,读写分离! 80%的情况下都是在进行读操作!减缓服务器压力!架构中经常使用!一主多从!
只要在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用Redis!
只配置从库,不用配置主库!
127.0.0.1:6379> info replication # 查看当前库的信息 单纯info是查看所有信息
# Replication
role:master # 角色 master
connected_slaves:0 # 没有从机
master_replid:4945e4f6497358d36ba173de686b52b18d65765c
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 配置文件,然后修改对应信息:
1、端口
2、pid 名字
3、log文件 名字
4、dump.rdb 名字 如果有开启了aof,aof也要改
修改完毕之后,根据对应名字 启动对应3个redis服务器,可以通过进程信息查看!如下:
默认情况下,每台Redis服务器都是主节点; 我们一般情况下只用配置从机就好了!
认老大!一主(79)二从(80,81)
通过命令修改的都只有本次有效,重启就失效
真正要做就得在conf里配,如下:
将地址和ip换好,然后之后启动之后你这个redis默认就是一个从机!
细节
主机可以写,从机不能写只能读!主机中的所有信息和数据,都会自动被从机保存!
从机只能读取内容!
主机如果断开:从机还能继续使用,因为是原先复制过来的,所有原先插进去的值就还是可以查的到。但是它的角色不会换回来,还是slave(从机)。因为我们没有使用哨兵模式!所以后续还需搭配哨兵模式使用!然后如果主机如果重新上线了,从机就又可以拿到主机新写的信息继续工作了。
正常思想下:主机断了,从机应该从剩下的几个从机中选举出一个作为主机,而不是干干的等着。
然后另一种情况是 从机断了:
如果是使用命令行,来配置的主从,这个时候如果从机shutdown之后重启了,就会变回主机,那就拿不到原先主机在这个从机断开期间插入的所有新值,这个已经变回主机的从机只有原先还是从机时保留下来的那些东西。数据是单向的,然后只要再变回从机,立马就会从从机中获取值,把主机的东西又拿过来了。
复制原理
Slave 启动成功连接到 master 后会发送一个sync同步命令!
Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步!
但是只要是重新连接master,一次完全同步(全量复制)将自动执行!我们的数据一定可以在从机中看到!
层层链路
这时候也可以完成我们的主从复制!
但是实际上上面俩个我们实际工作中都不使用!
如果没有老大了,这个时候能不能选择一个老大出来呢?哨兵模式没出之前:手动!
谋朝篡位
如果主机断开了连接,我们可以使用 slaveof no one 让自己变成主机!其他的节点就可以手动连接到最新的这个主节点(手动)!如果这个时候老大修复了,那就只能重新连接将刚刚那个变成老大那个又让出去,变成小弟,不然就算你回来了,你就只是自己一个主机,下面没有任何slave。
(自动选举老大的模式)
概述
主从切换技术:当主机宕机后,需要手动把一台从(slave)服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用,所以推荐哨兵架构(Sentinel)来解决这个问题。Redis从2.8开始正式提供了Sentinel( 哨兵 )架构来解决这个问题。
谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵模式的作用:
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器;
当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机;
然而一个哨兵进程对Redis服务器进行监控,也可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
故障切换的过程:
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行 failover 过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行 failover 操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。
测试
我们目前的状态的一主二从。
1、配置哨兵配置文件 sentinel.conf
# sentinel monitor 被监控的名称 host port 1
sentinel monitor myredis 127.0.0.1 6379 1
后面的这个数字1,代表主机挂了,slave投票看让谁接替成为主机,票数最多的,就会成为主机!
2、启动哨兵
redis-sentinel kconfig/sentinel.conf # 后面这个conf文件就算步骤1时创建的,然后命令行回车跑起来就可以了
如果Master节点断开了(这里面有一个投票算法)
后面如果主机又回来了,它就变成了一个光杆司令,刚开始是主机,过一会被哨兵检测到了,就会自动归并到新的主机下,变成从机。
哨兵模式
优点:
1、哨兵集群,基于主从复制模式,所有的主从配置优点,它全有
2、主从可以切换,故障可以转移,系统的可用性更好
3、哨兵模式就算主从模式的升级,手动到自动,更加健壮!
缺点:
1、Redis 不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦!
2、实现哨兵模式的配置其实是很麻烦的,里面又很多选择!(上面只是做了一个最简单的配置,而且仅监视一个主机)
哨兵模式的全部配置!
# Example sentinel.conf
# 哨兵sentinel实例运行的端口 默认26379 如果有哨兵集群,我们还需要配置每个 哨兵端口
port 26379
# 哨兵sentinel的工作目录
dir /tmp
# 哨兵sentinel监控的redis主节点的 ip port
# master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。
# quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor
sentinel monitor mymaster 127.0.0.1 6379 2
# 2是指其中有2个哨兵投票某个slave,就将它选为master
# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码
# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码
# sentinel auth-pass
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒
# sentinel down-after-milliseconds
sentinel down-after-milliseconds mymaster 30000
# 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。
# sentinel parallel-syncs
sentinel parallel-syncs mymaster 1
# 故障转移的超时时间 failover-timeout 可以用在以下这些方面:
#1. 同一个sentinel对同一个master两次failover之间的间隔时间。
#2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
#3.当想要取消一个正在进行的failover所需要的时间。
#4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了
# 默认三分钟
# sentinel failover-timeout
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECUTION
#配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。
#对于脚本的运行结果有以下规则:
#若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10
#若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
#如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
#一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
#通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数,一个是事件的类型,一个是事件的描述。如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
#通知脚本
# shell编程
# sentinel notification-script
sentinel notification-script mymaster /var/redis/notify.sh
# 客户端重新配置主节点参数脚本
# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。
# 以下参数将会在调用脚本时传给脚本:
#
# 目前总是“failover”,
# 是“leader”或者“observer”中的一个。
# 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 一般都是由运维来配置!
服务的高可用问题!
什么是缓存穿透
缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中,请求都会压到数据库,从而压垮数据库。比如用户一个不存在的用户id获取用户信息。
在日常工作中出于容错的考虑,如果从持久层(数据库)查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层(数据库)去查询,失去了缓存保护后端持久的意义。例如:秒杀系统这种,就很容易宕!
解决方案
一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
下面有3种方法可以有效地解决缓存穿透问题
1、对空值缓存:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
2、设置可访问的白名单:使用bitmaps;类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmaps里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问
布隆过滤器
3、采用布隆过滤器:布隆过滤器(Bloom Filter)是由Howard Bloom在1970年提出的一种比较巧妙的概率型数据结构,它可以告诉你某种东西一定不存在或者可能存在。当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。 布隆过滤器相对于Set、Map 等数据结构来说,它可以更高效地插入和查询,并且占用空间更少,它也有缺点,就是判断某种东西是否存在时,可能会被误判。但是只要参数设置的合理,它的精确度也可以控制的相对精确,只会有小小的误判概率。
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
这里重点讲一下布隆过滤器
了解布隆过滤器的用途,下面有必须要把它的原理解释一下,不然有些读者还会继续蒙在鼓里。
向布隆过滤器中添加key时,会使用多个hash函数对key进行hash,算得一个整数索引值,然后对位数组进行取模运算得到一个位置,每个hash函数都会算得一个不同的位置。在把位数组的这几个位置都置为1
向布隆过滤器询问key是否存在时,也会把hash的几个位置都算出来,看看位数组中这几个位置是否都为1,只要有一个位为0,那么说明布隆过滤器中这个key不存在。如果这几个位置都是1,并不能说明这个key就一定存在,只是极有可能存在,因为这些位被置为1可能是因为其他的key存在所致。如果这个位数组比较稀疏,判断正确的概率就会很大,如果这个位数组比较拥挤,判断正确的概率就会降低。
对于1、3方法空值存储会存在两个问题:
1、如果空值能够被存储起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键!
2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响!(例如缓存层里的是空值,而数据库原先没有,而现在有了,这就有了不一致的出现了)
什么是缓存击穿
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),当一个key非常热门,并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,并且回写缓存,引起数据库压力瞬间增大,造成过大压力(有点像一把尖刀瞬间击穿到数据库)
解决方法
设置热点数据永不过期:从缓存层面看,没有设置过期事件,就不会出现热点key过期后产生的问题。
预先设置热门数据:在redis高峰访问前,把一些热门数据提前存入redis中,加大这些热门数据key的时长实时调整 现场监控哪些数据是热门数据,实时调整key的过期时长。
使用分布式锁: 就是在缓存失效的时候(判断拿出来的值为空),不是立即去查数据库,先使用缓存工具的某些带成功操作返回值的操作。比如redis的setnx去set一个mutex key,当操作返回成功时(分布式锁),在查数据库,并回设缓存,最后删除mutex key
当操作返回失败,证明有线程在查询数据库,当前线程睡眠一段时间在重试整个get缓存的方法
就是保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大
什么是缓存雪崩?
缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。(生活理解:比如马上就要双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时,那么到了凌晨一点钟的时候,这批商品缓存就都过期了,而对这批商品的访问查询,就都落在了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层(数据库),存储层(数据库)的调用量就会暴增,造成存储层(数据库)也会挂掉的情况)
常见缓存雪崩出现原因:1、redis服务器挂掉了。2、对缓存数据设置了相同的过期时间,导致某时间段内缓存集中失效。
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某哥节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段中集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
双十一:停掉一些服务,(保证主要的服务可用!)也就是服务降级。
解决方案
redis高可用
这个思想的含义就是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)
限流降级(限流或者降级(在SpringCloud讲解过(服务降级)))
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据预热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的 时间点尽量均匀。
用Jedis连接阿里云等服务器上的redis
一. 配置redis.conf
1.设置访问redis的密码:requirepass 要设置密码
2.注释bind 127.0.0.1
(重启redis-server服务,进入redis后要先验证密码,用这个命令:auth 密码 ,然后ping一下看有没有配置成功)
二 . idea访问时添加auth密码
Jedis jedis = new Jedis(“服务器的外网ip”,6379);
jedis.auth(“redis的密码”);
System.out.println(jedis.ping());
(输出PONG的话就成功了)
首先要开启安全组策略6379!!!!!!!!!
然后bind注释掉所有!!!!!!!
受保护的也设置为no!!!!!
防护墙也要关掉!!!!
且要重启才能生效!!!