一、基本概念
redis是单线程的。NOSQL的非关系型数据库,是以键值对的形式在内存中存储数据。数据吞吐量比较 大,在高并发情况下进行数据的查询效率更高。由于存储在内存中,数据有可能丢失。redis一般用于 缓存数据库中的数据,提升查询效率。常用配置:
1. databases 16: 设置数据库的数量。默认16个数据库编号0~15,默认使用的是第0个
2. bind 127.0.0.1: 限制哪些ip可以访问这个redis服务
3. port 6379 : redis访问端口号。默认:6379
4. save seconds changes :
save 900 1 # 900秒(15分钟) 有1次增删改操作
save 300 10 # 300秒(15分钟) 有10次增删改操作
save 60 10000 # 60秒(1分钟) 有10000次增删改操作
5. dbfilename dump.rdb: 设置快照的文件名,默认是 dump.rdb
6. timeout 300: 客户端闲置多少秒后关闭连接,0:服务端不会主动断开连接
7. dir ./ : 指定本地数据库存放目录
8. requirepass 123456: 设置 Redis 连接密码。设置后需AUTH 密码 命令提供密码
9. maxclients 128: 设置同一时间最大客户端连接数,默认无限制。当客户端连接
数到达限制时,Redis 会关闭新的连接并向客户端返回 max
number of clients reached 错误信息
10. appendonly no: 默认关闭,yes:开启aof。
11. appendfilename appendonly.aof: 指定AOF更新日志文件名,默认为 appendonly.aof
12. appendfsync everysec: 配置aof记录命令日志时机
# no: 表示等操作系统进行数据和缓存同步到磁盘(快)
# always: 表示每次更新操作后手动调用fsnc(),将数据写到磁盘(慢,安全)
# everysec: 表示每秒同步一次(折中,默认值)
二、 redis客户端获取值中文乱码:
一、修改 命令提示符的编码 为utf-8 : chcp 65001
二、命令行启动redis客户端: redis-cli --raw
二、相关文件
1. dump.rdb: RDB快照文件,一定时间内检测写操作,持久化内存的数据到磁盘中。
redis宕机后,下一次启动会自动加载dump.rdb文件,恢复数据
2. redis.windows.conf/redis.windows-service.conf : 配置文件
点击安装目录下的redis-server.exe会默认加载redis.windows-
service.conf的配置。
4. appendonly.aof: AOF更新日志文件,下一次启动会自动加载appendonly.aof文件,执
行操作命令,恢复数据
5. redis-cli.exe: redis的客户端
6. redis-server.exe: redis服务器端
三、常用命令
一、通用命令
1. keys * : 查询所有的键
2. type key : 获取键对应的value的类型
3. del key: 删除指定的key value
4. exits key : 判断是否有指定的key
5. select index: 切换数据库
6. auth 密码: 输入redis密码
二、设置和获取值:
1. 字符串类型 string
set key value 设置值
get key 获取值
del key 删除
2. 哈希类型 hash
hset key field value 设置值
hget key field 获取值
hdel key field 删除指定某一条数据
hgetall key 获取所有
del key 删除指定hash
3.列表类型 list
lpush key value 从左边推入一个元素,存储
rpush key value 从右边推入一个元素,存储
lrange key start end 使用lrange key 0 -1 代表获取所有
lpop key 左弹出
rpop key 右弹出
del key 删除指定list
4. 集合类型 set
sadd key value 设置值
smembers key 获取所有值
srem key value 删除set集合中的某个元素
del key 删除set
5. 有序集合类型 sortedset
有序集合为了排序,每个元素多了一个score属性用于排序。排序的依据仅和score的值有关。
zadd key score value 存储一个值,同时指定此元素的score
zrange key start end [withscores] 获取指定范围的值
zrevrange key start end [withscores] 获取指定范围的值,倒序输出
zrem key value 删除指定值
del key 删除指定的集合
四、数据结构
key全都是字符串
value有以下几种:
1) 字符串类型 : string
2) 哈希类型 hash : map格式
3) 列表类型 list : linkedlist格式,用于当成队列使用。支持重复元素
4) 集合类型 set : 不允许重复元素,无序的
5) 有序集合类型 sortedset: 不允许重复元素,且元素有顺序
五、应用场景
• 缓存(数据查询、短连接、新闻内容、商品内容等等)
• redis锁。(防重复提交)
• 聊天室的在线好友列表
• 任务队列。(秒杀、抢购、12306等等)
• 应用排行榜
• 网站访问统计
• 数据过期处理(可以精确到毫秒)
• 分布式集群架构中的session分离
• redis模拟session(单点登录,session共享)
六、存储对象格式(String格式)
1、直接存对象
redisHelper.set("user",UserRequestVo.builder().userName("奥巴驴").password("123456").phoneNumber("17864110889").build());
存储格式:
2、转为json串
redisHelper.set("aoBaLv",JSON.toJSONString(UserRequestVo.builder().userName("奥巴驴").password("123456").phoneNumber("17864110889").build()));
存储格式:
3、直接存对象集合
List<UserRequestVo> objects = new ArrayList<>();
objects.add(UserRequestVo.builder().userName("张三").password("123").phoneNumber("456").build());
objects.add(UserRequestVo.builder().userName("李四").password("789").phoneNumber("100").build());
redisHelper.setnx("objects",objects);
存储格式:
4、转为json串后存储
List<UserRequestVo> objects = new ArrayList<>();
objects.add(UserRequestVo.builder().userName("张三").password("123").phoneNumber("456").build());
objects.add(UserRequestVo.builder().userName("李四").password("789").phoneNumber("100").build());
redisHelper.setnx("jsonObj",JSON_BINDER.toJson(objects));
存储格式:
七、持久化机制
持久化: redis是一个内存数据库,当redis服务器重启,或者电脑重启,宕机,数据会丢失, 我们可以将redis内存中的数据持久化保存到硬盘的文件中。当下次Redis重启时, 利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程服务器三种持久化机制:RDB快照、AOF记录日志文件、混合持久化
一、RDB快照
1.概念:
在一定的间隔时间中,检测key的变化情况,然后持久化数据内存中的数据 生成一个新的快照,都会覆盖之前的老快照。 默认方式,不需要进行配置,redis默认就使用这种机制, RDB默认是启动的。2.redis.windwos.conf文件
触发rdb持久化机制时机
# after 900 sec (15 min) if at least 1 key changed
save 900 1 // 900秒内只有一次 增删改操作
# after 300 sec (5 min) if at least 10 keys changed
save 300 10 // 300秒内只有10次增删改操作
# after 60 sec if at least 10000 keys changed
save 60 10000 // 60秒内只有10000次增删改操作
3.dbfilename dump.rdb: 设置快照的文件名,默认是 dump.rdb
二、AOF日志文件
1. 概念:
默认是关闭的,日志记录的方式,可以记录每一条命令的操作。每一次命令(增删改)操作后记录每一条操作命令, 以追加文件的方式进行持久化数据,服务重启的时候执行加载AOF文件,执行命令恢复数据。2. 开启AOF
redis.windwos.conf文件:
appendonly no(关闭aof) --> appendonly yes (开启aof)
3. AOF的持久化策略:
# appendfsync always: 同步持久化形式,每一次操作都进行持久化, 每次写入时都记录会
产生大量磁盘IO,从而性能会受到影响,但是数据最安全
appendfsync everysec: 异步操作,每隔一秒进行一次持久化, 如果持久化之后的一秒内宕
机,会造成1S的数据丢失
# appendfsync no: 操作系统控制的写回,每个写命令执行完,只是先把日志写到 AOF 文
件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘,落盘的
时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,
一旦宕机对应的数据就丢失了
4. appendfilename “appendonly.aof”: 指定aof文件
5.aof重写机制
根据数据库的现状创建一个新的 AOF 文件, 多条写命令可以合并为批量写命令
重写机制具有 多变一 功能,旧日志文件中的多条命令,在重写后的新日志中变成了一条命令
触发重写时机:
1. 手动触发:
执行BGREWRITEAOF命令不会阻塞redis的服务
2. 自动触发:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
启用的AOF持久化时,当AOF文件体积大于64mb,
并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发
三、混合持久化 (redis 4.0版本之后)
1. 概念:(Redis 5.0 默认是开启的)
rdb 文件的内容和增量的 AOF 日志文件存在一起, 自持久化开始到持久化结束的这段时间发生的增量 AOF 日志, 通常这部分AOF 日志很小。在redis重启的时候,加载 aof 文件进行恢复数据:先加载 rdb 内容再加载剩余的 aof操作日志2.开启混合持久化:
aof-use-rdb-preamble yes # yes:开启,no:关闭
四、rdb aof区别和优缺点
1. 区别:
RDB:在指定的的时间间隔内将内存中的数据快照写入磁盘,新生成的快照文件会覆盖旧的。它恢复时是将快照文件直接读到内存中,恢复数据。
AOF:以日志的形式来记录每个写操作,只许追加文件但不可以改写文件,redis启动会读取该文件,执行文件中的命令,重新构建数据。
2. 优缺点:
RDB:
适合大规模的数据恢复,对数据完整性和一致性要求不高
恢复时是将快照文件直接读到内存中恢复速度快
redis宕机,会导致丢失最后一次快照后的所有修改
AOF:
数据安全性,完整性相对高, redis宕机最多丢失一秒的数据
AOF 文件比 RDB 文件大,且恢复速度慢
数据量大的时候,比 rdb 启动效率低。
八、雪崩,击穿,穿透
一、雪崩
在高并发下,大量缓存key在同一时间失效,大量请求直接访问数据库,导致数据库宕机。
解决方案:
1.不设置过期时间。方式最可靠,占空间,内存消耗大
2.随机设置key失效时间,避免大量key集体失效。
3.跑定时任务,在缓存失效前刷新缓存。
4.搭建redis集群,对数据库进行读写分离
二、击穿
在高并发下,某一热点key突然失效,大量请求就会击破缓存直接访问数据库,导致数据库宕机。
解决方案:
1.加锁:在未命中缓存时,通过加锁避免大量请求访问数据库
2.不设置过期时间:不设置过期时间。定时在后台异步的更新数据。
三、穿透
在高并发下,用户访问的数据既不在缓存中,也不在数据库中,大量请求到来时,访问数据库,导致数据库的压力骤增
解决方案:
1.接口添加校验:对请求的参数增加基础校验,避免随便输入入参就可以访问数据库;指定接口的请求方式;减少恶意被攻击
的概率
2.设置默认值:对缓存中不存在数据库中也不存在的数据设置默认值;防止攻击用户反复用同一个id暴力攻击
九、自增
/**
* 生成卡号
* 从0开始自增
*
* @return Long
*/
public String getIncr(String cardNumber) {
assert redisTemplate != null;
RedisAtomicLong entityIdCounter = new RedisAtomicLong(REDIS_INCR_ZK_FIX,
Objects.requireNonNull(redisTemplate.getConnectionFactory()));
long andIncrement = entityIdCounter.getAndIncrement() + 1;
DecimalFormat decimalFormat = new DecimalFormat(cardNumber + "000000000");
return decimalFormat.format(andIncrement);
}
十、监听过期key
- 监听配置类
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
- 自定义监听类
@Slf4j
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
// 过期key
String expiredKey = message.toString();
//逻辑处理
}
}