Redis学习笔记
Redis简介与安装Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,默认占用6379端口号。redis特点:数据间没有必然的关联关系内部采用单线程机制进行工作高性能。官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,
Redis简介与安装
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,默认占用6379
端口号。
redis特点:
- 数据间没有必然的关联关系
- 内部采用单线程机制进行工作
- 高性能。官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s
- 多数据类型支持
- 持久化支持。可以进行数据灾难恢复
redis应用:
- 为热点数据加速查询(zset商品ID和销量)
- 任务队列,例如秒杀、抢购、购票排队
- 即时信息查询,例如排行榜,公交到站信息,在线人数等
- 时效性信息控制,如验证码控制,投票控制
- 验证码等具有时效性的操作
- 分布式缓存
- 分布式数据共享,如分布式集群架构中session分离
- 存储token信息
- 消息队列
- 分布式锁
redis安装与启动:
菜鸟教程写的很详细了, 大家看一下就好了https://www.runoob.com/redis/redis-install.html
可视化客户端:
- Another-Redis-Desktop-Manager
- Redis Desktop Manager,下载地址:http://www.downza.cn/soft/210734.html
Redis基本操作
操作 | 功能 | 备注 |
---|---|---|
set name zrl | 添加数据 | 重复set会更新原数值,和map操作一样 |
get name | 查询数据 | 查询不到会返回nil |
clear | 清空屏幕 | |
help get | 获取单个命令帮助文档 | |
help @string | 获取群组命令帮助文档 | 显示操作这种数据的所有函数 |
quit | 退出 | |
exit | 退出 | |
<ESC> | 退出 |
数据存储类型
string
简单介绍
- 数据类型指的是value的类型
- 放字符串类型的数字最大值是LONG类型的最大值9223372036854775807
- 解决MySQL分库分表主键可能重复的问题,我们可以使用redis进行控制
key设置的约定
# user是表名,id是主键名,201931是主键值,fans是字段名,122109是字段的值
set user:id:201931:fans 122109
常用操作
操作 | 功能 | 备注 |
---|---|---|
set key value | 添加/修改数据 | 重复set会更新原数值,和map操作一样 |
get key | 查询数据 | 查询不到会返回nil |
del key | 删除数据 | |
mset key1 value1 key2 value2 … | 添加/修改多个数据 | |
mget key1 key2 … | 获取多个数据 | |
strlen key | 获取数据字符串长度 | |
append key value | 追加信息到原始信息尾部 | 如果原始信息不存在就创建 |
incr key | 字符串的value加1 | |
incrby key increment | 字符串加指定的整数 | |
incrbyfloat key increment | 字符串加指定的浮点数 | |
decr key | 字符串的value减1 | |
decrby key increment | 字符串减去指定的整数 | 减去没有浮点数的操作 |
setex key seconds value | 设置数据的生命周期 | 以秒为单位 |
psetex key milliseconds value | 设置数据的生命周期 | 以毫秒为单位 |
set user:id :201931 {id:201931,name:春晚,fans:1000,blogs:111} | 使用json格式存储数据 | 拿数据很方便,但是改数据就很麻烦了 |
hash
简单介绍
以前是一个数据对应一个数据,现在是一个数据对应一堆数据,即一个存储空间对应一堆数据,可以理解为redis里面的redis
hash类型底层使用哈希表结构实现数据存储,hash存储优化与两条路:
- 如果field数量少,存储结构优化为数据结构
- 如果filed数量较多,存储结构使用HashMap结构
hash类型数据操作的注意事项:
- hash类型下的vaule只能为字符串,别想着搞什么嵌套之类的。如果数据未获取到则对应值为nil
- 每个hash可以存储2的32次方-1个键值对
- hash类型贴近对象的数据存储形式,并且十分灵活,但是不要滥用,这不是hash设计的初衷,更不要将hash作为对象列表使用
- hgetall操作可以获取全部属性,但是如果内部dield过多,遍历整体数据效率就会很低,数据少的话就用hget好了
常用操作
操作 | 功能 | 备注 |
---|---|---|
hset key field value | 添加/修改数据 | |
hget key field | 获取单个数据 | |
hagetall key | 获取全部数据 | |
hdel key field1,field2 | 删除数据 | |
hmset key field1 value1 field2 value2 … | 添加/修改多个数据 | |
hmget key field1 field2 … | 获取多个数据 | |
hlen key | 获取哈希表中字段数量 | |
hexists key field | 获取哈希表是否存在指定字段 | |
hkeys key | 获取所有字段名 | |
hvals key | 获取所有字段值 | |
hincrby key field increment | 设置指定字段的数值数据增加指定范围的整数 | |
hincrbyfloat key field increment | 设置指定字段的数值数据增加指定范围的浮点数 | |
hdecr key | 设置指定字段的数值数据减1 | |
hincrbyfloat key field increment | 设置指定字段的数值数据减少指定范围的整数 |
简单示范
hset user name zhangsan
hset user age 38
hgetall user
hget user name
hdel user weight
gget all user
list
简单介绍
- 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
- 需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
- list中保存的数据都是string类型,数据总容量有限,最多2的32次-1个元素(4294967295)
- list具有索引的概念,但是操作数据通常以队列的形式进行入队出队操作,或者以栈的形式进行入栈出栈操作
- 获取全部数据操作结束索引设置为-1
- list可以对数据进行分页操作,通常第一页信息来自list,第二页以及更多信息通过数据库加载
常用操作
操作 | 功能 | 备注 |
---|---|---|
lpush key value1 value2 … | 添加/修改数据 | 从左端放,key是list的名称 |
rpush key value1 value2 … | 添加/修改数据 | 从右端放 |
lrange key start stop | 获取某个区间的元素 | 区间左右都是闭区间,-1是最后一个元素的索引 |
lindex key index | 获取某个元素 | |
llen key | 获取元素个数 | |
lpop key | 获取并移除数据 | 从左端删除 |
rpop key | 获取并移除数据 | 从右端删除 |
blpop key1 key2 … timeout | 等待规定时间并移除数据 | 从左端删除 |
blpop key1 key2 … timeout | 等待规定时间并移除数据 | 从右端删除 |
lrem key count value | 移除指定指定个数的指定数据 | count是你移除几个元素,从左开始数 |
set
简单介绍
set的实现形式,使用哈希表,只不过我们将key作为set的value,value改为nil
- 新的存储需求:存储大量的数据,在查询方面提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
- set 类型不允许数据重复,如果添加的数据在set中已经存在,将只保留一份
- set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
常用操作
操作 | 功能 | 备注 |
---|---|---|
sadd key value1 value2 … | 添加元素 | key是set的名称 |
smembers key | 获取全部数据 | |
srem key member1 member2 … | 删除数据 | |
soard key | 获取集合数据总量 | |
sismember key member | 判断集合中是否包含指定元素 | |
sinter key1 key2 | 求两个集合的交集 | |
sunion key1 key2 | 求两个集合的并集 | |
sdiff key1 key2 | 求两个集合的补集 | |
sinterstore destination key1 key2 | 求两个集合的交、并、补集并存储到指定集合中 | destination是存储的集合 |
sunionstore destination key1 key2 | 求两个集合的交、并、补集并存储到指定集合中 | |
sdiffstore destination key1 key2 | 求两个集合的交、并、补集并存储到指定集合中 | |
smove source desyination member # destination是目标集合 | 将指定数据从原始集合移动到目标集合中 | |
srandmember key count | 随机获取集合中指定数量的数据 | |
spop key member | 随机获取集合中某个数据并将该数据移出 |
sorted_set
简单介绍
score是排序规则
- 新的存储需求:数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
- 需要的存储结构:新的存储模型,可以保存可排序的数据
- sorted set类型:在set的存储结构基础上添加可排序字段
- score保存的数据存储空间是64位,如果是整数范围是9007199254740992~9007199254740992
- score保存的数据也可以是一个双精度的double值,基于双精度浮点数的特征,可能会丢失精度,使用时候要慎重
- sorted_set底层存储还是基于set结构的,因此数据不能重复,如果重复添加相同的数据,score值将被反复覆盖,保留最后一次修改的结果
常用操作
操作 | 功能 | 备注 |
---|---|---|
zadd key score1 member1 score2 member2 … | 添加数据 | |
zrange key start stop [withscores] | 获取全部数据,升序 | 加上withscores会把对应的scores也打印出来 |
zreverrange key start stop | 获取全部数据,降序 | |
zrem key member1 member2 … | 删除数据 | |
zrangebyscore key min max [limit index count] withscores | 查询指定范围数据,升序 | limlt后面第一个参数是起始的index,从0开始,count是返回的条数 |
zrevrangebyscore key max min [limit index count] withscores | 查询指定范围数据,降序 | |
zremrangebyrank key start stop | 删除指定范围数据 | 根据索引 |
zremrangebyscore key min max | 删除指定范围数据 | 根据数值 |
zcard key | 获取集合数据总个数 | |
zcount key min max | 获取指定范围数据个数 | |
zinterstore destination numkeys key1 key2 … | 集合求交集 | numkeys是后面有几个集合,返回的数据是对应求和之后的数据 |
zinterstore destination numkeys key1 key2 … [aggregate max] | 集合求交集 | 交后返回的数据是最大值 |
zunionstore destination numkeys key1 key2 … | 集合求并集 | |
zrank key memebr | 获取数据对应的索引 | 即获取排名,升序 |
zrevrank key member | 获取数据对应的索引 | 即获取排名,降序 |
zscore key member | 获取对应的score值 | |
zincrbt key increment member | score递增指定数值 | |
time | 获取时间 | 第一个数值是时间戳小数点前面的数值,第二个是小数点后面的 |
通用命令
key通用命令
key是一个字符串,通过key获取redis中保存的数据
操作 | 功能 | 备注 |
---|---|---|
del key | 删除指定key | |
exists key | 获取key是否存在 | |
type key | 获取key的类型 | |
expire key seconds | 为指定key设置有效期 | |
pexpire key milliseconds | 为指定key设置有效期 | 毫秒 |
expireat key timestamp | 为指定key设置有效期 | Linux一般用这个时间戳 |
pexpireat key milliseconds-timestamp | 为指定key设置有效期 | |
ttl key | 获取key的有效时间 | 如果key时间已经消失了返回-2,如果这个key不存在返回-1 |
pttl key | 获取key的有效时间 | |
persist key | 切换key时效性为永久性 | 成功返回1,不存在(失败)返回0 |
rename key newkey | 为key改名 | 新名字已经存在就覆盖 |
renamenx key newkey | 为key改名 | 新名字如果存在就失败返回0 |
keys n[adw]me | 查询key | *匹配任意数量符号,?匹配任意一个符号,[]匹配包含其中指定的任意一个符号 |
sort key | 对所有key排序 | 不影响原数据,升序加上desc,还能分页啥的可以自己再看看 |
help @generic | 其他key通用操作 |
数据库通用命令
简单介绍
为了解决key重复的问题,redis为每个服务提供有16个数据库,编号从0到15,每个数据库之间的数据相互独立,但是用的是同一块内存空间
常用操作
操作 | 功能 | 备注 |
---|---|---|
select index | 切换数据库 | |
quit | 退出客户端 | |
ping | 查看是否连通上 | |
echo message | 输出message | |
move key dbindex | 数据剪切 | |
flushdb | 删除当前数据库的数据 | |
flushall | 删除全部数据库数据 | |
dbsize | 查看数据总量 |
jedis
简单操作
jedis是Java操作redis的类,jedis的操作与redis完全相同
jar包下载地址:https://mvnrepository.com/artifact/redis.clients/jedis
maven项目依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.1</version>
</dependency>
创建一个maven项目简单测试一下
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class JedisTest {
@Test
punlic void testJedis(){
//1、连接redis
Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.select(0);//选择库
//2、操作redis
jedis.set("name","lzxyy");
//3、关闭redis
jedis.close();
}
}
编写一个jedis工具类
编写配置文件redis.properties
redis.host=127.0.0.1
redis.port=6379
redis.maxTotal=30#最大连接数
redis.maxIdle=10#活跃数
Java工具类
public class JedisUtils {
private static JedisPool jp = null;//创建连接池
private static String host = null;//连接ip
private static int port = null;//连接端口号
private static int maxTotal = null;//最大连接数
private static int maxIdle = null;//最大
static {//静态代码块使得只调用一次就ok了
ResourceBundle rb = ResourceBundle.getBundle("redis");
host = rb.getString("redis.host");
prot = Integer.parseInt(rb.getString("redis.port"));
maxTotal = Integer.parseInt(rb.getString("redis.maxTotal"));
maxIdle = Integer.parseInt(rb.getString("redis.maxIdle"));
JedisPoolConfig jpc = new JedisPoolConfig();
jpc.setMaxTotal(maxTotal);
jpc.setmaxIdle(maxIdle);
jp = new JedisPool(jpc,host,port);
}
public static Jedis getJedis() {
return jp.getResource;
}
}
可视化客户端
常用命令
1.对value操作的命令
exists(key):确认一个key是否存在
del(key):删除一个key
type(key):返回值的类型
keys(pattern):返回满足给定pattern的所有key
randomkey:随机返回key空间的一个key
rename(oldname, newname):将key由oldname重命名为newname,若newname存在则删除newname表示的key
dbsize:返回当前数据库中key的数目
expire:设定一个key的活动时间(s)
ttl:获得一个key的活动时间
select(index):按索引查询
move(key, dbindex):将当前数据库中的key转移到有dbindex索引的数据库
flushdb:删除当前选择数据库中的所有key
flushall:删除所有数据库中的所有key
2.对String操作的命令
set(key, value):给数据库中名称为key的string赋予值value
get(key):返回数据库中名称为key的string的value
getset(key, value):给名称为key的string赋予上一次的value
mget(key1, key2,…, key N):返回库中多个string(它们的名称为key1,key2…)的value
setnx(key, value):如果不存在名称为key的string,则向库中添加string,名称为key,值为value
setex(key, time, value):向库中添加string(名称为key,值为value)同时,设定过期时间time
mset(key1, value1, key2, value2,…key N, value N):同时给多个string赋值,名称为key i的string赋值value i
msetnx(key1, value1, key2, value2,…key N, value N):如果所有名称为key i的string都不存在,则向库中添加string,名称key i赋值为value i
incr(key):名称为key的string增1操作
incrby(key, integer):名称为key的string增加integer
decr(key):名称为key的string减1操作
decrby(key, integer):名称为key的string减少integer
append(key, value):名称为key的string的值附加value
substr(key, start, end):返回名称为key的string的value的子串
3.对List操作的命令
rpush(key, value):在名称为key的list尾添加一个值为value的元素
lpush(key, value):在名称为key的list头添加一个值为value的 元素
llen(key):返回名称为key的list的长度
lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)
ltrim(key, start, end):截取名称为key的list,保留start至end之间的元素
lindex(key, index):返回名称为key的list中index位置的元素
lset(key, index, value):给名称为key的list中index位置的元素赋值为value
lrem(key, count, value):删除count个名称为key的list中值为value的元素。count为0,删除所有值为value的元素,count>0 从头至尾删除count个值为value的元素,count<0从尾到头删除|count|个值为value的元素。
lpop(key):返回并删除名称为key的list中的首元素
rpop(key):返回并删除名称为key的list中的尾元素
blpop(key1, key2,… key N, timeout):lpop 命令的block版本。即当timeout为0时,若遇到名称为key i的list不存在或该list为空,则命令结束。如果 timeout>0,则遇到上述情况时,等待timeout秒,如果问题没有解决,则对key i+1开始的list执行pop操作。
brpop(key1, key2,… key N, timeout):rpop的block版本。参考上一命令。
rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部
4.对Set操作的命令
sadd(key, member):向名称为key的set中添加元素member
srem(key, member) :删除名称为key的set中的元素member
spop(key) :随机返回并删除名称为key的set中一个元素
smove(srckey, dstkey, member) :将member元素从名称为srckey的集合移到名称为dstkey的集合
scard(key) :返回名称为key的set的基数
sismember(key, member) :测试member是否是名称为key的set的元素
sinter(key1, key2,…key N) :求交集
sinterstore(dstkey, key1, key2,…key N) :求交集并将交集保存到dstkey的集合
sunion(key1, key2,…key N) :求并集
sunionstore(dstkey, key1, key2,…key N) :求并集并将并集保存到dstkey的集合
sdiff(key1, key2,…key N) :求差集
sdiffstore(dstkey, key1, key2,…key N) :求差集并将差集保存到dstkey的集合
smembers(key) :返回名称为key的set的所有元素
srandmember(key) :随机返回名称为key的set的一个元素
5.对zset(sorted set)操作的命令
zadd(key, score, member):向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新该元素的顺序。
zrem(key, member) :删除名称为key的zset中的元素member
zincrby(key, increment, member) :如果在名称为key的zset中已经存在元素member,则该元素的score增加increment;否则向集合中添加该元素,其score的值为increment
zrank(key, member) :返回名称为key的zset(元素已按score从小到大排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
zrevrank(key, member) :返回名称为key的zset(元素已按score从大到小排序)中member元素的rank(即index,从0开始),若没有member元素,返回“nil”
zrange(key, start, end):返回名称为key的zset(元素已按score从小到大排序)中的index从start到end的所有元素
zrevrange(key, start, end):返回名称为key的zset(元素已按score从大到小排序)中的index从start到end的所有元素
zrangebyscore(key, min, max):返回名称为key的zset中score >= min且score <= max的所有元素
zcard(key):返回名称为key的zset的基数
zscore(key, element):返回名称为key的zset中元素element的score
zremrangebyrank(key, min, max):删除名称为key的zset中rank >= min且rank <= max的所有元素
zremrangebyscore(key, min, max) :删除名称为key的zset中score >= min且score <= max的所有元素
zunionstore / zinterstore(dstkeyN, key1,…,keyN, WEIGHTS w1,…wN, AGGREGATE SUM|MIN|MAX):对N个zset求并集和交集,并将最后的集合保存在dstkeyN中。对于集合中每一个元素的score,在进行AGGREGATE运算前,都要乘以对于的WEIGHT参数。如果没有提供WEIGHT,默认为1。默认的AGGREGATE是SUM,即结果集合中元素的score是所有集合对应元素进行 SUM运算的值,而MIN和MAX是指,结果集合中元素的score是所有集合对应元素中最小值和最大值。
6.对Hash操作的命令
hset(key, field, value):向名称为key的hash中添加元素field<—>value
hget(key, field):返回名称为key的hash中field对应的value
hmget(key, field1, …,field N):返回名称为key的hash中field i对应的value
hmset(key, field1, value1,…,field N, value N):向名称为key的hash中添加元素field i<—>value i
hincrby(key, field, integer):将名称为key的hash中field的value增加integer
hexists(key, field):名称为key的hash中是否存在键为field的域
hdel(key, field):删除名称为key的hash中键为field的域
hlen(key):返回名称为key的hash中元素个数
hkeys(key):返回名称为key的hash中所有键
hvals(key):返回名称为key的hash中所有键对应的value
hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value
Spring Boot整合redis
引入依赖
提供了RedisTemplate
和StringRedisTemplate
两个操作类,默认是存String,把一个对象放入redis的话使用序列化(所以需要实现Serializable
序列化接口),RedisTemplate的key
和value
都可以是Object,并且在取的时候可以自动反序列化。
StringRedisTemplate
的key
和value
放的都是字符串
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.5.2</version>
</dependency>
添加配置
虽然这些都是默认配置
spring:
redis:
host: localhost
port: 6379
database: 0
StringRedisTemplate测试
@RunWith(SpringRunner.class)
@SpringBootTest
class RedisTest {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void Test() {
//操作String
stringRedisTemplate.opsForValue().set("name","帅帅龙");
System.out.println(stringRedisTemplate.opsForValue().get("name"));
//删除
Boolean name = stringRedisTemplate.delete("name");
//判断是否存在
stringRedisTemplate.hasKey("name");
//判断类型
stringRedisTemplate.type("name");
//设置超时时间
stringRedisTemplate.expire("name", 10, TimeUnit.MINUTES);
stringRedisTemplate.getExpire("name");
//获取所有key
Set<String> keys = stringRedisTemplate.keys("*");
keys.forEach(key -> System.out.println(key));
//重命名
stringRedisTemplate.rename("name","hello");
stringRedisTemplate.renameIfAbsent("name","hello");
//移动key到不同的库
stringRedisTemplate.move("name",1);
}
}
RedisTemplate测试
修改key的序列化策略,让其保持字符串格式
User类:
@Accessors(chain = true)
@Data
public class User implements Serializable {
Integer id;
String username;
String password;
}
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
class RedisTest {
@Autowired
RedisTemplate redisTemplate;
@Test
public void Test() {
User user = new User();
user.setId(1).setUsername("111").setPassword("1111");
//修改key的序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.opsForValue().set("user1",user);
User user1 = (User) redisTemplate.opsForValue().get("user1");
System.out.println(user1);
}
}
绑定对象
不管是RedisTemplate
还是StringRedisTemplate
都提供了bound方法,当我们需要对某个key进行多次操作的时候,可以将一个对象抽离出来直接操作,简化代码
@RunWith(SpringRunner.class)
@SpringBootTest
class RedisTest {
@Autowired
RedisTemplate redisTemplate;
@Test
public void Test() {
//修改key的序列化方式
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//添加数据
redisTemplate.opsForList().leftPush("users","1");
redisTemplate.opsForList().leftPush("users","2");
BoundListOperations users = redisTemplate.boundListOps("users");
users.leftPush("3");
}
}
redis持久化
将redis的内存数据保存到硬盘上的过程,官方提供了两种方式将redis的数据持久化:
-
快照(snapshotting):保存这一时刻的数据状态,
默认开启
,生成以.rdb
结尾的文件 -
AOF(append only file 只追加日志文件)`:将redis的所有写命令追加到日志文件中
快照生成方式
方法一:客户端使用BGSAVE
或SAVE
指令
使用`BGSAVE`命令的时候,会调用`fork`创建一个子进程进行持久化,开始主进程与子进程共享内存,直到主进程或子进程写数据,因此常用
使用`SAVE`命令时,客户端会进入阻塞状态,直到快照完成之后才能响应其他命令,不是很常用
方法二:修改服务器默认配置
如果在`redis.conf`中设置了`save`配置选项,redis会在save选项条件满足之后自动触发一次`BGSAVE`命令,如果设置多个save配置选项,当任意一个满足即可触发`BGSAVE`命令
save 300 1---->表示每5分钟发生一次改变就生成快照
方法三:服务器接收客户端的shutdown命令会自动调用SAVE
命令
配置快照
在redis.conf中修改
-
dbfilename是生成的快照文件名
-
dir是生成的文件的文件夹
快照存在的问题
虽然快照能保存某一时刻的数据,但是当数据发生改变,同时还没到达触发快照生成的条件,这时候如果突然宕机,则会造成数据丢失
开启AOF持久化
在配置文件中设置:appendonly yes
,生成目录在快照目录下
日志追加频率
官方提供了三种同步频率,默认是每秒同步一次,在配置文件中可以进行修改appendfsync
:
- always:每个命令都写一次,不推荐使用,甚至可能会引起写入放大的问题,导致硬盘寿命变短
- everysec:每秒进行一次同步,用户最多丢失一秒的数据
- no:不进行数据同步
AOF存在的问题
持久化文件会越来越大,同时可能存在操作是重复的,这就需要使用AOF重写
来减小AOF文件体积
触发AOF重写
方法一:客户端执行BGREWRITERAOF
命令
客户端执行`BGREWRITERAOF`命令,后台重写,不会阻塞redis服务
方法二:修改配置文件
auto-aof-rewriter-percentage值默认为100
auto-aof-rewrite-size值默认为64mb
当aof达到64MB时会触发一次重写,当下次aof文件达到重写后文件二倍(100%)的时候会再次触发,以此往复
注意:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件,这点和快照有点类似。
主从复制架构(不常用)
主从复制
主从复制仅仅是用来解决数据的冗余备份,主节点对外提供服务,从节点仅仅用来同步数据,不能在主节点出现故障时顶上去对外提供服务,无法做到自动故障转移(哨兵机制解决)。默认不允许执行写操作,可以修改slave-read-only让从节点可以执行写操作,但是不建议,因为没意义
搭建主从复制结构
# 准备3台机器,创建三个目录即可,复制conf文件
- master
port 7000
bind 0.0.0.0 # 开启远程连接
- slave1
port 7001
bind 0.0.0.0 # 开启远程连接
slaveof masterip masterport # 写master的ip和端口号
- slave2
port 7002
bind 0.0.0.0 # 开启远程连接
slaveof masterip masterport
# 使用三个配置文件启动三个redis
redis-server /root/master/redis.conf
哨兵(sentinel)机制
哨兵机制
Sentinel(哨兵)是 Redis的高可用性解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。简单的说哨兵就是带有自动故障转移功能的主从架构。
哨兵架构原理
原master宕机上线后充当从节点的身份,而不是master了
搭建哨兵结构
# 在主节点上创建哨兵配置
在Master对应redis.conf同目录下新建sentinel.conf文件,名字绝对不能错
# 配置哨兵,在 sentinel.conf文件中填入内容,num表示起几个哨兵服务
sentinel monitor 被监控数据库名字(自己起名字) ip port num
# 启动哨兵模式进行测试
redis-sentinel /myredis/sentinel.conf
说明:这个后面的数字2,是指当有两个及以上的sentinel服务检测到master宕机,才会去执行主从切换的功能
存在的问题
无法解决单节点并发压力问题
无法解决单节点的物理上限问题
spring boot整合哨兵架构
被连接的redis需要在sentinel.conf
文件里加上bind 0.0.0.0
以开启远程链接
# master书写是使用哨兵监听的那个名称
spring.redis.sentinel.master=mymaster
# 连接的不再是一个具体redis主机,书写的是多个哨兵节点
spring.redis.sentinel.nodes=192.168.202.206:26379,192.168.202.208:26379
分布式缓存
什么是分布式缓存
本地缓存和分布式缓存区别?
本地缓存:存在应用服务器内存中数据称之为本地缓存(1ocal cache)
分布式缓存:存储在当前应用服务器内存之外数据称之为分布式缓存( distribute cache)
什么是集群
集群:将同一种服务的多个节点放在一起共同对系统提供服务过程称之为集群
什么是分布式系统
分布式:有多个不同服务集群共同对系统提供服务这个系统称之为分布式系统( distribute system)
redis集群(cluster)
集群架构图
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)