redis 怎么说呢,在项目中经常用,但是仅仅只是限于用它常用的一些api
至于它里面的原理也是一直都没有搞清楚
今天就来具体探究一下redis内部的工作机制和底层原理吧
Redis 是一个开源的key-value 存储系统,no-sql 数据库
支持存储的value类型 可以包括String(字符串), list(链表), set(集合),zset(sorted set --有序集合)和 hash(哈希类型)
这些数据类型支持 push/pop、add/remove 及取交集并集和差集及更多操作,且这些操作都是原子性的
数据都缓存在内存中的,redis会周期性的把更新的数据写入磁盘,或把修改操作写入追加的记录文件
常用命令
./redis-server /etc/redis.conf 启动 redis
./redis-cli 登录
set key value 设置key 和值
get key 获取key对应的值
keys * 查看当前库所有 key
exists key 判断某个key是否存在
type key 查看你的key 是什么类型
del key 删除指定的key数据
unlink key 根据key选择非阻塞删除 仅将keys 从keyspace 元数据中删除,真正删除会在后续异步操作
expire key 10 设置key过期时间10秒钟
ttl key 查看还有多少秒过期,-1 表示永不过期,-2 表示已经过期
select 1 选择库
dbsize 查看当前数据库的key的数量
flushdb 清空当前库
mset k1 v1 k2 v2 k3 v3 设置多个key-value
mget k1 k2 k3 获取多个key 对应的值
msetnx k11 v11 k22 v22 k33 v33 原子性,
setex k 30 value 设置 k 值为value 过期时间30秒
Redis 线程模型:
redis 采用 nio 的io多路复用原则,也就是一个线程维护多个不同的redis客户端连接,从而提高处理并发效率和保证线程安全的问题,底层采用linux系统的epoll技术避免空轮询。
我觉得暂时了解到这里就可以了吧,至于底层linux的epoll技术是什么呢?有兴趣的话可以接着深入探究一下
redis 缓存机制与原理
可存储的五种数据类型对应的是 value的类型
String 类型,Hash类型,List类型,Set类型,Sorted-Sets
String 的数据结构为简单动态字符串 Simple Dynamic String[SDS], 是可以修改的字符串,内部结构实现上类似java 的ArrayList,采用预分配冗余空间的方式来减少内存频繁分配 最大长度512M
string 常用命令
set key value 设置key 和值
get key 获取key对应的值
append key value2 在key对应的值后面追加value2
strlen key 获取key对应的值的长度
setnx key value 当key 不存在时 才能设置成功
incr key 增加1 incrby key 10 增加10
decr key 减1 decrby key 9 减9
List 单键–多值 如:name ----“gexl,xiaozhang,xiaoli”
底层数据结构是双向链表 quicklist 快速链表
lpush/rpush 存值[左/右]
lpop/rpop 取值[左/右]
lrange key 0 -1 取出k对应的全部值
set 类型
set 集合的操作命令
将一个或多个元素添加到指定的集合总
sadd key value [value value …]
sadd set01 a b c
sadd set01 d e f
获取指定集合中所有的元素: smembers key
smembers set01
判断指定元素是否在集合中存在 sismember key member
存在 返回1
不存在 返回0
sismember set01 d
获取指定集合的长度
scard key
scard set01
指定移除集合中的一个或者多个元素:
srem key member [member …]
srem set01 a b f
将指定集合中的指定元素移动到另一个集合中
smove source dest member
smove set1 set2 c
获取第一个集合中有但是 其他集合中没有的元素组成的新集合
sdiff key key [key …]
sdiff set1 set2 set3
获取所有指定集合中所有元素中相同的元素
sinter set1 set2 set3
获取所有指定集合中所有元素组成的大集合
sunion set1 set2 set3
sorted-sets类型
hash 类型
hash 类型的数据结构 特别适合对象的存储
key–user value ----> field value user = {id=1,name=gexl,age=20} 不过修改数据时 不方便
id 1
name gexl
age 20
第二种 数据分开存储 user:id 1
user:name gexl
user:age 20 缺点数据分散
第三种方案 hash id 1
user—> name gexl
age 20
命令:hset user:1001 id 1
hset user:1001 name gexl
hset user:1001 age 20
hget user:1001
hkeys user:1001 查看key
hvals user:1001 查看key对应的value
Redis 的持久化机制 aof 、 rdb(默认)
redis 宕机之后数据不会丢失的原因就是持久化机制
默认开启的持久化
RDB 是采用的定时同步,属于是全量同步
在redis.conf 文件中的配置
save 900 1 # 每900秒(15分钟) 之内至少有1次keychanged [key 的变化] 操作 则记录 在dump.rdb 文件中
save 300 10 # 每300秒(5分钟) 内至少有10次 keychanged 操作 则记录在dump.rdb文件中
save 60 10000 # 每60秒(1分钟) 至少有10000次 keychanged操作 则 记录在dump.rdb文件中
AOF 是根据操作日志来进行同步的,属于增量同步
aof 的三种同步策略
在 redis.conf 文件修改配置 如下:
appendonly yes
appendfilename “appendonly.aof”
# appendfsync always # 数据发生修改 则同步到aof文件中去,保证数据不丢失,但是效率比较低
appendfsync everysec # 每秒钟 从缓冲区一次性写入进入aof文件, 同步效率高,但是可能丢失一秒的数据
# appendfsync no #
appendonly.aof 文件中 记录了 每次set 命令调用执行时的信息 key 和 value信息
EHCACHE 一级缓存
淘汰策略,持久化机制
全量同步和增量同步
每天定时避开高峰期或者采用周期 实现将数据拷贝到另一个地方
增量同步采用行为操作对数据实现同步
频率高,对服务器同步的压力大,数据不丢失
redis的应用场景:
Token 令牌的生成
短信验证码的code 时效性
实现缓存查询数据
减轻数据库的访问压力, 可以作为一种nosql的数据库 存储数据
实现计数器
分布式锁
lua 脚本 保证 删除的原子性
redis 实现分布式锁
String uuid = UUID.randomUUID().toString();
// 添加uuid 防止 误删除
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",uuid,3,TimeUnit.SECONDS);
// 获取到 uuid 如果一致 则删除
if(uuid.equals((String))redisTemplate.opsForValue().get("lock")) {
// 释放锁
redisTemplate.delete("lock");
// 续命
}
延迟操作
分布式消息中间件
缓存击穿
在同一时间某些热点数据的redis key 过期,此时又有大量的请求访问过来,请求打到数据库,造成数据库压力增大,
解决方案
设置redis key 不过期,或者不定时过期,总之不能在同一时间过期,减小数据库的访问压力
缓存穿透
使用 redis 和 数据库都不存在的key 来大量的请求 查询 redis缓存,redis中不存在的key 的请求, 则会打到数据库上去
造成数据库压力增大
解决方案:
这种多是 来自黑客的攻击,查找并禁用 黑客的ip地址或者请求
在接口处做 校验 如果 id<0 则直接返回,不让请求打到redis和数据库
将这些请求的key 设置在redis中 key 对应的value 设置为null
缓存雪崩
有缓存击穿或者缓存穿透 造成的数据库宕机 无响应,影响正常的业务操作
在spring项目中使用 RedisTemplate redisTemplate时 的注入问题
在制定了泛型时 使用@Autowired 注入无效
@Resource 则可用
数据库的数据与redis 数据不一致时,
MySQL 和 Redis 的数据同步问题如何解决?
方式一:直接清理Redis 缓存,重新查询数据库即可
方式二: 直接采用MQ订阅 mysql binlog 日志文件 增量同步到Redis中
最终一致性方案 存在短暂数据延迟
方式三:使用alibaba的canal
强一致性 在redis 不成立,只是通过弱一致性和 最终一致性来解决的
使用MQ 订阅数据库binlog 文件,增量实时同步到 redis中去
redis这块怎么说呢,感觉里面的有些东西如果深入研究的话内容还是比较多的,有些问题也需要去构建环境实践的,时间有限,所以先抄作业记录在此处,后续再接着完善