redis

Redis入门笔记

前言:先自我介绍一下,我大三在读,这个笔记是我自己在网上看的两个Redis教学视频总结出来的,分享出来,也方便自己以后翻阅查看。PS:我个人很懒,没有繁琐的官方语言,纯用自己思考过后,用最简单的话来形容一些知识点 (๑•̀ㅂ•́)و✧ 做的不好的地方可以评论我会即使改正哒 ( ̄︶ ̄)↗

一、面试

哨兵模式、主从复制、持久化、删除策略、数据类型

面试题

1.腾讯三面:哨兵挂了,Redis还能正常工作吗?

网上许多文章的答案都是在说Redis的哨兵机制,长篇大论的让人阅读了之后,就不在思考问题的本身了(也可能是我还没到达大佬们的境界),没人有正面说出来答案的结果,而且还有许多Copy文章(# ̄~ ̄#)我翻看了许多评论找到了两条比较我个人感觉很好的回答

  • 客户端用的是哨兵的地址,redis真实地址是哨兵给的。哨兵挂了,redis是好的。不过客户端应该是连不上了,得不到地址了
  • 从Redis经典三节点哨兵集群看得出来,最少3个才拥有维持规矩的基础,如果最后只剩下2个人,那么规则系统必定崩塌

2.字节二面:Redis数据结构的底层实现

自行百度吧,我也不太会 ┗( T﹏T )┛

3.顺丰一面:Redis 集群了解吗,集群的工作原理、机制?

简书的一篇文章:https://www.jianshu.com/p/84dbb25cc8dc

二、Redis命令

1.启动

redis_第1张图片

2.设置密码

单机版的Redis可以不用设置密码,如果是云服务器的Redis一定要设置密码 ✧(≖ ◡ ≖✿),这种方式Redis重启密码就失效了,需要进入配置文件修改密码,具体方法会在:六、Redis.config详解SECURITY里介绍

redis_第2张图片

3.Linux查看进程

img

三、基础知识

1.Redis单线程

官方表示:Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis是根据机器的内存和网络带宽,使用单线程实现!

读写速度:CPU>内存>硬盘

2.Redis误区

  • 高性能服务器一定是多线程的嘛:理论上来说是的(在不考虑数据一致性前提下)

  • 多线程效率一定比单线程效率高嘛:多线程效率不一定比单线程效率高; 抛开业务因素等, 针对性的说多核cpu机器,多线程肯定比单线程效率高

3.事务

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

运行时异常如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误的命令抛出异常:Redis与MySQL区别

编译型异常(代码、命令有错)事务中所有的命令都不会执行

四、springBoot整合redis

1.pom依赖(SpringBoot版本是2.6.2)

<dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

2.配置连接

#配置Redis
spring.redis.host=192.168.184.129
spring.redis.port=6379

3.测试连接

@Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

        redisTemplate.opsForValue().set("mykey", "yxy"); //value现在使用中文,redis会出现\xac\xed\x00\x05t\x00\x05mykey乱码
        System.out.println(redisTemplate.opsForValue().get("mykey")); //因为redis默认使用JDK序列化,后文会使用Json序列化

    }

4.解决Redis中文乱码

User类:

@Component
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable {
    private String name;
    private int age;
}

使用Lombok可以不用写set、get方法等等٩( ‘ω’ )و

我个人感觉Lombok有安全隐患,大量的构造器可以不用自己写,全权交给Lombok。感觉不太稳妥 (T ^ T)

个人开发无所谓,如果团队开发,一个人用Lombok团队所有人都要用 (○` 3′○)

测试类:

 @SneakyThrows
    @Test
    public void test() {
        User user = new User("轱辘的牛宝宝", 19);
        /**
         * ObjectMapper类是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构
         */
        String jsonUser = new ObjectMapper().writeValueAsString(user);
        redisTemplate.opsForValue().set("user",jsonUser);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }

Run:{“name”:“轱辘的牛宝宝”,“age”:19}

PS:这个时候redis那边一定还是乱码 (°ㅂ° ╬)

自定义RedisTemplate:

@Configuration
public class RedisConfig {
    @Bean(name="redisTemplate")
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(redisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(redisSerializer);
        //key haspmap序列化
        template.setHashKeySerializer(redisSerializer);
        return template;
    }
}

自定义序列化类名与源码一致,测试类需要使用自定义序列化:

@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisTemplate;

Redis:

127.0.0.1:6379> keys * #生产环境不要用*哦
1) "\xac\xed\x00\x05t\x00\x04user"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
1) "user" #成功 ♪(^∇^*)

5.收获

主机连接不上虚拟机redis问题

#bind 127.0.0.1、protected-mode yes 改成 no

并且需要关闭防火墙,如果在关闭状态,尝试打开防火墙,总之反复尝试就对了,不是IP地址问题就是防火墙问题(๑>؂<๑)

六、Redis.config详解

了解配置文件,以后修改一些文件可以方便一点

网络:

bind 127.0.0.1 #指定 redis 只接收来自于该IP地址的请求
protected-mode yes #是否开启保护模式,默认开启。
port 6379 #端口号

GENERAL:

daemonize yes #是否在后台执行,默认是no
pidfile /var/run/redis/redis.pid #redis的进程文件
loglevel notice #服务端日志的级别,notice适合生产环境
databases 16 #数据库数量 0-15

SNAPSHOTTING:

save "" #若不想用RDB方案,可以把 save "" 的注释打开
save 900 1 # 900秒内有1个更改,进行持久化
save 300 10 # 300秒内有10个更改,进行持久化
save 60 10000 # 60秒内有10000个更改,进行持久化
stop-writes-on-bgsave-error yes #当RDB持久化出现错误后,是否依然进行继续进行工作
rdbcompression yes #是否压缩RDB文件,但会占用一点CPU时间,如果关闭会导致数据库文件变化巨大
rdbchecksum yes #是否校验RDB文件,如果追求性能可以关闭
dir ./ #RDB文件保存位置

REPLICATION:主从复制的相关配置哦 (/ω\)

# replicaof   #主机IP地址 主机端口号

SECURITY:

requirepass 123456 #原来是注释的,需要自己去掉注释,修改密码

CLIENTS:

maxmemory-policy noeviction #内存达到上限之后的处理策略,六种策略可以自行百度哦 o( ̄▽ ̄)d

APPEND ONLY:

appendonly no #默认不开启,它的出现是为了弥补RDB的不足
appendfilename "appendonly.aof" #持久化文件名字
appendfsync always #always表示每次写入都执行fsync,以保证数据同步到磁盘
appendfsync everysec #everysec表示每秒执行一次fsync,可能会导致丢失这1s数据
appendfsync no #no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快

七、Redis持久化

持久化:在规定的时间内,执行了多少次操作

Redis是内存数据库,如果没有持久化,那么数据断电就没啦 w(゚Д゚)w

面试和工作,持久化都是重点

1.DRB

RDB可以看作为某一时刻Redis的快照,比较适合灾难恢复,可以看作快照

redis_第3张图片

优点:主进程不进行任何IO操作,确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是很敏感,那么RDB方式要比AOF方式更加高效

缺点:最后一次持久化的时候如果宕机,数据可能丢失。fork进程的时候,会占用一定的内存空间

RDB触发机制

​ 1.save的规则满足的情况下,会自动触发RDB规则

​ 2.执行flushall命令,也会触发RDB规则

​ 3.退出Redis,也会产生RDB文件

恢复RDB文件

​ 只需要将RDB文件放在redis启动目录,redis启动的时候会自动检查dump.rdb恢复其中的数据

2.AOF

将所有命令都记录下来,恢复的时候把文件全部再执行一遍

​ AOF默认是关闭的,需要在配置文件中开启AOF。Redis支持AOF和RDB同时生效,如果同时存在,AOF优先级高于RDB(Redis重新启动时会使用AOF进行数据恢复)

​ 监听执行的命令,如果发现执行了修改数据的操作,同时直接同步到数据库文件中

优点:相对RDB数据更加安全

缺点:相同数据集AOF要大于RDB,相对RDB可能会慢一些

开启办法

# 默认no
appendonly yes
# aof文件名
appendfilename "appendonly.aof"

八、Redis主从复制

Redis支持集群功能。为了保证单一节点可用性,支持主从复制功能。每个节点有N个复制品(replica),其中一个复制品是主(master),另外N-1个复制品是从(Slave),也就是说Redis支持一主多从

redis_第4张图片

优点:

增加单一节点的健壮性,从而提升整个集群的稳定性。(Redis中当超过1/2节点不可用时,整个集群不可用)

从节点可以对主节点数据备份,提升容灾能力。

读写分离。在redis主从中,主节点一般用作写(具备读的能力),从节点只能读,利用这个特性实现读写分离,写用主,读用从

环境配置

复制三份配置文件:

redis_第5张图片

master:主机不用修改端口号

logfile "master.log"
dbfilename dump_master.rdb

salve1:

port 6380
pidfile /var/run/redis_6380.pid
logfile "salve1.log"
dbfilename dump_salve1.rdb

savle2:

port 6381
pidfile /var/run/redis_6381.pid
logfile "salve2.log"
dbfilename dump_salve2.rdb

修改成功:

redis_第6张图片

从机认主:

SLAVEOF 192.168.184.129 6379 #主机IP 主机端口

主机信息显示:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1 
slave0:ip=192.168.184.129,port=6380,state=online,offset=210,lag=0
master_replid:6cb7a665a70075f56596e30814a3bb0ee659d074
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 
slave0:ip=192.168.184.129,port=6380,state=online,offset=504,lag=1
slave1:ip=192.168.184.129,port=6381,state=online,offset=504,lag=0
master_replid:6cb7a665a70075f56596e30814a3bb0ee659d074
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:504
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:504
127.0.0.1:6379> 

命令行认主行为只是暂时的,真正的应该去配置文件配置

主机写,从机只能读!主机所有信息数据,都会自动被从机保存

扩展:

Redis01挂掉了,Redis02也还是只能读不能写 <( ̄︶ ̄)>

redis_第7张图片

九、哨兵(Sentinel)

1.哨兵模式简述

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例 对于男孩子来说这个模式很吊的有木有 (≧∀≦)ゞ

redis_第8张图片

哨兵两个作用:

发送命令,让每个被监控的Redis服务器返回其运行状态

当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机 (๑ˉ∀ˉ๑)

一个哨兵监控的时候可能会有偷懒的时候 ╮(╯▽╰)╭ ,这个时候就需要多个哨兵啦,而且让哨兵之间互相监督不许偷懒  ̄へ ̄

文字叙述一下failover过程:假设哨兵A发现主机挂掉啦,不会马上进行故障转移,因为这仅仅是它自己主观认为主机挂掉了,这个现象网上称为主观下线。等到发现主机挂掉到达一定数量的其他哨兵,它们会集合起来开会,最后决定由一个哨兵去进行故障转移。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从机切换为主机,这个过程称为客观下线。这样对于外部而言,一切都是透明的

redis_第9张图片

2.测试

配置哨兵配置文件sentinel.conf

sentinel monitor 被监控的名称 host port 1 #1代表至少由一个哨兵确认

哨兵模式的缺点

Reids不好在线扩容,集群容量到达一定上限,在线扩容很麻烦

实现哨兵模式的配置其实是很麻烦的,里面有很多选择

3.哨兵模式相关问题

主机挂掉了,选举出了新的主机,这个时候主机再回来时候自动就变成了从机

主机内心:啊~~~朕的大清亡了 …(⊙_⊙;)…

从机内心:三年前你瞧我不起,三年后我让你高攀不起 <( ̄ˇ ̄)/

哨兵都挂掉了肿么办⊙▽⊙

从Redis经典三节点哨兵集群看得出来,最少3个才拥有维持规矩的基础,如果最后只剩下2个人,那么规则系统必定崩塌,哨兵模式有自己的算法,可以自行百度(>人<;)

哨兵模式 客户端不用连接主服务器了吗?直接连接哨兵服务器就可以?

哨兵服务器相当于注册中心。先从注册中心获取redis master 服务地址,然后再发起链接。当master宕机 哨兵会进行投票决定master是否真正死亡,然后选举最健康的slave作为新的master,然后客户端再次发起新的链接

哨兵监控从节点的作用是?

监控从节点是为了方便在 master 客户下线的时候,选举其某个表现良好的从节点成为新的 master

十、Redis缓存穿透和雪崩

缓存机制

redis_第10张图片

1.缓存穿透

缓存穿透是查不到,与缓存击穿有明显的区别。缓存击穿是查到的太多了!

redis缓存中没有该条查询结果,会去数据库中查询,查询一次没有就查询两次,如果这个时候秒杀系统(也可能是有人采用洪水攻击)大量给数据库发送请求,数据库可能会招架不住导致崩溃 ┗( T﹏T )┛

2.布隆过滤器

布隆过滤器(LOL:”你可以永远相信布隆!!!” “站在布隆后面!!!”)

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储层的查询压力。相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的

redis_第11张图片

3.缓存空对象

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

如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的空键

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

4.缓存击穿

简述:

缓存击穿与缓存穿透不一样,缓存击穿是一个key非常热点,一直在扛着高并发。俗话说就是:对着一个点猛攻!

当这个Key在过期的那一瞬间,由于缓存过期会同时访问数据库来查询最新数据,并回写缓存,这会导致数据库瞬间压力过大

解决方案:

设置热点数据永不过期(不太可能实现,因为存着存着的它会满啊,满了自己删除一些Key)

加锁,使用分布式锁,保证对于每个Key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可,把压力给了分布式锁 ₍₍ ◝( ゚∀ ゚ )◟⁾⁾不送

5.缓存雪崩

简述:

是指在某一时间段内,缓存集体过期失效,或者是Redis宕机,就是上图中缓存层没有啦 (>▽<)

但最致命的是缓存服务的某个节点宕机,对数据库造成的压力不可预知,很有可能瞬间就把数据库搞垮 o((⊙﹏⊙))o.

解决方案:

Redis高可用:多加几台Redis

限流降级:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量

数据预热:就是提前把可能会被大量访问的Key们,加载到缓存中,给它们设置不同的过期时间

十一、Redis类型

Redis命令相关手册有很多,下面为其中比较好用的两个

1.https://www.redis.net.cn/order

2.http://doc.redisfans.com/text-in

1. Key操作

exists

​ 判断key是否存在。

​ 语法:exists key名称

​ 返回值:存在返回数字,不存在返回0

expire

​ 设置key的过期时间,单位秒

​ 语法:expire key 秒数

​ 返回值:成功返回1,失败返回0

ttl

​ 查看key的剩余过期时间

​ 语法:ttl key

​ 返回值:返回剩余时间,如果不过期返回-1

del

​ 根据key删除键值对。

​ 语法:del key

​ 返回值:被删除key的数量

2. 字符串值(String)

set

​ 设置指定key的值

​ 语法:set key value

​ 返回值:成功OK

get

​ 获取指定key的值

​ 语法:get key

​ 返回值:key的值。不存在返回nil

setnx

​ 当且仅当key不存在时才新增。

​ 语法:setnx key value

​ 返回值:不存在时返回1,存在返回0

setex

​ 设置key的存活时间,无论是否存在指定key都能新增,如果存在key覆盖旧值。同时必须指定过期时间。

​ 语法:setex key seconds value

​ 返回值:OK

3.哈希表(Hash)

​ Hash类型的值中包含多组field value。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfdIlRoG-1641622044263)(D:\Distributed\分布式资料分享\Redis\文档\Redis文档.assets\Redis-03.jpg)]

hset

​ 给key中field设置值。

​ 语法:hset key field value

​ 返回值:成功1,失败0

hget

​ 获取key中某个field的值

​ 语法:hget key field

​ 返回值:返回field的内容

hmset

​ 给key中多个filed设置值

​ 语法:hmset key field value field value

​ 返回值:成功OK

hmget

​ 一次获取key中多个field的值

​ 语法:hmget key field field

​ 返回值:value列表

hvals

​ 获取key中所有field的值

​ 语法:hvals key

​ 返回值:value列表

hgetall

​ 获取所有field和value

​ 语法:hgetall key

​ 返回值:field和value交替显示列表

hdel

​ 删除key中任意个field

​ 语法:hdel key field field

​ 返回值:成功删除field的数量

4. 列表(List)

Rpush

​ 向列表末尾中插入一个或多个值

​ 语法;rpush key value value

​ 返回值:列表长度

lrange

​ 返回列表中指定区间内的值。可以使用-1代表列表末尾

​ 语法:lrange list 0 -1

​ 返回值:查询到的值

lpush

​ 将一个或多个值插入到列表前面

​ 语法:lpush key value value

​ 返回值:列表长度

llen

​ 获取列表长度

​ 语法:llen key

​ 返回值:列表长度

lrem

​ 删除列表中元素。count为正数表示从左往右删除的数量。负数从右往左删除的数量。

​ 语法:lrem key count value

​ 返回值:删除数量。

5 集合(Set)

​ set和java中集合一样。

sadd

​ 向集合中添加内容。不允许重复。

​ 语法:sadd key value value value

​ 返回值:集合长度

scard

​ 返回集合元素数量

​ 语法:scard key

​ 返回值:集合长度

**smembers **

​ 查看集合中元素内容

​ 语法:smembers key

​ 返回值:集合中元素

6 .有序集合(Sorted Set)

​ 有序集合中每个value都有一个分数(score),根据分数进行排序。

zadd

​ 向有序集合中添加数据

​ 语法:zadd key score value score value

​ 返回值:长度

zrange

​ 返回区间内容,withscores表示带有分数

​ 语法:zrange key 区间 [withscores]

​ 返回值:值列表

7.三种特殊类型

Geospatial

​ 经纬度数据类型

Hyperloglog

​ 不重复计数类型

	Hyperloglog是专门用于存放不重复且需要计数的数据的,例如一篇文章的浏览量;当然这种数据也可以存放到set类型中,因为set类型也是不重复的,但如果数据量很大,则存放到set中会占用大量的内存,基于此,Redis 在2.8.9 版本中更新了 Hyperloglog 数据结构专门用于存放不重复计数类型的数据,其特点是占用的内存很小且固定,存放了2^64 个不同元素的key,只需要废 12KB内存,所以,hyperloglog是存放不重复计数类型的最佳类型

Bitmap

​ 位存储数据类型

其key值为map类型,但是其map的key只能为integer类型,value值只能为0或1。使用场景:打卡等

你可能感兴趣的:(数据库,redis,数据库,java,linux)