Redis

Redis基础

概念

基于内存的键值型NoSQL数据库

特征

  • 键值型,value支持多种不同数据结构,功能丰富
  • 单线程,每个命令具备原子性
  • 低延迟,速度快(基于内存、IO多路复用、良好的编码)
  • 支持数据持久化
  • 支持主从集群(可以做读写分离)、分片集群
  • 支持多语言客户端

区别

SQLNOSQl
数据结构结构化非结构化
数据关联关联的无关联的
查询方式SQl查询非SQl
事务特性ACIDBASE
存储方式磁盘内存
拓展性垂直水平
使用场景1.数据结构固定
2.相关业务对数据安全性一致性要求较高
1.数据结构不固定
2.对一致性、安全性不高
3.对性能要求

数据结构

Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样

基本数据类型

String:字符串类型,Reids中最常见的存储类型其value是字符串,不过根据字符串的格式不同,分三类

  • string:普通字符串
  • int:整型类型,可以做自增,自减操作
  • float:浮点类型,可以做自增,自减操作

底层都是字节数组形式存储,只不过编码方式不同,最大空间不能超过512M

常见命令

  • SET:添加或者修改已经存在的一个String类型的value

  • GET:根据key获取String类型的键值对

  • MSET:批量添加多个String类型的键值对

  • MGET:批量获取多个String类型的value

  • INCR:让一个整形的key自增1

  • INCRBY:让一个整型的key自增并指定步长

  • INCRBYFLOAT:让一个浮点型的key自增长

  • SETNX:添加一个String类型的键值对,前提是这个Key不存在,否则不执行

  • SETEX:添加一个String类型的键值对,并指定有效期,可直接用SET key value ex 秒在后面添加过期时间

  • Hash:Hash类型,也叫散列,value是一个无序字典,类似于java中的HashMap结构

可以将对象中的每个字段单独存储,可以针对单个字段做CRUD

常见命令

  • HSET key field value:添加或修改hash类型的field的值

  • HMGET key field :获取一个hash类型的key的field的值

  • HMSET :批量获取多个hash类型key的filed的值

  • HMGET:批量获取多个hash类型key的filed的值

  • HGETALL:获取一个hash类型的key中的所有的filed和value

  • HKEYS:获取一个hash类型的key中的所有的filed

  • HVALS:获取一个hash类型的key中的所有的value

  • HINCRBY:让一个hash类型key的字段值自增长并指定步长

  • HSETNX:添加一个hash类型的key的field值,前提是这个filed不存在,否则不执行

  • List:与Java中的LinkedList类似,可以看作是一个双向链表,既支持正向检索也支持反向检索

特征

  • 有序
  • 元素可以重复
  • 插入和删除快
  • 查询速度一般

常见命令

  • LPUSH key element…:向列表左侧插入一个或多个元素
  • LPOP key :移除并返回列表左侧的第一个元素,没有则返回null
  • RPUSH key element…:向列表的右侧插入一个或多个元素
  • RPOP key:移除并返回列表左侧的第一个元素
  • LRANGE key star end :返回一段角标范围内的所有元素
  • BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时指定时间,而不是返回null
  • Set:与Java中的HashSet类似,可以看作是一个value是null的HashMap

特征

  • 无序
  • 元素不可重复
  • 查找快
  • 支持交集、并集、差集等功能

常用命令

  • SADD key member…:向set中添加一个或多个元素
  • SREM key member…:移除set中的指定元素
  • SCARD key:返回set中元素的个数
  • SISMEMBER key member:判断一个元素是否存在于set中
  • SMEMBERS:获取set中的所有元素
  • SINTER key1 key2…:求key1与key2的交集
  • SDIFF key1 key2 …:求key1与key2的差集
  • SUNION key1 key2 …:求key1与key2的并集
  • SortedSort:可排序的set集合,与Java中的treeSet类似,SortedSet中的每一个元素有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加hash表。

特性

  • 可排序
  • 元素不重复
  • 查询速度快

经常被用来实现排行榜这样的功能

常见命令

  • ZADD key score meber:添加一个或多个元素到sorted set ,如果已经存在则更新其score值
  • ZREM key member:删除sorted set 中的一个指定元素
  • ZSCORE key member :删除sorted set 中的指定元素的score值
  • ZRANK key member :获取sorted set 中的指定元素的排名
  • ZCARD key :获取sorted set 中的元素个数
  • ZCOUNT key min max :统计score值在给定范围内的所有元素的个数
  • ZINCBY key increment member :让sorted set中的指定元素自增,步长为指定的increment值
  • ZRANGE key min max :按照score排序后,获取指定范围内的元素
  • ZRANGEBYSCORE key min max :按照score排序后,获取指定score范围内的元素
  • ZDIFF、ZINTER、ZUNION:求差集、交集、并集

默认都是升序,如果要降序则在命令的Z后面添加REV即可,例:ZREVRANGE key min max

特殊类型

  • GEO
  • BItMap
  • HyperLog

通用命令

通过 help [ ] 可查看命令详情
  • KEYS:查看符合模板的所有Key,不建议再生产环境下使用
  • DEL:删除一个指定的KEY(支持删除多个KEY,Key之间用空格隔开)
  • EXISTS:判断Key是否存在
  • EXPIRE:给一个Key设置有效期,有效期到期时该key会被自动删除(EXPIRE key名称 秒)

Key的层级结构

Redis的key允许有多个单词形成层级结构,多个单词之间用“:”隔开

项目名:业务名:类型:id

格式并非固定,可以根据需求更改

  • user相关的key:XXX:user:1
  • product的key:XXX:product:1

Value是一个Java对象,可以将对象序列化为JSON字符串后存储

SpringDataRedis的基本使用

  • 添加依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 配置Reids
spring:
  data:
    redis:
      host: 127.0.0.1
      port: 6379
  • 注入RedisTemplate,使用
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
    redisTemplate.opsForValue().set("name","李四");
    Object name = redisTemplate.opsForValue().get("name");
    System.out.println("name="+name);
}

SpringDataRedis的序列化方式

默认方式

RedisTemplate可以接收任意Object作为值填入Redis,只不过写入前会把Object序列化为字节形式,采用JDK的序列化方式

缺点

  • 可读性差
  • 内存占用较大

自定义序列化方式

  • 自动序列化定义
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
//创建Template
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

//设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//key和hashKey采用string序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
//value和hashValue采用Json序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
  • 自动的序列化会存储对象的一些信息,为节省内存空间,一般不使用Json序列化器来处理vlaue,而是统一使用String序列化器,要求只存储String类型的key和value,当需要存储java对象的时候,手动完成对象的序列化和反序列化
  • Spring默认提供了一个SpringRedisTemplate类,他的key和value的序列化方式默认为String方式
  • 手动序列化和反序列化
@Autowired
private StringRedisTemplate stringRedisTemplate;
private static final ObjectMapper mapper=new ObjectMapper();
@Test
void redisTemplateTest() throws JsonProcessingException {
//创建对象
User user = new User("张三", 15);
//手动序列化
String json = mapper.writeValueAsString(user);
//向Redis存储
stringRedisTemplate.opsForValue().set("user:100",json);
//从redis中取数据
String o = stringRedisTemplate.opsForValue().get("user:100");
//手动反序列化
User user1 = mapper.readValue(o, User.class);
//打印
System.out.println("user:100="+user1);
}

缓存

概念

缓存就是数据交换的缓冲区,是存贮数据的临时地方,一般读写性能较高,在CPU中

作用

  • 降低后端负载
  • 提高读写效率,降低响应时间

成本

  • 数据一致性成本
  • 代码维护成本
  • 运维成本

缓存作用模型

![](https://i-blog.csdnimg.cn/img_convert/d24316a025ee77e85f9491ac339f6d8e.png)

缓存更新策略

内存淘汰超时剔除主动更新
说明不用自己维护,利用Reids的内存淘汰机制。当内存不足时自动淘汰部分数据下次查询时更新缓存给缓存数据添加TTL时间,到期后自动删除缓存,下次查询时更新缓存编写业务逻辑,在修改数据库的同时,更新缓存
一致性一般
维护成本

业务场景

  • 低一致性需求:利用内存淘汰机制
    • 高一致性需求:主动更新,并以超时剔除作为兜底方案
      • 读操作
        • 缓存命中则直接返回
        • 缓存未命中则查询数据库,并写入缓存,设定超时时间
      • 写操作
        • 先写数据库,然后再删除缓存,发生线程安全的可能性更低
        • 确保数据库与缓存操作的原子性
主动更新策略
  • 由缓存的调用者,在更新数据库的同时更新缓存(可靠性更高)
    1. 删除缓存:查询时再更新缓存
    2. 单体系统:将缓存与数据库操作放在一个事务
    3. 分布式系统:利用TCC等分布式事务方案
    4. 一般先更新数据库,然后再删缓存
  • 缓存与数据库整合为一个服务,由服务来维护一致性,调用者调用该服务,无需关心缓存一致型那个问题
  • 调用者只操作缓存,由其他线程异步的将缓存数据持久化到数据库,保持最终版一致

缓存穿透

缓存穿透是指客户端请求的数据再缓存中和数据库都不存在,这样缓存永远不会生效这些请求都会打到数据库

解决方案

  • 缓存空对象

  • 优点:实现简单,维护方便

    • 缺点:
      • 额外的内存消耗
      • 可能造成短期不一致
  • 布隆过滤

    * 优点:内存占用少,没有多余key
    * 缺点:
        + 实现复杂
        + 存在误判可能

缓存雪崩

缓存雪崩是指同一时段大量的缓存key同时失效,或者Redis服务宕机,导致大量请求到达服数据库,带来巨大压力

解决方案

  • 给不同的key的TTL添加随机值
  • 利用Redis集群提高服务的可用性
  • 给缓存业务添加降级限流策略
  • 给业务添加多级缓存

缓存击穿

缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效,无数的请求访问会再瞬间给数据库带来巨大的冲击

解决方案

  • 互斥锁

  • 逻辑过期

解决方案优点缺点
互斥锁+ 没有额外的内存消耗
+ 保证一致性
+ 实现简单
+ 线程需要等待,性能受影响
+ 可能有死锁风险
逻辑过期+ 线程无需等待,性能较好+ 不保证一致性
+ 有额外的内存消耗
+ 实现复杂

分布式锁

![](https://i-blog.csdnimg.cn/img_convert/c4073293e3052ae339f7edf8c5d2fa91.png)

满足分布式系统或集群模式下多进程可见并且互斥的锁

基本特性

  • 多进程可见
  • 互斥
  • 高可用
  • 安全性
  • 高性能

分布式锁的实现

分布式锁的核心是实现多进程之间互斥
MySQLRedisZookeeper
互斥利用mysql本身的互斥锁机制利用setnx这样的互斥命令利用节点的唯一性和有序性实现互斥
高可用好(支持主从模式)好(主从、集群)
高性能一般一般
安全性断开连接,自动释放锁利用锁超时时间、到期释放临时节点,断开连接自动释放

基于Redis的分布式锁

  • 获取锁
    • 互斥:确保只能有一个线程获取锁

SET lock key NX EX time

  • 释放锁
    • 手动释放
      DEL key
    • 超时释放:获取锁时添加一个过期时间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值