redis

作者: 赵恩栋 | 来源:发表于2021-10-03 19:38 被阅读0次

前言思考

整个网站的瓶颈是什么?

  1. 数据量如果太大、一台机器放不下了
  2. 数据的索引(B+ Tree),一个机器内存也放不下
  3. 访问量(读写混合),一个服务器承受不了

2、Memcached(缓存)+ MYSQL + 垂直拆分(读写分离)

3、分库分表 + 水平拆分 + MYSQL集群

redis入门

概述

Redis是什么?

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。

Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。

Redis能干嘛?

  1. 内存储存、持久化,内存中是断电即失,所以说持久化很重要(rdb、aof)
  2. 效率高,可用于高速缓存
  3. 发布订阅
  4. 地图信息分析
  5. 计时器、计数器
  6. ………………

特性

  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务

通过指定的配置文件启动服务

redis默认安装目录

/usr/local/bin

redis-server kcongfig/redis.conf

redis是单线程

[图片上传失败...(image-aa8202-1633261064223)]

setex key 30 "hello"    # 设置过期时间
setnx       # 不存在,再设置(在分布式锁中会常常使用)
mset        # 批量设置
mget        # 批量获取
msetnx      # 原子性操作,要么一起成功,要么一起失败
getset      # 先get然后set


# set中的值是不能重复
sadd
SISMEMBER   # 判断某一个值是不是在set中
SMEBERS     # 查看指定set的所有值
scard myset # 获取set集合中内容元素的个数
srem        # 移除set中指定的元素
SRANDNEMBER # 随机抽选出一个元素

smove       # 将一个指定的值,移动到另外一个set集合

SDIFF       # 查看两个set集合中的差集
SINTER      # 查看两个set集合中的交集
SUNION      # 查看两个set集合的并集

# Hash(哈希)
hset
hget
hmset
hmget
hdel        # 删除hash指定key字段!对应的value值也就消失了
HEXISTS     # 判断hash指定的字段是否存在
hkeys       # 只获取所有的key
hvals       # 只获取所有的value

# Zset(有序集合)
# 在set的基础上

Hyperloglog

什么是基数?

不重复的元素(个数)

网页的uv(一个人访问一个网站多次。但是还是算作一个人)

0.81%错误率!

PFadd       # 创建一组元素
PFCOUNT     # 统计元素的基数数量
PFMERGE     # 合并两组 并集

如果不运行出错,那么使用set或者自己的数据类型即可

Bitmaps

位储存

统计用户信息,活跃,不活跃!登录、未登录!打卡! 两个状态的都可以使用Bitmaps

事务

Redis事务的本质:一组命令的集合!一个事务中的所有命令都会被序列化,再事务执行的过程中,会按照顺序执行!

==Redis单条命令是保证原子性的,但是事务不保证原子性!==

==redis事务没有隔离级别的概念==

redis事务

  • 开启事务(multi)
  • 命令入队(…..)
  • 执行事务(exec)

Redis监视(乐观锁)

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> INCRBY out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20

理解:watch监听状态下,开启事务,若中途有一个新的线程修改了监听的值,执行事务时失败。unwatch取消监听后,重新watch

通过Jedis操作redis

// maven导包
public static void main(String[] args ) {
    // 1、new Jedis对象
    Jedis jedis = new Jedis("127.0.01",6379);
    
    System.out.pringIn(jedis.ping());
}

spring boot整合

说明:在springBoot2.x之后,原来使用的jedis被替换了lettuce

jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool连接池! BIO

lettuce:采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况! 可以减少线程数据了,更像Nio模式

1、导入依赖

<dependency>
  <groupId>org,springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、在application-properties中进行配置

spring.redis.host=127.0.0.0
spring.redis.port=6379

3、测试

@Autowired
private RedisTemplate redisTemplate;

发现存在中文乱码的问题:因为没有配置序列化

@Configuration
public class RedisConfig {
  // 编写我们自己的redisTemplate
    @Bean
    public RedisTemplate<String, Object> reidsTemplate(RedisConnectionFactory redisConnectionFactory) throw UnknowHostException {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>();
        // 配置具体的序列化方式
        template.setKeySerializer(jackson2JsonRedisSerializer)
        
        ..................基本为固定模板..................
    }
}


配置工具类 redisUntil

Redis持久化

RDB 策略生成文件 AOF 将操作记录下来

1、相对于数据文件来说,aof远远大于rdb,修复的速度也比 rdb慢!

2、Aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化!

发布订阅

Redis主从复制

概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master/leader),后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。
默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

主从复制的作用主要包括:

1、数据冗余∶主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

2、故障恢复︰当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余.

3、负载均衡∶在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

4、高可用基石︰除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的,原因如下︰

1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;

2、从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。

Redis缓存穿透和雪崩

缓存穿透(查不到)

概念

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

解决方案

布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;

[图片上传失败...(image-8162a3-1633261064224)]

缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源﹔

image-20210817150041806

但是这种方法会存在两个问题:

1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

缓存击穿(量太大,缓存过期)

概念

这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。

解决方案

设置热点数据永不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。

加互斥锁

分布式锁∶使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

缓存雪崩

概念

缓存雪崩,是指在某一个时间段,缓存集中过期失效。Redis宕机!

产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

解决方案

redis高可用

这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis ,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)

限流降级

这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

数据预热

数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

相关文章

网友评论

      本文标题:redis

      本文链接:https://www.haomeiwen.com/subject/ijlbnltx.html