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这项技术有帮助,