最全redis学习笔记

Redis学习笔记

redis介绍

Redis数据库是一个非关系型数据库(nosql),是一个内存数据库. 以键值对的形式存储的

redis开源免费

Redis支持的数据类型 string hash list set zset

Redis单个key存入512M大小

Redis是单线程的,基于内存操作,cpu不是redis的性能瓶颈,redis是通过C语言实现的

***误区:多线程不一定比单线程的效率高

几大组成部分:

Redis-server 是redis数据库的服务端

Redis-cli 是redis官方的一个连接操作redis的一个客户端

redis-benchmark 是redis官方自带的一个测试redis性能的工具

redis的优缺点

Redis是一个内存数据库,基于内存操作

优点:cpu不是redis的性能瓶颈

​ 具有高速的读和写,

​ redis开源免费

缺点:缺点是会造成服务器内存消耗严重,也可能导致内存溢出,

redis的使用

1、String的操作

Keys *表示查看所以的key

Exists key 表示查看是否存在某个key

Expire key xx(时间)表示设置某个key的有效时间,秒为单位

MOVE key db 把名称为key的数据移动到db库

如:127.0.0.1:6379[1]> MOVE age 2

(integer) 1

Type key 查看key的类型

如:127.0.0.1:6379[2]> type age

String

strlen key 查询key对应的value值长度

如:127.0.0.1:6379[1]> strlen sex

(integer) 3

redis 127.0.0.1:6379> FLUSHALL

删除所有数据库的数据

redis 127.0.0.1:6379> flushdb

flushdb 执行删除在某个db环境下执行的话,只删除当前db的数据

2、list的操作

介绍

​ list底层实现原理是一个链表

把数据从左到右插入到list中(lpush list名称 值)

127.0.0.1:6379[1]> lpush mylist a

(integer) 1

127.0.0.1:6379[1]> lpush mylist a b c d e f

(integer) 7

127.0.0.1:6379[1]> lrange mylist 0 -1

“f”

“e”

“d”

“c”

“b”

“a”

“a”

把数据从右边插入到list中(rpush list名称 值)

127.0.0.1:6379[1]> rpush mylist 1 2 3

(integer) 10

127.0.0.1:6379[1]> lrange mylist 0 -1

“f”

“e”

“d”

“c”

“b”

“a”

“a”

“1”

“2”

“3”

右边移除(rpop list名称)

127.0.0.1:6379[1]> rpop mylist

“3”

127.0.0.1:6379[1]> lrange mylist 0 -1

“l”

“f”

“e”

“d”

“c”

“b”

“a”

“a”

“1”

“2”

左边移除(lpop list名称)

127.0.0.1:6379[1]> lpop mylist

“l”

127.0.0.1:6379[1]> lrange mylist 0 -1

“f”

“e”

“d”

“c”

“b”

“a”

“a”

“1”

“2”

查看list的长度(llen list名称)

127.0.0.1:6379[1]> llen mylist

(integer) 9

移除list中指定的key(lrem list名称 count key)

127.0.0.1:6379[1]> lrange mylist 0 -1

“f”

“e”

“d”

“c”

“b”

“a”

“a”

“1”

“2”

127.0.0.1:6379[1]>

127.0.0.1:6379[1]> lrem mylist 2 a --移除两个

(integer) 2

127.0.0.1:6379[1]> lrange mylist 0 -1

“f”

“e”

“d”

“c”

“b”

“1”

“2”

截取list中的数据(ltrim list名称 开始位置 结束位置)

127.0.0.1:6379[1]> lrange mylist 0 -1

“f”

“e”

“d”

“c”

“b”

“1”

“2”

127.0.0.1:6379[1]> ltrim mylist 2 4

OK

127.0.0.1:6379[1]> lrange mylist 0 -1

“d”

“c”

“b”

移除list中的值并把该值加入到一个新的list(rpoplpush mylist myotherlist)

127.0.0.1:6379[1]> lrange mylist 0 -1

“d”

“c”

“b”

127.0.0.1:6379[1]>

127.0.0.1:6379[1]>

127.0.0.1:6379[1]> rpoplpush mylist myotherlist

“b”

127.0.0.1:6379[1]> lrange mylist 0 -1

“d”

“c”

127.0.0.1:6379[1]> lrange myotherlist 0 -1

“b”

更新list中指定下标的值(lset 如果list或者其小标不存在则会报错)

如:127.0.0.1:6379[1]> lrange mylist 0 -1

“d”

“c”

127.0.0.1:6379[1]> lset mylist 0 aa

OK

127.0.0.1:6379[1]> lrange mylist 0 -1

“aa”

“c”

127.0.0.1:6379[1]> lset mylist2 0 aa mylist2不存在,则报错

(error) ERR no such key

127.0.0.1:6379[1]> lset mylist2 3 aa 下标3不存在

(error) ERR no such key

在list中某个值之前、之后插入一个值

如:

127.0.0.1:6379[1]> linsert mylist after aa bb (语法: linsert key BEFORE|AFTER pivot value)

(integer) 3

127.0.0.1:6379[1]> lrange mylist 0 -1

“aa”

“bb”

“c”

3、Set的操作

4、hash的操作

5、zset的操作

6、geo的操作(地理位置)

添加地理位置

127.0.0.1:6379[2]> geoadd mygeo 121.472644 31.231706 2##添加一个地理坐标(经度和纬度)

(integer) 1 

127.0.0.1:6379[2]> geoadd mygeo 111.290843 30.702636 a 121.472644 31.231706 b#添加多个

(integer) 2

获取两个地理位置的距离

127.0.0.1:6379[2]> geodist mygeo a b#以米为单位获取两个地理位置的距离"972498.5462"

127.0.0.1:6379[2]> geodist mygeo a b km#以千米为单位获取两个地理位置的距离"972.4985"

获取地理位置存储的hash值

127.0.0.1:6379[2]> geohash mygeo a b#返回获取地理位置的hash值

1) "wmrnsmpxbd0"

2) "wtw3sjt9vg0"

获取某个位置的经度和纬度

127.0.0.1:6379[2]> geopos mygeo b#获取b位置的经度和纬度

1) "121.47264629602432251" 

2) "31.23170490709807012" 

127.0.0.1:6379[2]>

获取两个位置之间的距离

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]

以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

范围可以使用以下其中一个单位:

m表示单位为米。

km表示单位为千米。

mi表示单位为英里。

ft表示单位为英尺。

127.0.0.1:6379[2]> GEORADIUS mygeo 110 30 1500 km withdist withcoord count 2

1) 1) "a"

  2) "146.4845"

  3) 1) "111.29084140062332153"

      2) "30.70263509423040915"

2) 1) "1"

  2) "1106.1744"

  3) 1) "121.47264629602432251"

      2) "31.23170490709807012"

7、HyperLogLog

定义:用来做基数统计的算法(基数:不重复的元素个数)

PFADD key element [element ...] redis> PFADD hll a b c d e f g

(integer) 1

redis> PFCOUNT hll

(integer) 7

redis>

计数

PFCOUNT key [key ...]

redis> PFADD hll foo bar zap

(integer) 1

redis> PFADD hll zap zap zap

(integer) 0

redis> PFADD hll foo bar

(integer) 0

redis> PFCOUNT hll

(integer) 3

redis> PFADD some-other-hll 1 2 3

(integer) 1

redis> PFCOUNT hll some-other-hll

(integer) 6

redis>

多个集合取不重复的个数

PFMERGE destkey sourcekey [sourcekey ...]

将多个 HyperLogLog 合并(merge)为一个 HyperLogLog , 合并后的 HyperLogLog 的基数接近于所有输入 HyperLogLog 的可见集合(observed set)的并集.

合并得出的 HyperLogLog 会被储存在目标变量(第一个参数)里面, 如果该键并不存在, 那么命令在执行之前, 会先为该键创建一个空的.

redis> PFADD hll1 foo bar zap a

(integer) 1

redis> PFADD hll2 a b c foo

(integer) 1

redis> PFMERGE hll3 hll1 hll2

OK

redis> PFCOUNT hll3

(integer) 6

redis>

8、redis的持久化

介绍

redis的持久化分为rdb和aof两种,默认情况下是默认开启rdb。

rdb运行原理

在redis运行过程中,会单独起一个子进程,专门用来备份redis中的数据产生后缀为rdb的一个镜像文件。关于rdb是怎么备份,或者需要什么条件触发rdb,则在redis.conf配置文件中配置

备份的触发条件

save 900 1 #表示900秒内有一次更新插入操作,则备份一次

save 300 10 #表示300秒内有10次更新插入操作,则备份一次

save 60 10000 #表示60秒内有10000次更新插入操作,则备份一次

在redis重启的时候会自动读取rdb的镜像文件恢复数据

aof运行原理

aof是备份文件的方式来备份数据的,默认情况下是没用开启aof机制的,aof是不断的添加读写到文件里

aof开启的条件:appendonly no 把no改成yes即可

***注意:在开启aof的情况下默认是以每秒备份读取一次文件 appendfsync everysec

备份文件大小的设置

auto-aof-rewrite-percentage 100 —百分之百

auto-aof-rewrite-min-size 64mb —64m一个文件

如果aof的备份文件出现损坏或者被误删了,则可以使用 redis-check-aof --fix appendonly.aof 修复

具体命令如下: redis-check-aof --fix appendonly.aof

***注意:rdb是没有这个修复机制的

rdb和aof的比较

rdb优点:

1、rdb的备份机制是开启一个子进程操作运行的,不影响redis的使用性能

2、rdb备份效率比aof要高,aof是以文件备份的,如果数据量大会影响到io的一个操作,而rdb则不会

aof的优点

1、aof相对rdb可能备份的数据更全面,因为aof是以每秒备份一次

9、redis做为消息队列的使用

通过publish(生产者) 和 subscribe(消费者)

127.0.0.1:6379[2]> SUBSCRIBE myz

Reading messages... (press Ctrl-C to quit)

1) "subscribe"

2) "myz"

3) (integer) 1

1) "message"

2) "myz"

3) "\xe4\xbd\xa0\xe5\xa5"

1) "message"

2) "myz"

3) "hello"

1) "message"

2) "myz"

3) "111"

10、redis的主从

一般情况下redis至少要搭建三台主机,实现一主二从,实行主从复制(主从复制是单项的,只能是从复制主的),读写分离,只能主的写入,从的读取,减缓服务器的一个压力

redis主从环境搭建

查看主从的配置,命令如下:

info replication

127.0.0.1:6379> info replication

# Replication

role:master

connected_slaves:0

master_replid:3b13450837d15f1255dd2237f91adceb1ae73752

master_replid2:0000000000000000000000000000000000000000

master_repl_offset:0

second_repl_offset:-1

repl_backlog_active:0

repl_backlog_size:1048576

repl_backlog_first_byte_offset:0

repl_backlog_histlen:0

模拟多台redis集群

1、需要修改redis.conf的配置文件,注意:需要修的的配置有如下:

port 6379 #端口

logfile “” #日志文件名称 ,默认是""

如果开启了aof,则要修改appendfilename “appendonly.aof” 里的aof文件名称

dbfilename dump.rdb #修改dump.rdb名称

pidfile /var/run/redis_6379.pid #修改 redis_6379 对应的端口

2、配置主从

***注意,只要配置从机,主机不用操作

进入要作为从机的redis,执行以下命令

​ slaveof 127.0.0.1 6379 # slaveof 地址 redis端口

执行完此命令后,就实现了主从的配置,但是通过此命令执行配置的主从并不是永久的,如果需要永久则需要通过配置文件配置操作:

replicaof #配置主机的ip 主机的端口

masterauth #配置主机的密码

哨兵模式

当主服务器宕机后,哨兵能监控到主机是否出现故障,并且通过投票(可能会存在多个哨兵,相互监督)的模式会自动的从从机选择一台为主机

哨兵:哨兵是一个独立的进程,哨兵会向主从服务器发生信息维持心跳来检测服务器是否运行正常

哨兵的配置是在sentinel.conf中配置,有以下步骤

1、命令如下:sentinel monitor

#master-name表示被监控的名称,自己随便命名

#quorum是用来识别故障的,真正执行故障转移的时候,还是要在哨兵集群执行选举,选举一个哨兵进程出来执行故障转移操作

假设有5个哨兵,quorum设置了2,那么如果5个哨兵中的2个都认为master挂掉了; 2个哨兵中的一个就会做一个选举,选举一个哨兵出来,执行故障转移; 如果5个哨兵中有3个哨兵都是运行的,那么故障转移就会被允许执行

​ 例子:sentinel monitor mymaster 127.0.0.1 6379 2

2、启动哨兵监控进程 redis-sentinel

启动命令:./redis-sentinel /root/myz/redis/redis-5.0.4/sentinel.conf

如果有多个哨兵,则需要修改哨兵的端口

[root@iz2zedf13i3kapmjbff0ogz src]# ./redis-sentinel  /root/myz/redis/redis-5.0.4/sentinel.conf

21128:X 07 Oct 2020 13:02:15.939# oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo21128:X 07 Oct 2020 13:02:15.939# Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=21128, just started21128:X 07 Oct 2020 13:02:15.939# Configuration loaded_._                                                              _.-``__ ''-._                                                    _.-`` `. `_.  ''-._          Redis 5.0.4 (00000000/0) 64 bit  .-`` .-```. ```\/    _.,_ ''-._                                    (    '      ,      .-` | `,    )    Running in sentinel mode  |`-._`-...-` __...-.``-._|'` _.-'|    Port: 26379  |    `-._  `._    /    _.-' |    PID: 21128  `-._    `-._  `-./  _.-'    _.-' |`-._`-._    `-.__.-'    _.-'_.-'| | `-._`-._        _.-'_.-' |http://redis.io`-._    `-._`-.__.-'_.-'    _.-'                                    |`-._`-._    `-.__.-'    _.-'_.-'| | `-._`-._        _.-'_.-'    | `-._    `-._`-.__.-'_.-'    _.-'                                          `-._    `-.__.-'    _.-' `-._        _.-'                                                          `-.__.-'                                                21128:X 07 Oct 2020 13:02:15.940# WARNING: The TCP

backlog setting of 511 cannot be enforced because

/proc/sys/net/core/somaxconn is set to the lower value of 128.21128:X 07 Oct 2020 13:02:15.943# Sentinel ID is 0b47f847c177274362ad34fc44f28e4895192b8121128:X 07 Oct 2020 13:02:15.943# +monitor master mymaster 127.0.0.1 6379 quorum 2

哨兵模式

当宕机的主机恢复后, 并不能再次成为主机,而是成为从机

优点:

1、哨兵集群,基于主从复制,主更改,从只读取,所有主从配置的优点,它全有

2、主从可以切换,故障转移,系统的高可用

3、哨兵模式就是主从模式的升级,手动到自动,更加健壮

缺点:

1、redis不好在线扩容,扩容麻烦

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

11、缓存的穿透、击穿和雪崩(面试高频)

缓存穿透

缓存穿透的概念:

用户想要去查询一个数据,发现redis缓存里没有,则会向持久层数据库查询,发现也没有于是本次查询失败,当用户很多的时候,如果缓存中都没有,于是都去请求持久层数据库,这样会给数据库很大的压力,严重导致数据库崩溃,这个时候就相当于出现了穿透。

解决缓存穿透的方法:

1、布隆过滤器

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

2、缓存空对象

定义:当查询缓存和数据库都没用命中时,即使返回的空对象也要将其存储起来,同时会设置一个过期时间,之后在访问这个数据将会从缓存中获取,保护了后端数据

使用缓存空对象的带来的问题:

1、空值被缓存起来,意味着需要更多的缓存空间,因为其值是空值,所以导致浪费了很多的空间

2、即使设置了过期时间,还会存在在缓存层和数据库持久层会有一端时间的不一致,这对于需要保持数据一致性的业务要求会有影响

缓存击穿

缓存击穿的概念:

缓存击穿是指一个key非常热点,在不断扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就直接请求了持久层数据库,导致数据库宕机,就像是在屏幕上砸开了一个洞。

解决方案:

1、设置热点key永不过期,这样就不会出现热点key过期导致请求直接去数据库查询数据。

2、分布式锁,使用分布式锁,保证对于每一个key,只能有一个线程去查询服务,其他线程只能等待,这种方式就是把压力给到了分布式锁上。

缓存雪崩

定义:服务器断电、断网或者大面积的key失效导致

解决方案

1、redis的高可用:集群配置redis,新增redis主机

2、限流降级:在缓存失效后,通过加锁或者队列来控制读写数据库写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待

1、布隆过滤器

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

2、缓存空对象

定义:当查询缓存和数据库都没用命中时,即使返回的空对象也要将其存储起来,同时会设置一个过期时间,之后在访问这个数据将会从缓存中获取,保护了后端数据

使用缓存空对象的带来的问题:

1、空值被缓存起来,意味着需要更多的缓存空间,因为其值是空值,所以导致浪费了很多的空间

2、即使设置了过期时间,还会存在在缓存层和数据库持久层会有一端时间的不一致,这对于需要保持数据一致性的业务要求会有影响

缓存击穿

缓存击穿的概念:

缓存击穿是指一个key非常热点,在不断扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就直接请求了持久层数据库,导致数据库宕机,就像是在屏幕上砸开了一个洞。

解决方案:

1、设置热点key永不过期,这样就不会出现热点key过期导致请求直接去数据库查询数据。

2、分布式锁,使用分布式锁,保证对于每一个key,只能有一个线程去查询服务,其他线程只能等待,这种方式就是把压力给到了分布式锁上。

缓存雪崩

定义:服务器断电、断网或者大面积的key失效导致

解决方案

1、redis的高可用:集群配置redis,新增redis主机

2、限流降级:在缓存失效后,通过加锁或者队列来控制读写数据库写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待

3、在设置缓存失效时间时,避免所有的key设置一个失效时间,尽量错开。

希望能对大家进一步学习redis这项技术有帮助,

                          

你可能感兴趣的:(最全redis学习笔记)